Redirecting from exported handle hook in sveltekit - sveltekit

I have a sveltekit app and I want to check if the user has an accesstoken from the cookie. I can access it through event.request.headers.get('cookie'); and redirects them to a certain route but I can't find specific syntax from the sveltekit docs.
src/hooks.ts
export async function handle({ event, resolve }) {
const reqCookie = event.request.headers.get('cookie');
const cookieName = 'userid';
const keeperCookie = reqCookie.split(';')
.find((c: string) => c.trim().startsWith(cookieName));
const response = await resolve(event);
if (!reqCookie || !keeperCookie) {
return response.headers.set('location', '/create');
}
return response.headers.set('location', '/login');
}
Redirect doesn't work for me and gives me an error in the console

I just got it using native Response
`return Response.redirect(baseUrl+"/login", 303);`

return new Response('Redirect', {status: 303, headers: { Location: '/login' }});
So you don't need the base url :)

Related

How to bypass NextAuth when given an external access token

This is not a common use case and even less a good practice, but for the purposes of my project, if an access token is passed as a parameter in the url (e.g.http://localhost:3000?accessToken=myAccessToken), I need to use it in my API calls and "disable" authentication with next auth.
The authentication process is just a fallback in case an accessToken is not passed.
My current implementation is:
storing the accessToken in a cookie in _app.tsx, before the auth
kicks and redirects to the login page :
_app.tsx
...
// Retrieving the callbackURL query params.
const { callbackUrl } = router.query;
// Retrieving the accessToken from the callbackURL.
const params = new URL(callbackUrl as string, 'https://example').searchParams;
const accessToken = params.get('accessToken');
// Storing it in a cookie.
if (storeNumber) {
document.cookie = `storeNumber=${storeNumber}`;
}
...
in my _middleware.ts file, trying to get this cookie, and authorize
the login if the token is present.
_middleware.ts :
export default withAuth({
pages: {
signIn: '/auth/signin',
},
callbacks: {
authorized: ({ req, token }) => {
const accessToken = getCookie('accessToken'); // => null
return !!accessToken;
},
},
});
I'm not even sure I can access the cookie from the _middleware.ts file, or if it's the right way to do this.
Any help would really be appreciated. Thank you guys.
If anyone wants the solution (doubt it), I managed to retrieve the cookie in the middleware like this :
callbacks: {
authorized: ({ req }) => {
const cookie = req.headers.get('cookie');
const accessToken = cookie.split('accessToken=')[1].split(';')[0];
console.log(accessToken);
// Do your logic
return !!accessToken
},
},

How to use a timeline ref with #prismicio/client library in Next.js/React

I'm using the #prismicio/client library to fetch data from Prismic inside my Next.js app, but I can't figure out how to connect the preview mode and the preview ref it provides to the client.query call in order to fetch data for that specific timeline ref.
I tried looking for this in the technical reference for both the library itself and the guide on how to use Preview mode. They both mention I can use refs, but don't show an actual example. Here is my current set up, which is not working:
Inside my preview.ts page, I have this custom getServerSideProps function, which uses a custom call to my CMS handler where I pass the ref token:
export const getServerSideProps = async (context: NextPageContext): Promise<unknown> => {
const lang = getLangFromContext(context);
const { slug } = context.query as { slug: string[] };
const { token, documentId } = context.query;
if (!token) {
return console.warn(`No token available, check your configuration`);
}
const { pageComponents, meta } = await getCmsPage(slug ? slug.join("/") : "", lang, token);
return { props: { pageComponents, meta } };
};
When making the call to the Prismic API:
const client = Prismic.client(refApiUrl, {
accessToken: apiToken,
});
const res: any = await client.query(predicates, {
key: refToken,
});
This results in the server side error:
Error: Unknown field key
at SearchForm.set (C:\main\Sprybase\projects\prismic-integration\dist\node_modules\#prismicio\client\cjs\#prismicio\client.js:200:19)
at ResolvedApi.query (C:\main\Sprybase\projects\prismic-integration\dist\node_modules\#prismicio\client\cjs\#prismicio\client.js:606:25)
at C:\main\Sprybase\projects\prismic-integration\dist\node_modules\#prismicio\client\cjs\#prismicio\client.js:1164:63
at processTicksAndRejections (internal/process/task_queues.js:88:5)
What am I doing wrong? What is the correct way to pass a timeline ref to the Prismic client call?
It seems in your application you're not using the getPreviewResolver function or a linkresolver which the toolbar uses to get the correct page and load the preview cookie on top of the browser.
Is there any reason why you're doing your preview in this way?
Thanks.

Navigation failed after logging in with react-native-fbsdk

I am using the FBSDK to do the registration in react native. I need the name, last name and email in order to pass it to the registration screen and fill the mentioned fields there automatically. Here is my code in login screen:
async _fbAuth() {
//console.log("that", that);
let { isCancelled } = await LoginManager.logInWithReadPermissions(['public_profile','user_posts', 'email','user_birthday']);
if ( !isCancelled ) {
let data = await AccessToken.getCurrentAccessToken();
let token = data.accessToken.toString();
// await afterLoginComplete(token);
const response = await fetch(
`https://graph.facebook.com/me?fields=id,email,name,first_name,last_name,gender,picture,cover&access_token=${token}`);
let result = await response.json();
this.setState({result});
console.log('result result result ', result);
//navigate to complete the registration.
this.props.navigation.navigate('Reg_1', {name: this.state.result.name, email: this.state.result.email, surname: this.state.result.last_name })
}
else {
console.log('Login incomplete');
}
}
Also I have this button to call the function:
<ButtonFB
onPress={ this._fbAuth}
isLoading={false}
isEnabled={true}
label={I18n.t("Accedi_con_Facebook")}
style={commonStyle.Button}
/>
Everything works fine and the data retrieved well. The only problem is the part of navigation and setSate. My problem is that the 'this' has been lost during the login with the facebook. I got the following warning after doing the login with facebook.
Possible: Unhandled promise rejection (id:0): type error:
this.setState is not a function
I also tried to bind the function of _fbAuth, but it doesn't work. Can you help me to solve this problem. Thanks in advance.
You need to bind the function as
_fbAuth = async () => {}
Since this is not being referenced in _fbAuth function.
For more info checkout this artice

How to access react-router v3 prop in function?

I'm using refresh-fetch for authentication token refreshing. If the app receives not 200 http status code response I need to handle that by redirecting the user to logout page. How could I achieve this using react-router v3.
browserHistory.push('/logout');
I think this is not an option because I'm using basename.
const refreshToken = () => {
return fetchJSONWithToken(`${API_ROOT}user/login/refresh`, {
method: 'POST',
body: JSON.stringify({ refresh_token: retrieveToken() })
})
.then(({body}) => {
saveToken(body.access_token, body.refresh_token);
return body;
})
.catch(error => {
//TODO: redirect user to /logout
throw error;
});
};
Or maybe there is a better way of doing this?
You need to store your browserHistory instance and reuse it.
Example:
import { createHistory, useBasename } from 'history'
// Run our app under the /base URL.
const yourCustomHistoryWithBasename = useBasename(createHistory)({
basename: '/base'
})
// Re-use the same history, which includes the basename
yourCustomHistoryWithBasename.push('/logout') // push /base/logout
yourCustomHistoryWithBasename.replace('/logout') // replace current history entry with /base/logout
Source for this example

React Relay Modern redirecting to another page when receiving 401 error on network environment

I´m using JWT authentication inside my ReactJS RelayJS network environment. All the token retrieval and processing in server and client are fine. I´m using react router v4 for routing.
My problem is when I receive a Unauthorized message from server (status code 401). This happens if the user points to an application page after the token has expired, ie. What I need to do is to redirect to login page. This is the code I wish I could have:
import { Environment, Network, RecordSource, Store } from 'relay-runtime';
const SERVER = 'http://localhost:3000/graphql';
const source = new RecordSource();
const store = new Store(source);
function fetchQuery(operation, variables, cacheConfig, uploadables) {
const token = localStorage.getItem('jwtToken');
return fetch(SERVER, {
method: 'POST',
headers: {
Authorization: 'Bearer ' + token,
Accept: 'application/json',
'Content-type': 'application/json'
},
body: JSON.stringify({
query: operation.text, // GraphQL text from input
variables
})
})
.then(response => {
// If not authorized, then move to default route
if (response.status === 401)
this.props.history.push('/login') <<=== THIS IS NOT POSSIBLE AS THERE IS NO this.history.push CONTEXT AT THIS POINT
else return response.json();
})
.catch(error => {
throw new Error(
'(environment): Error while fetching server data. Error: ' + error
);
});
}
const network = Network.create(fetchQuery);
const handlerProvider = null;
const environment = new Environment({
handlerProvider, // Can omit.
network,
store
});
export default environment;
Naturally calling this.props.history.push is not possible as the network environment is not a ReactJS component and therefore has no properties associated.
I´ve tried to throw an error at this point, like:
if (response.status === 401)
throw new Error('Unauthorized');
but I saw the error on the browser console, and this cannot be treated properly in the code.
All I wanna do is to redirect to login page in case of 401 error received, but I can´t find a proper way of doing it.
I am not using relay but a render prop. I experienced kind of the same issue. I was able to solve it using the window object.
if (response.statusText === "Unauthorized") {
window.location = `${window.location.protocol}//${window.location.host}/login`;
} else {
return response.json();
}
You can go with useEnvironment custom hook.
export const useEnvironment = () => {
const history = useHistory(); // <--- Any hook using context works here
const fetchQuery = (operation, variables) => {
return fetch(".../graphql", {...})
.then(response => {
//...
// history.push('/login');
//...
})
.catch(...);
};
return new Environment({
network: Network.create(fetchQuery),
store: new Store(new RecordSource())
});
};
// ... later in the code
const environment = useEnvironment();
Or you can create HOC or render-prop component if you are using class-components.
btw: this way you can also avoid usage of the localStorage which is slowing down performance.

Resources