I made a Quasar App with an external authentification server. After the login I receive the access and refresh token. The refresh token is not expiring until I press logout. The access token expires after 10 minutes. So since I need the access token to get the data, this is possible for the next 10 minutes after login. Afterwards I have to call an API including the refresh token to get a new access token.
My question is, how can I make sure to always have a valid access token without logging in again?
As a User I expect to login and have access to everything until I logout. And if my App was for example 15 minutes just laying around and then I want to receive data, that's not possible.
Somehow I want to call the refresh token api silently, but when and how?
Is it common to refresh the token at a certain time interval, or on changing a page or every time I want to receive data?
I didn't find an efficient solution yet.
In a boot file I added the refresh token method. So every time the App was started, the token will be refreshed. For iPhone users for example the app won't be closed completely so the init-method will not be triggered until I completely close the App manually.
I guess to refresh the token before every API call is too much. Or is it?
My question is, how can I make sure to always have a valid access
token without logging in again?
You may use Axios response interceptors in the Quasar Axios boot file to check if a response has failed due to expired access token (based on status code eg 401).
axios.interceptors.response.use(
(response) => {
return res;
},
async(error) => {
if (error.response) {
if (error.response.status === 401) {
// Use refresh token here to get new JWT token;
// return a request
return axios_instance(config);
}
}
return Promise.reject(error);
}
);
Hope this helps!
Related
I'm using Google for auth (expo-auth-session/providers/google)
I can successfully login for the first time and fetch an access token and a refresh token. The refresh token will get stored in SecureStorage.
Now at this point, when the old access token is invalidated, I need to use the refresh token to get a new access token, but Expo's docs don't really provide any guidance on this part. I have checked their API quite thoroughly, but can't see anything that helps me retrieve a new access token with a refresh token.
Any guidance would be welcome.
The AuthSession library has a method specifically for refreshing tokens. It requires the clientId used to retrieve the token initially, so you can reuse that, the refreshToken which you have stored as well as a token endpoint.
const tokenResult = await AuthSession.refreshAsync({
clientId: "<your-client-id>>",
refreshToken: "<your-refresh-token>",
}, {
tokenEndpoint: "www.googleapis.com/oauth2/v4/token",
},
);
I wasn't able to test this myself as we use firebase and useIdTokenAuthRequest as a result, so I wasn't able to get my hands on a refreshToken to run it through that function - but the documentation of that method seems pretty solid.
I want to ask if someone knows a possibility to refresh token after user do any kind of activity. Right now token gets created after user logs in but it never get refresh, only if token is expired and user tries to do a request, this functionality can be found in AuthInterceptor but in our current project we automatically log out if expired_at is less than current Date.
Does someone can give me some guidance? I have tried creating another interceptor and call function handleExpiredAccessToken from class AuthHttpHeaderService but no good response, my token tries to refresh many times ending in a loop.
Also we tried refreshing the token 5 minutes before the expiration time and refresh headers for request like follow code:
const stream = this.authStorageService.getToken();
stream.subscribe((tokenData) => {
if(tokenData.expires_at && ( +tokenData.expires_at - 300000 < new Date().getTime())){
this.oAuthLibWrapperService.refreshToken();
}
if(tokenData.access_token){
request = request.clone({
setHeaders: {
Authorization: `${tokenData.token_type || 'Bearer'} ${tokenData.access_token}`,
},
});
}
});
Thanks in advance.
Maybe you can leverage this back-end configuration property: https://help.sap.com/viewer/d0224eca81e249cb821f2cdf45a82ace/2105/en-US/3d3ea6a4d5fa486aa324ce278fa2afc3.html?q=oauthauthorizationserver.tokenServices.reuseRefreshToken
According to the docs, every time the access token expires (and Spartacus automatically refreshes it), the server will generate a new refresh token. I'm assuming this means the validity of the new refresh token will be reset (easy to check).
You can try to setup a silent refresh like in this repo. If you then call the silentRefresh function of the OAuthService class, it will do a refresh of the token in a iframe.
I'm building a react native app which uses the spotify web api. I'm using the authorization code flow to authorize a user. First I get a authorization code which can be used to obtain an access token and a refresh token. Everything works!
The problem is: an access token is only valid for a limited amount of time. That's where the refresh token comes in. I understand this concept, but I'm breaking my head about how to implement this.
Let's say a users opens the app, requests an access token and uses this for some time. Then, the user closes the app. After 15 minutes, the users opens the app again. The access token has now expired, so I need to request a new access token.
I've come op with several "solutions". Can someone point me to the correct solution?
Solution 1:
Every time the user opens the app, I request a new access token and use this. Problem: when the user uses the app longer than the valid time of the access token, I won't work anymore.
Solution 2:
I use the access token that's stored in the secure storage on every request. When a request comes back with 'access token invalid' (I don't know the exact error code but you guys know what I mean), I request a new access token with the stored refresh token, and then I send the previous command again (with the new access token). But my question here is: can I use some kind of "wrapper function" which checks the response of the request, and if the response is "access token invalid", it automatically requests a new access token and runs the previous request again.
I think certainly correct solution is solution 2,and i think its clear enough.
and for using solution 2 you need somthing like wrapper function,yes its intelligently.
so you should use interceptor:
what is interceptor ?
You can intercept requests or responses before they are handled by then or catch.
in link below there is a good example of implementing refresh token in axios interceptor:
https://gist.github.com/Godofbrowser/bf118322301af3fc334437c683887c5f
I agree that Solution 2 is the best, each time you do a request you can check to see if the Access Token has expired, and if it has then you can request a new Access Token using the Refresh Token as you mentioned and then make your request, in my own project I do this in a FormatRequestHeadersAsync method which calls a CheckAndRenewTokenAsync method where I perform the following check, here shown in C#:
if(AccessToken?.Refresh != null && (AccessToken.Expiration < DateTime.UtcNow))
{
AccessToken = await GetRefreshTokenAsync(
AccessToken.Refresh,
AccessToken.TokenType,
cancellationToken);
}
You can store the Access Token and the Refresh Token and then use something similar to this before you make each request to the API this will refresh your token and then you can store the new Access Token and the existing Refresh Token.
I'm a beginner in react native and I'm creating an app. I've done some research about how to make a secured react native app, but I didn't found much information. I've come up with a "solution" myself, but I want to make sure this is the right way to do this. So I need the help of some react native/javascript/security experts if possible, to quickly check if my approach is OK or not?
I have included 3 questions in this text, but obviously they're related. I've put them in bold. Feel free to answer one or more questions, I appreciate every answer!
I'm creating an app in react native. For a user to be able to use the app, the user should create an account and sign in. I'm using an JSON web token as an access token to authorize the requests made from the app to the server, and to identify the user (I store the user ID in the JSON web token).
At my server, I first check if the access token is valid. If so, I get the user ID out of the access token and use this user ID to identify the user.
For extra security, I'm also using refresh tokens, because an access token is only valid for 10 minutes. When a user send a request with an expired access token, the server responds with a 401 not authorized status.
To make my code more "managable", I've created a wrapper function in react native. I wrap every "request function" (every function where I do a GET/POST/PUT/DELETE request to the server) with this wrapper function. This wrapper function checks the response of the request. If the response status is 200, the response is returned to the code. If the response status is 401, the refresh token is send to a specific endpoint to obtain a new access token. When the access token arrives at the app, the previous request is made again with the new access token. The wrapper function also stores the new access token in (temporary) redux (keychain or shared preferences). 1. Is a wrapper function a good idea? For me, it's more manageble because now I'm reusing the code.
Every time the user opens the app, a new access token is requested, and when a user closes the app, the current access token is deleted, even if it is not expired yet. That way, I want to make sure that every app "session" starts with a new access token. 2. Is this okay? Or should I prevent unnecessary requests to the server when I still have a (possibly) valid access token?
In my react native app, this wrapper function is located in a context component. This "authentication" context is wrapper around my other components in App.js like this:
<AuthenticationProvider>
<AppNavigator />
</AuthenticationProvider>
This way, my wrapper function is accessible to all my other components. My authentication context looks like this:
const AuthenticationContext = createContext({
accessToken: null,
wrapperFunction: () => {}
})
const AuthenticationProvider = (props) => {
let accessToken = null
const refreshToken = useSelector(state => state.auth.refreshToken)
const wrapperFunction = () => {
// wrapper function
// set the access token
// await fetch('server endpoint')...
}
return (
<AuthenticationContext.Provider value={{ accessToken, wrapperFunction }}>
{props.children}
</AuthenticationContext.Provider>
)
}
3. Is using a context a good practice to do stuff like this?
Server-side, I store every refresh token in a database. When a user requests a new access token, I check if the sent request token still exists in the database. If not, I have revoked access for this user and the user should be logged out. This way, I want to make sure I can "manage" users.
Yes, it makes sense. Actually I can't think of a better way to manage the scenario you mentioned. When you wanna temper the request before it's sent, you will need a single function to do so. You could also use some hooks e.g. onBeforeSend and onAfterReceive, but in your case I don't see any extra value for this.
I do not agree with the deletion of a valid token. You can still send request to server on every app start to get user's last data -might have changed on another device-. I don't understand the logic of starting the app with a new session -maybe more information?
I don't think you need to pass the wrapperFunction/token using context. It would be best if you could send user data by context. you wrapper function can access the token directly from asyncStorage. And each component can call the function directly by importing it.
I believe you are taking the approach of using a wrapper function since the relevant API requests are made directly in components. The best practice is to move such requests outside (E.g. Redux actions with a middleware like redux-thunk) the components.
It's better to check if the access token is expired (by decoding the token) before sending the API request and retrieve the new access token. This will reduce the amount of requests to server. You can implement a common request method which handle this check as well.
I think since your access token expires every 10 mins this is unnecessary. Is there a specific reason to start each session with a new access token?
You can pass in user access details using the context. I think it's matter of preference. Passing in the wrapper function is not needed if you're handing the requests through a common request method.
In my app, I make a call to getSession if the user refreshes the page or tries to access a client side rout that requires the user to be authenticated.
The problem I am seeing is that the refreshToken never expires.
So I do this:
const currentSession = await authorisationProvider.getSession();
this.setState({ isAuthenticated: currentSession && currentSession.isValid(), busy: false });
But having stepped through the code and if the cachedSession.isValid() call returns false then a call is made to refreshToken which always appears to return new tokens no matter how long I leave it.
Does the refreshToken never expire or can I configure it to expire in an hour or so?
The only way for things to expire is for localStorage.clear() to be called which is obviously not a real solution.
In aws Cognito console under General settings -> App clients tab you can configure refresh token expiration in days with limit 1-3650 days
Reference: Refresh Token expiration