Edited at

Cognito adminInitiateAuthのREFRESH_TOKENフローでSECRET_HASHが合致しないエラーが発生する


現象

下記のコードで NotAuthorizedException: Unable to verify secret hash for client xxx が発生。

secretHashの生成方法は間違っていないはずなのになぜ...?と若干ハマりました。

const { username, password } = req.body

const cognitoidentityserviceprovider = new AWS.CognitoIdentityServiceProvider()
const secretHash = crypto
.createHmac('SHA256', ClientSecret)
.update(username + ClientId)
.digest('base64')

// ログイン
const data = await cognitoidentityserviceprovider
.adminInitiateAuth({
UserPoolId,
ClientId,
AuthFlow: 'ADMIN_NO_SRP_AUTH',
AuthParameters: {
USERNAME: username,
PASSWORD: password,
SECRET_HASH: secretHash
}
})
.promise()

// ログイン成功
const { AuthenticationResult } = data

// リフレッシュトークンを取得
// => NotAuthorizedException発生
await cognitoidentityserviceprovider
.adminInitiateAuth({
UserPoolId,
ClientId,
AuthFlow: 'REFRESH_TOKEN_AUTH',
AuthParameters: {
REFRESH_TOKEN: AuthenticationResult.RefreshToken,
SECRET_HASH: secretHash
}
})
.promise()


原因

結局、ログイン時のUSERNAMEはユーザーから入力されたEmail等を利用してsecretHashを作成するのですが、ログイン後はCognito User Poolsで割り振られたusername(ユニークなID)を利用しなければならないのでした。これはわかりにくい。

const jwt = require('jsonwebtoken')

const secretHash = crypto
.createHmac('SHA256', ClientSecret)
.update(jwt(AuthenticationResult.AccessToken).username + ClientId) // 本番環境では署名検証が必要です
.digest('base64')