Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to restore an expired token [AWS Cognito]?

I'm using AWS for my website. After 1 hour the token expires and the user pretty much can't do anything.

For now i'm trying to refresh the credentials like this:

 function getTokens(session) {
   return {
     accessToken: session.getAccessToken().getJwtToken(),
     idToken: session.getIdToken().getJwtToken(),
     refreshToken: session.getRefreshToken().getToken()
   };
 };


function getCognitoIdentityCredentials(tokens) {
  const loginInfo = {};
  loginInfo[`cognito-idp.eu-central-1.amazonaws.com/eu-central-1_XXX`] = tokens.idToken;
  const params = {
    IdentityPoolId: AWSConfiguration.IdPoolId
    Logins: loginInfo
  };
  return new AWS.CognitoIdentityCredentials(params);
 };


 if(AWS.config.credentials.needsRefresh()) {
    clearInterval(messwerte_updaten);
    cognitoUser.refreshSession(cognitoUser.signInUserSession.refreshToken, (err, session) => {
      if (err) {
        console.log(err);
      }
      else {
        var tokens = getTokens(session);
               
        AWS.config.credentials = getCognitoIdentityCredentials(tokens);
       
        AWS.config.credentials.get(function (err) {
          if (err) {
            console.log(err);
          }
          else {
            callLambda();
          }
       });
     }
   });
 }

the thing is, after 1hour, the login token gets refreshed without a problem, but after 2hrs i can't refresh the login token anymore.

i also tried using AWS.config.credentials.get(), AWS.config.credentials.getCredentials() and AWS.config.credentials.refresh() which doesn't work either.

The error messages i'm getting are:

Missing credentials in config

Invalid login token. Token expired: 1446742058 >= 1446727732

like image 244
David Avatar asked Feb 20 '18 14:02

David


People also ask

What happens when Cognito token expires?

If the refresh token is expired, your app user must re-authenticate by signing in again to your user pool. If the minimum for the access token and ID token is set to 5 minutes, and you are using the SDK, the refresh token will be continually used to retrieve new access and ID tokens.

How do you refresh an expired token?

Use the Authorization Code Flow to get both a refresh token and access token. If your application is authorized for programmatic refresh tokens, the following fields are returned when you exchange the authorization code for an access token: refresh_token — Your refresh token for the application.

How do you handle expired tokens?

When ACCESS_TOKEN expires you need to call another api with REFRESH_TOKEN to get new ACCESS_TOKEN. The client application can get a new access token as long as the refresh token is valid and unexpired.


4 Answers

After almost 2 weeks i finally solved it.

You need the Refresh Token to receive a new Id Token. Once the Refreshed Token is acquired, update the AWS.config.credentials object with the new Id Token.

here is an example on how to set this up, runs smoothly!

refresh_token = session.getRefreshToken();   // you'll get session from calling cognitoUser.getSession()

if (AWS.config.credentials.needsRefresh()) {

  cognitoUser.refreshSession(refresh_token, (err, session) => {
    if(err) {
      console.log(err);
    } 
    else {
      AWS.config.credentials.params.Logins['cognito-idp.<YOUR-REGION>.amazonaws.com/<YOUR_USER_POOL_ID>']  = session.getIdToken().getJwtToken();
      AWS.config.credentials.refresh((err)=> {
        if(err)  {
          console.log(err);
        }
        else{
          console.log("TOKEN SUCCESSFULLY UPDATED");
        }
      });
    }
  });
}
like image 126
David Avatar answered Oct 11 '22 19:10

David


Usually it's solved by intercepting http requests with additional logic.

function authenticationExpiryInterceptor() {
 // check if token expired, if yes refresh
}

function authenticationHeadersInterceptor() {
 // include headers, or no
}}

then with use of HttpService layer

  return HttpService.get(url, params, opts) {
     return authenticationExpiryInterceptor(...)
            .then((...) => authenticationHeadersInterceptor(...))
            .then((...) => makeRequest(...))
  }

It could be solved by proxy as well http://2ality.com/2015/10/intercepting-method-calls.html

In relation to AWS: https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Credentials.html

You're interested in:

  • getPromise()
  • refreshPromise()
like image 30
kxyz Avatar answered Oct 11 '22 17:10

kxyz


Here is how I implemented this:

First you need to authorize the user to the service and grant permissions:

Sample request:

Here is how I implemented this:

First you need to authorize the user to the service and grant permissions:

Sample request:

POST https://mydomain.auth.us-east-1.amazoncognito.com/oauth2/token&
Content-Type='application/x-www-form-urlencoded'&
Authorization=Basic aSdxd892iujendek328uedj
grant_type=authorization_code&
client_id={your client_id}
code=AUTHORIZATION_CODE&
redirect_uri={your rediect uri}

This will return a Json something like:

HTTP/1.1 200 OK Content-Type: application/json

{"access_token":"eyJz9sdfsdfsdfsd", "refresh_token":"dn43ud8uj32nk2je","id_token":"dmcxd329ujdmkemkd349r", "token_type":"Bearer", "expires_in":3600}

Now you need to get an access token depending on your scope:

POST https://mydomain.auth.us-east-1.amazoncognito.com/oauth2/token
Content-Type='application/x-www-form-urlencoded'&
Authorization=Basic aSdxd892iujendek328uedj
grant_type=client_credentials&
scope={resourceServerIdentifier1}/{scope1} {resourceServerIdentifier2}/{scope2}

Json would be:

HTTP/1.1 200 OK Content-Type: application/json

{"access_token":"eyJz9sdfsdfsdfsd", "token_type":"Bearer", "expires_in":3600}

Now this access_token is only valid for 3600 secs, after which you need to exchange this to get a new access token. To do this,

To get new access token from refresh Token:

POST https://mydomain.auth.us-east-1.amazoncognito.com/oauth2/token >
Content-Type='application/x-www-form-urlencoded'
Authorization=Basic aSdxd892iujendek328uedj
grant_type=refresh_token&
client_id={client_id}
refresh_token=REFRESH_TOKEN

Response:

HTTP/1.1 200 OK Content-Type: application/json

{"access_token":"eyJz9sdfsdfsdfsd", "refresh_token":"dn43ud8uj32nk2je", "id_token":"dmcxd329ujdmkemkd349r","token_type":"Bearer", "expires_in":3600}

You get the picture right.

If you need more details go here.

like image 36
Innocent Criminal Avatar answered Oct 11 '22 19:10

Innocent Criminal


This is how you can refresh access token using AWS Amplify library:

import Amplify, { Auth } from "aws-amplify";

Amplify.configure({
  Auth: {
    userPoolId: <USER_POOL_ID>,
    userPoolWebClientId: <USER_POOL_WEB_CLIENT_ID>
  }
});

try {
    const currentUser = await Auth.currentAuthenticatedUser();
    const currentSession = currentUser.signInUserSession;
    currentUser.refreshSession(currentSession.refreshToken, (err, session) => {
      // do something with the new session
    });
  } catch (e) {
    // whatever
  }
};

More discussion here: https://github.com/aws-amplify/amplify-js/issues/2560.

like image 40
Ruslan Kazakov Avatar answered Oct 11 '22 19:10

Ruslan Kazakov