In my nuxt project, i get a token from the backend that identifies the user. I tie this token to a vuex prop and save it in localstorage, so the user doesnt have to re authenticate when the page is refreshed.
To revalidate the user only when the page is actually refreshed, i wrote a beforemount function in the highest level, which is the default layout
beforeMount() {
const token = localStorage.getItem('user-token')
console.log(token)
if (token) {
this.$axios.defaults.headers.common.Authorization = token
this.$store.dispatch('auth/setToken', token)
}
}
In the next step, the router on protected pages should check if the authstate is true, which is only true if the vuex localstorage prop is set. Since i only need that on certain pages, i wrote a router middleware thats only loaded on these pages
export default function (context) {
if (!context.store.getters['auth/isAuthenticated']) {
return context.redirect('/auth?login')
}
}
Problem is, the middleware runs before the beforeMount according to the docu, which creates the problem that the middleware checks for a token which is set later and kicks the user out.
Since the only thing that comes before router middleware is global middleware, my plan was to write the reauth as global middleware. But somehow, the middleware is also called on every router change, not only before the site is created aka page refresh. This would execute the function way too often.
The goal is to set the token before the route validate based on the token, only on page refresh, since the rest is taken care of by vuex.
Related
I store a user token in a vuex state.
When the page of my nuxt app is refreshed, i want this token to persist, to check for eligibility to visit user-related routes.
From a global middleware, i just dispatch an action like so
context.store.dispatch('authModule/resetToken')
triggering the vuex action
resetToken(context) {
context.commit('RE_AUTH')
},
which triggers the following mutation
RE_AUTH: (state, token) => {
if (!state.token && process.client && localStorage.getItem('auth-token')) {
token = localStorage.getItem('auth-token')
state.token = token
}
},
When i reload the page, the mutation is triggered, but the if condition does not resolve true and execute the code to reappend the token, even though there is the correct named token in localhost.
When i however then navigate to another page, the code does execute and reappends the token. I dont understand why, because global middleware should be executed first in lifecycle and vuex should have access to localstorage
I am using #auth0/auth0-react library to handle authentication process. For an unauthorized user, it will redirect to back to initial screen ("/") route with this query params. ?error=unauthorized... Then again if I am trying to execute the login it will stay on the same page. Maybe I need to find a way to clear the previous auth0 state.
const { loginWithRedirect, logout} = useAuth0();
const loginWithAuth0 = () => {
logout({}); // clear previous auth 0 state
loginWithRedirect({
redirectUri: window.location.origin + "/dashboard"
});
};
Above is my attempt. Using logout({}) I am trying to clear the previous auth0 state and going forward which doesn't happen. For an authorized user there's no issues. So what I need is to handle the unauthorized user behaviour. Currently it will not redirect to the dashboard which is correct for unauthorized. But what I need is to clear the previous auth0 state and redirect to the next attempt. How can I achieve it?
You could destructure the isAuthenticated prop off of the object returned by the useAuth0() hook:
const { loginWithRedirect, logout, isAuthenticated } = useAuth0();
if (!isAuthenticated) {
logout({}); // (not certain this is necessary)
// redirect with whatever router your framework might include
}
Also consider the withAuthenticationRequired function which is exported from the same #auth0/auth0-react package, and allows you to protect a route/component and configure a redirect for unauthenticated users at the same time:
When you wrap your components in this Higher Order Component and an anonymous user visits your component they will be redirected to the login page and returned to the page they we're redirected from after login.
I need to redirect our users to a SSO form that is handle by another team. This form (is not a next.js app) is on the same domain as the next.js app.
I try to follow https://nextjs.org/docs/authentication#authenticating-server-rendered-pages but I can't figure out on how to get the current URL, so I can tell the SSO to redirect back once authentication is finish.
return {
redirect: {
destination: `/sso/form?redirect=${currentUrl}`,
permanent: false,
},
}
Any idea, on how to get the currentUrl?
The context contain a property called resolvedUrl corresponding to the current route.
const { resolvedUrl, req } = context;
const baseUrl = getBaseUrl(req);
const currentUrl = `${baseUrl}${resolvedUrl}`;
getBaseUrl is an helper function that return the base url of our current nextjs app.
The redirection you are doing on the getServerSideProps is done in the server so no dom info can be accessed on that level. You have tu pass the path info to the server in a cookie or something like that.
Anyway, if im not mistaken, you redirect to SSO when you try to load a page and the auth fails. This auth happens on getServerSideProps so you can hardcode the SSO redirection url because you call a different getServerSideProps everytime you go to a new page.
I am attempting to implement 0Auth user authorization for my Next.js app using MoneyButton API. I am able to trigger the authorization request with client.requestAuthorization('auth.user_identity:read','http://localhost:3000');
And it works smoothly redirecting me to MoneyButton permission consent and back to my app with the code and state params in URL -> ?code=6aa72eef702eb710cd22715d797cf7d27e06532a&state=38984b9d-3af0-48f1-8b5f-3fa47f4dfd9d
There is client.handleAuthorizationResponse(); method for handle the response. That method automatically gets the tokens from the query parameters and set the internal state of the client to use them. Also it saves the credentials in local storage, so the user stays logged in with Money Button if they close the browser.
But unfortunately i don't know how to use this method after being redirected back to my app. I am using it in Authuser function, but requestAuthorization triggers redirect to moneybutton, so rest of the function is not executed. How to use handleAuthorization after being redirected back to application?
https://docs.moneybutton.com/docs/api/auth/api-auth-jsclient.html - here are the MoneyButton docs
I am also considering to add MoneyButton as custom 0Auth provider in NextAuth.js to make integrations faster in the future.
Authuser.js
const { MoneyButtonClient } = require('#moneybutton/api-client')
export default function Authuser () {
const client = new MoneyButtonClient('MYAPP_OAUTH_IDENTIFIER_CODE');
client.requestAuthorization('auth.user_identity:read','http://localhost:3000');
client.handleAuthorizationResponse();
const refreshToken = client.getRefreshToken();
client.setRefreshToken(refreshToken)
}
You need to make sure that client.handleAuthorizationResponse(); is run client side (not server side render) after the moneybutton auth has redirected back:
if ((new URLSearchParams(window.location.search)).has('code')) {
await client.handleAuthorizationResponse()
const accessToken = await client.getValidAccessToken()
...
}
I use token authentication for my react spa app. I'm trying to add a token using React hooks.
I have a three file for this small example.
AuthContex.js
AuthReducer.js
authentication-service.js
When user click on the login button, react call authentication-service.js in login function.
When the user is logged in, I need to register the token into the state with the help of hooks. Because, I need to refresh the token at any point in the application, and as a result of this refresh the token was not distributed correctly to all components. I thought of solving this problem by placing the token on top of all components. Thus, if the token is refreshed at any time in the application, it would be distributed properly to the subcomponents.
But react has gave the error --->>
× Unhandled Rejection (Error): Invalid hook call. Hooks can only be
called inside of the body of a function component. This could happen
for one of the following reasons:
You might have mismatching versions of React and the renderer (such
as React DOM)
You might be breaking the Rules of Hooks
You might have more than one copy of React in the same app
function login(username, password) {
const { authDispatch } = useContext(AuthContext);
return axios.post('/api/Authentication/SignIn', {
email: username,
password: password
})
.then((res) => {
// store user details and jwt token in local storage to keep user logged in between page refreshes
localStorage.setItem('auth-jwt', JSON.stringify(res.data));
currentUserSubject.next(res);
authDispatch({ type: LOGIN, payload: res.data });
return res;
}).catch(handleResponse);
}
Please see my CodeSandbox for a small demo.