* Which Category is your question related to? *
Using User Pool as APIGW's authorizor.
It shall pass the Cognito IdToken in the 'Authorization' header of each API request.
This idToken will expire every hour after granted.
The SDK document says Amplify will automatically update/refresh the tokens.
How to refresh Cognito tokens only when necessary?
What's the suggested code to refresh tokens? More detailed questions in the code snippets part
* What AWS Services are you utilizing? *
Cognito User Pool and APIGateway
* Provide additional details e.g. code snippets *
Through the following issue said to call Auth.currentSession() to refresh token is the right code, there is some additional unnecessary network call in that process.
https://github.com/aws-amplify/amplify-js/issues/446
When the APIGW request called frequently, and every time before sending the request, to call currentSession with this unnecessary network access causes latencies.
Using Auth.currentSession() will call getUserData every time, which causes unnecessary network request/response. How to make a correct way to have a valid token for each API request and the refresh token operation is only done when necessary and there is no additional network access when refreshing the tokens?
https://aws-amplify.github.io/docs/js/authentication#retrieve-current-session
https://github.com/aws-amplify/amplify-js/blob/master/packages/auth/src/Auth.ts#L998
https://github.com/aws-amplify/amplify-js/blob/master/packages/auth/src/Auth.ts#L905
@yunganw Regarding the network traffic, I believe getUserData will use cached data unless your pass in a bypassCache parameter.
Are you having some sort of other issue with the tokens not refreshing?
Correct. Latest version has this param. Thanks.
Here is what I learned after working on two projects.
Auth.currentSession()
to get current valid token or get the new if current has expired. Amplify will handle itx
minutes, maybe 10 min. This is required when you have a long running process like uploading a very large video which will take more than hour (maybe due to slow network) then your token will expire during the upload and amplify will not update automatically for you. In this case, this strategy will work. Keep updating your tokens on some interval.import { Auth } from 'aws-amplify';
try {
const cognitoUser = await Auth.currentAuthenticatedUser();
const currentSession = await Auth.currentSession();
cognitoUser.refreshSession(currentSession.refreshToken, (err, session) => {
console.log('session', err, session);
const { idToken, refreshToken, accessToken } = session;
// do whatever you want to do now :)
});
} catch (e) {
console.log('Unable to refresh Token', e);
}
@mzohaibqc I like your answer -- it got me where I needed to go, so thank you. Just a thought though, and it may not really be important but... As the docs say and I'm sure you know, Auth.currentSession()
will automatically refresh the accessToken
and idToken
if tokens are expired, so if this is the case you will be refreshing the session twice back to back. Not, if the session isn't expired. There is a method cognitoUser.getSignInUserSession()
that obviously returns the original session, from which you can grab the refresh token and pass that to cognitoUser.refreshSession()
instead. I'm picking nits here since either works, albeit the latter could potentially be one less api call. My question is however, (and I was wondering if you knew by chance) if there is any negative impact to using the original signInUserSession
on the CognitoUser
object or reason not to use it as an alternative to Auth.currentSession()
?
const cognitoUser = await Auth.currentAuthenticatedUser();
const { refreshToken } = cognitoUser.getSignInUserSession();
cognitoUser.refreshSession(refreshToken, (err, session) => {}
@jsheebs104 Thanks for sharing this. Small improvements matter.
I don't know about the impact of using cognitoUser.getSignInUserSession()
instead of Auth.currentSession(). I hope both will work the same and as you told,
cognitoUser.getSignInUserSession()` will save api call in case token is expired.
@mzohaibqc Hi a question re your proposed solution, is there a reason why you don't extract the currentSession
directly from the cognitoUser
object?
So my simplified version looks like this, any thought?
try {
const cognitoUser = await Auth.currentAuthenticatedUser();
const currentSession = cognitoUser.signInUserSession;
cognitoUser.refreshSession(currentSession.refreshToken, (err, session) => {
// do something with the new session
});
} catch (e) {
// whatever
}
};
@giulioambrogi I can't test this but seems like a good point and will save one refresh session api call if your session is expired at the time of execution.
I am using Auth.currentSession();. But sometime it failed to give the token
I am getting 401: {message:'The incoming token has expired'}
Then how the token is automatically refreshing here?
export async function get (endpoint: string, data?) {
const currentSession = await Auth.currentSession();
const providerId = currentSession.getIdToken().payload.sub;
const identityJwt = currentSession.getIdToken().getJwtToken();
return GET(endpoint, data, identityJwt, providerId);
}
This will be helpful for anyone willing to refresh Id Token
Axios.interceptors.request.use(function (config) {
return new Promise((resolve, reject) => {
Auth.currentSession()
.then((session) => {
var idTokenExpire = session.getIdToken().getExpiration();
var refreshToken = session.getRefreshToken();
var currentTimeSeconds = Math.round(+new Date() / 1000);
if (idTokenExpire < currentTimeSeconds) {
Auth.currentAuthenticatedUser()
.then((res) => {
res.refreshSession(refreshToken, (err, data) => {
if (err) {
Auth.signOut()
} else {
config.headers.Authorization = "Bearer " + data.getIdToken().getJwtToken();
resolve(config);
}
});
});
} else {
config.headers.Authorization = "Bearer " + session.getIdToken().getJwtToken();
resolve(config);
}
})
.catch(() => {
// No logged-in user: don't set auth header
resolve(config);
});
});`
According to the docs you dont need that anymore.
https://docs.amplify.aws/lib/auth/manageusers/q/platform/js#retrieve-current-authenticated-user
Retrieve current session
Auth.currentSession() returns a CognitoUserSession object which contains JWT accessToken, idToken, and refreshToken.
This method will automatically refresh the accessToken and idToken if tokens are expired and a valid refreshToken presented. So you can use this method to refresh the session if needed.
import { Auth } from 'aws-amplify';
Auth.currentSession()
.then(data => console.log(data))
.catch(err => console.log(err));
Thanks @mzohaibqc for your answer! I have one further issue. At which point in a react application should I trigger the refresh of the token? Is it a good idea to do it in the root component like in app.js or where in a react application should I do this?
@nklswbr You can refresh token in App.js or you can create separate background task like using redux-saga which will refresh your token on application load time or you can create a saga to keep refreshing this after every 50 minutes or so.
Most helpful comment
Here is what I learned after working on two projects.
Auth.currentSession()
to get current valid token or get the new if current has expired. Amplify will handle itx
minutes, maybe 10 min. This is required when you have a long running process like uploading a very large video which will take more than hour (maybe due to slow network) then your token will expire during the upload and amplify will not update automatically for you. In this case, this strategy will work. Keep updating your tokens on some interval.How to refresh on demand is not mentioned in docs so here it is.