AWS | Amazon CognitoとAWS SDK for JavaScript v3でユーザー登録
ユーザー登録までの流れを忘れそうなので記録しておきます。
「一旦出来た」という状態なので、間違い等あるかもしれません。
環境
Amazon Cognitoのセットアップ
Terraformの部分抜粋です。
ユーザー名をemailにした (username_attributes)
Administrator以外でもユーザー登録を許可した (allow_admin_create_user_only)
クライアントシークレットの生成は無しにした (generate_secret)
認証フローを多めに設定した (explicit_auth_flows、絞り込みは追々)
resource "aws_cognito_user_pool" "dev" {
name = "dev"
username_attributes = ["email"]
auto_verified_attributes = ["email"]
admin_create_user_config {
allow_admin_create_user_only = false
}
password_policy {
minimum_length = 8
require_lowercase = false
require_uppercase = false
require_numbers = false
require_symbols = false
temporary_password_validity_days = 7
}
account_recovery_setting {
recovery_mechanism {
name = "verified_email"
priority = 1
}
}
tags = {
"Environment" = "development"
}
}
resource "aws_cognito_user_pool_client" "dev" {
name = "dev"
user_pool_id = aws_cognito_user_pool.dev.id
generate_secret = false
explicit_auth_flows = ["ALLOW_USER_SRP_AUTH", "ALLOW_REFRESH_TOKEN_AUTH", "ALLOW_ADMIN_USER_PASSWORD_AUTH", "ALLOW_CUSTOM_AUTH", "ALLOW_USER_PASSWORD_AUTH"]
callback_urls = ["http://localhost:3333"]
logout_urls = ["http://localhost:3333"]
allowed_oauth_flows_user_pool_client = true
allowed_oauth_flows = ["code", "implicit"]
allowed_oauth_scopes = ["email", "openid"]
supported_identity_providers = ["COGNITO"]
}
CLIで動作確認
Amazon Cognitoのセットアップが出来たらCLIで動作確認しておきます。
aws cognito-idp sign-up --client-id <CLIENT ID> --username <USERNAME> --password <PASSWORD>
ユーザー登録の全体イメージ
Amazon Cognitoに登録したクライアントアプリケーションをいつ使うのか最初混乱したので、全体イメージを貼っておきます。
新規アカウント登録
CognitoIdentityProviderのadminCreateUserを使います。
登録に成功するとUsernameに指定したemailに一時パスワードのメールが飛びます。
(Amazon Cognitoに備わっているメール機能により)
なお、Amazon Cognito上に登録されたユーザーの状態は「FORCE_CHANGE_PASSWORD」となります。
const config: CognitoIdentityProviderClientConfig = {
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID || '',
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || ''
}
};
const provider = new CognitoIdentityProvider(config);
const result = await provider.adminCreateUser({
UserPoolId: process.env.COGNITO_USER_POOL_ID || '',
Username: payload.email
});
ちなみに、クライアントアプリケーション経由のユーザー登録も出来そうでしたが(allow_admin_create_user_only=falseにしてるし??)、ひとまず使い分けて検証を進めました。
初回サインイン
一次パスワードを用いてサインインを行います。
ここで返ってきたユーザーの状態が「NEW_PASSWORD_REQUIRED」となっているため初回パスワード変更を行います。
また、同時に返ってきているSessionも利用します。
const config: CognitoIdentityProviderClientConfig = {
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID || '',
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || ''
}
};
const input: InitiateAuthCommandInput = {
ClientId: process.env.COGNITO_CLIENT_ID,
AuthFlow: 'USER_PASSWORD_AUTH',
AuthParameters: {
USERNAME: payload.email,
PASSWORD: payload.password
}
};
const client = new CognitoIdentityProviderClient(config);
const command = new InitiateAuthCommand(input);
const response = await client.send(command);
初回パスワード変更
ここで利用するRespondToAuthChallengeCommandとは別にCognitoIdentityProviderにあるadminSetUserPasswordでもパスワード変更は出来るようですが、こちらはSessionなど不要でAdministrator用かと思ったためadminSetUserPasswordは利用しませんでした。
const config: CognitoIdentityProviderClientConfig = {
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID || '',
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY || ''
}
};
const input: RespondToAuthChallengeCommandInput = {
ClientId: process.env.COGNITO_CLIENT_ID,
ChallengeName: 'NEW_PASSWORD_REQUIRED',
Session: payload.session,
ChallengeResponses: {
USERNAME: payload.username,
NEW_PASSWORD: payload.password
}
}
const client = new CognitoIdentityProviderClient(config);
const command = new RespondToAuthChallengeCommand(input);
const response = await client.send(command);
これに成功すると、以降のレスポンスにAccessTokenなどが返ってくるようになります。
さいごに
マイクロサービス化などを進めると認証基盤をどうしようかと思ったときに、サーバレスで構築出来るAmazon Cognitoも候補に含まれるかなと思い今回検証していました。
どういうトラブルがあるのか、バックアップ・リカバリはどうできるのか、開発環境構築に手間は無いか、など実運用に向けては課題があるかと思います。
ちなみに今回はRemixのArchitect (AWS Lambdaにデプロイ出来る) を利用してみましたが、一緒に利用しているAWS-Vaultの環境変数をパスしてくれないようで(デフォルト利用、調べきれてない)、最初ユーザー登録出来ずに悩んでいました。AWS-VaultからAccessKey等を取り出しdotenvに書くというなんともな暫定処置で試していたので、この辺りもおいおい調べていければと思います。