Cognito User Pool: обновить токен доступа с помощью токена обновления
Я использую пул пользователей Cognito для аутентификации пользователей в моей системе. Успешная аутентификация дает идентификационный токен (JWT), токен доступа (JWT) и токен обновления. В документации здесь четко упоминается, что токен обновления может использоваться для обновления токена доступа, но не упоминается как.
У меня вопрос, как только истекает срок действия моего токена доступа, как мне использовать сохраненный токен обновления, чтобы снова обновить мой токен доступа?
Я искал через SDK JavaScript и не мог найти какой-либо метод, чтобы сделать то же самое. Я определенно что-то пропустил.
Также я думал сделать это с помощью функции Lambda, которая получает токен доступа и обновляет токен и отвечает обновленным токеном доступа. Было бы здорово, если бы кто-нибудь смог пролить свет на это.
Ответы
Ответ 1
Если вы находитесь в ситуации, когда Cognito Javascript SDK не будет работать для ваших целей, вы все равно сможете увидеть, как он обрабатывает процесс обновления в источнике SDK:
В refreshSession
вы можете видеть, что конечная точка Cognito InitiateAuth вызывается с REFRESH_TOKEN_AUTH
, установленным для значения AuthFlow
, и объектом, переданным как значение AuthParameters
.
Этот объект необходимо будет настроить в соответствии с потребностями вашего пула пользователей. В частности, вам может потребоваться передать ваш SECRET_HASH
, если у вашего целевого идентификатора клиента приложения есть связанный секретный ключ клиента приложения. Клиентские приложения пула пользователей, созданные для использования с Javascript SDK, в настоящее время не могут содержать секрет клиента, поэтому для их подключения SECRET_HASH
не требуется.
Еще одно предостережение, которое может привести вас к циклу, если ваш пул пользователей настроен на запоминание устройств, и вы не передаете DEVICE_KEY
вместе со своим REFRESH_TOKEN
. В настоящее время Cognito API возвращает ошибку "Недопустимый токен обновления", если вы передаете RefreshToken
, не передавая также DeviceKey
. Эта ошибка возвращается, даже если вы передаете действительный RefreshToken
. Связанная выше нить освещает это, хотя я надеюсь, что AWS обновит свою обработку ошибок, чтобы в будущем она стала менее загадочной.
Как обсуждалось в этой теме, если вы используете AdminInitiateAuth вместе с ADMIN_NO_SRP_AUTH
, полезная нагрузка успешного ответа аутентификации в настоящее время не содержит NewDeviceMetadata
; это означает, что вам не нужно будет передавать DeviceKey
при попытке обновить свои токены.
Мое приложение требует реализации на Python, поэтому вот пример, который работал для меня:
def refresh_token(self, username, refresh_token):
try:
return client.initiate_auth(
ClientId=self.client_id,
AuthFlow='REFRESH_TOKEN_AUTH',
AuthParameters={
'REFRESH_TOKEN': refresh_token,
'SECRET_HASH': self.get_secret_hash(username)
# Note that SECRET_HASH is missing from JSDK
# Note also that DEVICE_KEY is missing from my example
}
)
except botocore.exceptions.ClientError as e:
return e.response
Ответ 2
Javascript sdk обрабатывает обновление токенов внутри. Когда вы вызываете "getSession" для получения токенов, в отсутствие каких-либо действительных кэшированных токенов доступа и идентификаторов SDK использует токен обновления, чтобы получить новый доступ и токены id. Он вызывает аутентификацию пользователя, требуя от пользователя указать имя пользователя и пароль, только когда токен обновления также истек.
С уважением,
Махеш
Ответ 3
Обновление сеанса с SDK браузера amazon-cognito-identity-js; в основном это делается для вас, и если вы не делаете что-то необычное, вам не нужно напрямую обрабатывать токен обновления. Вот что вам нужно знать:
Предположим, что вы создали экземпляр пула пользователей следующим образом:
const userPool = new AmazonCognitoIdentity.CognitoUserPool({
UserPoolId: USER_POOL_ID,
ClientId: USER_POOL_CLIENT_ID
});
Чтобы найти последнее имя пользователя аутентифицированным, вы должны сделать это:
const cognitoUser = cognitoUserPool.getCurrentUser();
Если он найдет его, cognitoUser будет не нулевым, и вы можете сделать это, что при необходимости обновит ваши токены за кулисами:
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, включая этот токен обновления. Он хранит их в локальном хранилище в вашем браузере по умолчанию, хотя вы можете предоставить свой собственный объект хранения, если хотите. По умолчанию токен обновления действителен в течение 30 дней, но это свойство (RefreshTokenValidity) вашего UserPoolClient, которое вы можете изменить. Когда вы сделаете вышеописанное, getSession() сначала увидит, существуют ли токены в вашем хранилище и все еще действительны; в противном случае он попытается использовать любой найденный там refreshToken для аутентификации в новом сеансе.
В документации http://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html указано, что SDK для iOS и Android будут делать это для Вы, хотя я не использовал их, поэтому не могу за это поручиться.
Ответ 4
Я боролся с этим, а также в Javascript. Здесь мое решение основано на https://github.com/aws/amazon-cognito-identity-js, но оно не полагается на хранилище, поэтому вы можете использовать его в лямбда-функции, если вы пожелает.
Изменить: Исправлен код, благодаря 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
})
Ответ 5
Вот пример того, как это сделать с JavaScript на стороне сервера с помощью Node.js.
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?
}
});
Вы можете увидеть полный рабочий пример в своем сообщении в блоге Как аутентифицировать пользователей с помощью токенов с помощью Cognito.
Ответ 6
Если у вас есть токен обновления, вы можете получить новый токен доступа, идентификатор и обновить, просто сделав этот простой запрос POST к cognito:
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
}
Ответ 7
Используя NodeJS aws-sdk
и немного Promise
, вы можете await
аутентифицировать, используя маркер обновления с 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;
})()
Помните, что если отслеживание устройства включено, вы должны передать ключ устройства, в противном случае вы можете получить ошибку Invalid update token.