見出し画像

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に書くというなんともな暫定処置で試していたので、この辺りもおいおい調べていければと思います。

いいなと思ったら応援しよう!