Cognito用户池:如何使用刷新令牌刷新访问令牌

时间:2016-05-25 16:31:43

标签: amazon-web-services aws-lambda amazon-cognito

我正在使用Cognito用户池来验证系统中的用户。成功的身份验证提供ID令牌(JWT),访问令牌(JWT)和刷新令牌。这里的文档http://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html清楚地提到刷新令牌可用于刷新访问令牌,但没有提到如何。我的问题是,一旦我的访问令牌过期,我如何使用存储的刷新令牌再次刷新我的访问令牌?

我搜索了javascript sdk,找不到任何方法来做同样的事情。我绝对错过了什么。

此外,我通过Lambda函数考虑这一点,该函数接收访问令牌并刷新令牌并使用刷新的访问令牌进行响应。如果有人能对此有所了解,那就太好了。

由于

7 个答案:

答案 0 :(得分:25)

如果您处于Cognito Javascript SDK无法正常工作的情况下,您仍然可以看到它如何处理SDK source中的刷新过程:

您可以在refreshSession中看到调用Cognito InitiateAuth端点时为REFRESH_TOKEN_AUTH设置了AuthFlow,并将一个对象作为{{1}传入}值。

需要配置该对象以满足用户池的需求。具体而言,如果您的目标App客户端ID具有关联的App客户端密钥,则可能必须传入AuthParameters。创建用于Javascript SDK的用户池客户端应用程序目前不能包含客户端密钥,因此无需SECRET_HASH连接它们。

另一个可能引发循环的警告是,如果您的用户池设置为记住设备,并且您不会将SECRET_HASHDEVICE_KEY一起传入。如果您传递REFRESH_TOKEN而未传递RefreshToken,则Cognito API当前会返回"Invalid Refresh Token"错误。即使您传入有效的DeviceKey,也会返回此错误。上面链接的线程说明了这一点,尽管我希望AWS在未来更新其错误处理不那么神秘。

正如该线程中所讨论的,如果您使用AdminInitiateAuthRefreshToken,则成功的身份验证响应有效负载当前不包含ADMIN_NO_SRP_AUTH;这意味着当您尝试刷新令牌时,您将无法传入任何NewDeviceMetadata

我的应用程序要求在Python中实现,所以这里有一个对我有用的例子:

DeviceKey

答案 1 :(得分:18)

Javascript sdk在内部处理令牌的刷新。当您调用“getSession”获取令牌时,如果没有任何有效的缓存访问权限和ID令牌,SDK将使用刷新令牌获取新的访问权限和ID令牌。它调用用户身份验证,只有当刷新令牌也过期时才要求用户提供用户名和密码。

此致 马赫什

答案 2 :(得分:7)

使用amazon-cognito-identity-js浏览器SDK刷新会话;它主要是为你做的,除非你做一些不寻常的事情,否则你不需要直接处理刷新令牌。这是你需要知道的:

假设您已经像这样实例化了用户池:

const userPool = new AmazonCognitoIdentity.CognitoUserPool({
  UserPoolId: USER_POOL_ID,
  ClientId: USER_POOL_CLIENT_ID
});

要查找经过身份验证的最后一个用户名,您可以这样做:

const cognitoUser = cognitoUserPool.getCurrentUser();

如果找到一个,cognitoUser将为非null,您可以执行此操作,如果需要,将在幕后刷新您的令牌:

cognitoUser.getSession(function(err, data) {
  if (err) {
    // Prompt the user to reauthenticate by hand...
  } else {
    const cognitoUserSession = data;
    const yourIdToken = cognitoUserSession.getIdToken().jwtToken;
    const yourAccessToken = cognitoUserSession.getAccessToken().jwtToken;
  }
});

如果您不希望这些令牌持久存储在本地存储中,您可以:

cognitoUser.signOut();

