概要
AWS SDK for JavaScript (v3) と Cognito を用いてユーザー認証・管理を行うクラス CognitoAdapter の実装例を紹介する。
実装例は以下の機能をサポートしている。
- ユーザー登録 (signup)
- 登録完了承認コードの確認 (confirmSignup)
- 登録完了承認コードの再送 (resendConfirmationCode)
- ログイン (login)
- RefreshTokenを用いたAccessTokenの再取得 (refreshAccessToken)
- AccessTokenの検証 (verifyAccessToken)
前提条件
- Cognito User Pool, App Client (Client Secret有り) が設定済み
- 環境変数として以下が設定済み
-
AWS_REGION
: CognitoがデプロイされているAWSリージョン -
AWS_COGNITO_USER_POOL_ID
: 対象User PoolのID -
AWS_COGNITO_CLIENT_ID
: 対象App ClientのID -
AWS_COGNITO_CLIENT_SECRET
: 対象App Clientに紐づくClient Secret
-
使用ライブラリ
-
@aws-sdk/client-cognito-identity-provider
: CognitoのAPIクライアント -
aws-jwt-verify
: JWTトークンの検証を行うライブラリ -
crypto
: 暗号化ライブラリ
コード例
import {
CognitoIdentityProviderClient,
SignUpCommand,
ConfirmSignUpCommand,
ResendConfirmationCodeCommand,
InitiateAuthCommand,
} from '@aws-sdk/client-cognito-identity-provider'
import crypto from 'crypto'
import { getEnv } from '@/backend/utils/env' // 自前の環境変数取得用のヘルパー
import { CognitoJwtVerifier } from 'aws-jwt-verify'
export class CognitoAdapter {
private client: CognitoIdentityProviderClient
private clientId: string
private clientSecret: string
private verifier: CognitoJwtVerifier
constructor() {
this.client = new CognitoIdentityProviderClient({
region: getEnv('AWS_REGION'),
})
this.clientId = getEnv('AWS_COGNITO_CLIENT_ID')
this.clientSecret = getEnv('AWS_COGNITO_CLIENT_SECRET')
this.verifier = CognitoJwtVerifier.create({
userPoolId: getEnv('AWS_COGNITO_USER_POOL_ID'),
tokenUse: 'access',
clientId: this.clientId,
})
}
// ユーザー登録
async signup(email: string, password: string) {
const secretHash = this.#calculateSecretHash(email)
const command = new SignUpCommand({
SecretHash: secretHash,
ClientId: this.clientId,
Username: email,
Password: password,
})
return await this.client.send(command)
}
// ユーザー登録承認
async confirmSignup(email: string, confirmationCode: string) {
const secretHash = this.#calculateSecretHash(email)
const command = new ConfirmSignUpCommand({
SecretHash: secretHash,
ClientId: this.clientId,
Username: email,
ConfirmationCode: confirmationCode,
})
return await this.client.send(command)
}
// ユーザー登録用の認証コード再送
async resendConfirmationCode(email: string) {
const secretHash = this.#calculateSecretHash(email)
const command = new ResendConfirmationCodeCommand({
SecretHash: secretHash,
ClientId: this.clientId,
Username: email,
})
return await this.client.send(command)
}
// ログイン(ユーザーパスワード認証)
async login(email: string, password: string) {
const secretHash = this.#calculateSecretHash(email)
const command = new InitiateAuthCommand({
ClientId: this.clientId,
AuthFlow: 'USER_PASSWORD_AUTH',
AuthParameters: {
SECRET_HASH: secretHash,
USERNAME: email,
PASSWORD: password,
},
})
return await this.client.send(command)
}
// RefreshTokenを用いてAccessToken再取得
async refreshAccessToken(refreshToken: string, sub: string) {
const secretHash = this.#calculateSecretHash(sub)
const command = new InitiateAuthCommand({
ClientId: this.clientId,
AuthFlow: 'REFRESH_TOKEN_AUTH',
AuthParameters: {
SECRET_HASH: secretHash,
REFRESH_TOKEN: refreshToken,
},
})
return await this.client.send(command)
}
// AccessTokenを検証
async verifyAccessToken(accessToken: string) {
return await this.verifier.verify(accessToken)
}
// SecretHash 計算
#calculateSecretHash(email: string) {
const message = email + this.clientId
const hmac = crypto.createHmac('sha256', this.clientSecret)
hmac.update(message)
return hmac.digest('base64')
}
}
主な処理のポイント
1. Clientインスタンスの生成
CognitoIdentityProviderClient を使用して、Cognitoと通信するためのクライアントを生成しています。
2. Secret Hashの生成
CognitoのApp Clientに「シークレットキー」が有効になっている場合、SECRET_HASH を計算する必要があります。
#calculateSecretHash() メソッドは、email + clientId を鍵としてHMAC-SHA256で署名し、その結果をBase64エンコードしたものをSecretHashとして返します。
3. ユーザー登録・承認フロー
signup() でユーザー登録
confirmSignup() でメール等で届いた確認コードを用いて登録を承認
resendConfirmationCode() で承認コードの再送
これらはCognitoによる標準的なユーザーオンボーディングフローを実現します。
4. ログインおよびRefresh TokenでのAccessToken再取得
login() は、USER_PASSWORD_AUTH フローでログインします。
成功時には AccessToken, IdToken, RefreshToken などが返却されます。
refreshAccessToken() により、失効前の RefreshToken を使って新たな AccessToken を取得可能です。
5. AccessToken検証
verifyAccessToken() は、aws-jwt-verify を用いてトークンがCognitoで発行されたものであることを検証します。
CognitoJwtVerifier.create() で tokenUse や userPoolId、clientId を指定しているため、不正なトークンを弾くことができます。
まとめ
本記事では、AWS Cognitoを用いたユーザー認証処理を抽象化するクラスCognitoAdapterの実装例を示しました。
このクラスを利用することで、サーバーサイドのユーザー登録、認証、トークン検証といった処理を簡潔に扱うことができます。
参考になれば幸いです。