Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

What's the best practise to refresh Cognito tokens? #2560

Closed
yunganw opened this issue Jan 17, 2019 · 13 comments
Closed

What's the best practise to refresh Cognito tokens? #2560

yunganw opened this issue Jan 17, 2019 · 13 comments
Assignees
Labels
Auth Related to Auth components/category

Comments

@yunganw
Copy link

yunganw commented Jan 17, 2019

** 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.
#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

@haverchuck
Copy link
Contributor

haverchuck commented Jan 18, 2019

@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?

@haverchuck haverchuck self-assigned this Jan 18, 2019
@haverchuck haverchuck added Auth Related to Auth components/category pending-close-response-required labels Jan 18, 2019
@yunganw
Copy link
Author

yunganw commented Jan 20, 2019

Correct. Latest version has this param. Thanks.

@yunganw yunganw closed this as completed Jan 20, 2019
@mzohaibqc
Copy link

mzohaibqc commented Apr 10, 2019

Here is what I learned after working on two projects.

  1. Use Auth.currentSession() to get current valid token or get the new if current has expired. Amplify will handle it
  2. As a fallback, use some interval job to refresh tokens on demand every x 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.
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);
}

@ghost
Copy link

ghost commented Jun 12, 2019

@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) => {}

@mzohaibqc
Copy link

@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.

@giulioambrogi
Copy link

giulioambrogi commented Feb 13, 2020

@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
  }
};

@mzohaibqc
Copy link

@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.

@nihp
Copy link

nihp commented May 29, 2020

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);
}

@ViduraPrasangana
Copy link

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);
      });
  });`

@nklswbr
Copy link

nklswbr commented Nov 11, 2020

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?

@mzohaibqc
Copy link

@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.

@Bariah96
Copy link

Bariah96 commented Jun 2, 2021

@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) => {}

We're having a problem tho that is the refreshSession is taking too much time (around 10 seconds) specifically when the app is being stale for a while (if you leave it for 5 to 7 minutes for example and then come back and refresh the page). any idea why is that ?

@github-actions
Copy link

This issue has been automatically locked since there hasn't been any recent activity after it was closed. Please open a new issue for related bugs.

Looking for a help forum? We recommend joining the Amplify Community Discord server *-help channels or Discussions for those types of questions.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Aug 25, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Auth Related to Auth components/category
Projects
None yet
Development

No branches or pull requests

8 participants