它的工作方式是,在成功验证后,浏览器将存储您的JWT令牌,包括该刷新令牌。默认情况下,它会将这些存储在浏览器的本地存储中,但您可以根据需要提供自己的存储对象。默认情况下,刷新令牌在30d内有效,但它是UserPoolClient的属性(RefreshTokenValidity),您可以更改该属性。当你执行上述操作时,getSession()将首先查看存储中的令牌是否存在且仍然有效;如果没有,它将尝试使用它在那里找到的任何refreshToken来验证你进入一个新的会话。

文档http://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html表示iOS和Android SDK会为您执行此操作,但我没有使用它们,因此无法保证。

答案 3 :(得分:4)

我在Javascript中一直在努力解决这个问题。这是我的解决方案,它基于https://github.com/aws/amazon-cognito-identity-js但它并不依赖于存储,因此如果您愿意,可以在lambda函数中使用它。 编辑:修复代码,感谢Crayons

const userPool = new AWSCognito.CognitoUserPool({
  UserPoolId: <COGNITO_USER_POOL>,
  ClientId: <COGNITO_APP_ID>
})

userPool.client.makeUnauthenticatedRequest('initiateAuth', {
  ClientId: <COGNITO_APP_ID>,
  AuthFlow: 'REFRESH_TOKEN_AUTH',
  AuthParameters: {
    'REFRESH_TOKEN': <REFRESH_TOKEN> // client refresh JWT
  }
}, (err, authResult) => {
  if (err) {
     throw err
  }
  console.log(authResult) // contains new session
})

答案 4 :(得分:3)

以下是使用Node.js在服务器端使用JavaScript进行此操作的示例。

const AccessToken = new CognitoAccessToken({ AccessToken: tokens.accessToken });
const IdToken = new CognitoIdToken({ IdToken: tokens.idToken });
const RefreshToken = new CognitoRefreshToken({ RefreshToken: tokens.refreshToken });

const sessionData = {
  IdToken: IdToken,
  AccessToken: AccessToken,
  RefreshToken: RefreshToken
};
const userSession = new CognitoUserSession(sessionData);

const userData = {
  Username: email,
  Pool: this.userPool
};

const cognitoUser = new CognitoUser(userData);
cognitoUser.setSignInUserSession(userSession);

cognitoUser.getSession(function (err, session) { // You must run this to verify that session (internally)
  if (session.isValid()) {
    // Update attributes or whatever else you want to do
  } else {
    // TODO: What to do if session is invalid?
  }
});

您可以在我的博文How to authenticate users with Tokens using Cognito中看到完整的工作示例。

答案 5 :(得分:0)

如果您有刷新令牌,则只需对认知进行简单的POST请求即可获得新的访问权限,ID和刷新令牌:

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=djc98u3jiedmi283eu928&
refresh_token=REFRESH_TOKEN

您将获得以下回复:

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

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

答案 6 :(得分:0)

使用NodeJS aws-sdk和一点Promise,您可以使用{em}和await Refresh Token 来进行initiateAuth身份验证:

const {CognitoIdentityServiceProvider} = require('aws-sdk');

const initiateAuth = (ClientId, REFRESH_TOKEN, DEVICE_KEY) =>
    new Promise((resolve, reject) => {
        const CISP = new CognitoIdentityServiceProvider();

        CISP.initiateAuth(
            {
                ClientId, // Cognito App Client Id
                AuthFlow: 'REFRESH_TOKEN_AUTH',
                AuthParameters: {
                    REFRESH_TOKEN,
                    DEVICE_KEY
                }
            },
            (err, data) => {
                if (err) {
                    return reject(err);
                }

                resolve(data);
            }
        );
    });

// ------ Usage ------ //

(async () => {
    const tokens = await initiateAuth('mY4pps3cR3T', '<R3FR3SHT0K3N>');

    console.log('Tokens', tokens);

    const {AuthenticationResult: {AccessToken, IdToken, ExpiresIn, TokenType}} = tokens;
})()
  

请记住,如果启用了 设备跟踪 ,则应传递设备密钥,否则您会收到无效的刷新令牌< / em>错误。