👏

Node.jsからCognitoを操作して、アカウントのステータスがどう変化していくかまとめる

2022/10/30に公開

Amazon Cognito を Node.js から操作してみます。

  • ユーザーの作成
  • サインイン
  • サインアウト
  • パスワードの変更
  • メールアドレスを「検証済」に変更

などの操作を試してみます。

Cognito でユーザープールを作成する

Amazon Cognitoを開きます。

ユーザープールの管理 > ユーザープールを作成する

をクリックして、ユーザープールを作成します。

  • プール名:CognitoNodeSample
    • デフォルトを確認する
  • アプリクライアントの追加
    • CognitoAppClientSample で作成
    • ユーザー名パスワードベースの認証を有効にする (ALLOW_USER_PASSWORD_AUTH) にチェックを追加
    • クライアントシークレットを生成 のチェックは外す

Cognito でユーザープールを作成すると、プール ID という ID が生成されるので、メモしておきます。
アプリクライアントをクリックすると、「アプリクライアント ID」が表示されるので、これもメモします。

プール ID とアプリクライアント ID を環境変数に設定する

プール ID とアプリクライアント ID を環境変数に設定します。

MY_USERNAME にはメールアドレスを、
MY_PASSWORD には gefAuC@0982のような、大文字小文字記号混じりの適当な文字列を入れてください。

.env
USER_POOL_ID=
COGNITO_CLIENT_ID=
REGION=
MY_USERNAME=
MY_PASSWORD=

aws-sdk をインストール

npm i aws-sdk
npm i -D @aws-sdk/types

adminCreateUser でユーザーを作成する

AWS Cognito UserPool をサーバーサイドで使うサンプル (Node.js)を参考に Node.js からユーザーを作成します。

import AWS from "aws-sdk";
import "dotenv/config";

const { USER_POOL_ID, COGNITO_CLIENT_ID, REGION, MY_USERNAME, MY_PASSWORD } =
  process.env;

function getEnvVariables() {
  if (!USER_POOL_ID) {
    console.log("exception");
    throw new Error(`USER_POOL_IDが falsy ッス。${USER_POOL_ID}`);
  }
  if (!COGNITO_CLIENT_ID) {
    throw new Error(`COGNITO_CLIENT_ID が falsy ッス。${COGNITO_CLIENT_ID}`);
  }
  if (!REGION) {
    throw new Error(`REGION が falsy ッス。${REGION}`);
  }
  if (!MY_USERNAME) {
    throw new Error(`MY_USERNAME null が falsy ッス。${MY_USERNAME}`);
  }
  if (!MY_PASSWORD) {
    throw new Error(`MY_PASSWORD が falsy ッス。${MY_PASSWORD}`);
  }
  return {
    userPoolId: USER_POOL_ID,
    cognitoClient: COGNITO_CLIENT_ID,
    region: REGION,
    userName: MY_USERNAME,
    password: MY_PASSWORD,
  };
}

async function adminCreateUser() {
  const { userPoolId, userName, region } = getEnvVariables();
  AWS.config.update({
    region,
  });
  const cognito = new AWS.CognitoIdentityServiceProvider({
    apiVersion: "2016-04-18",
  });
  try {
    const user = cognito
      .adminCreateUser({
        UserPoolId: userPoolId,
        Username: userName,
      })
      .promise();
    console.log(
      "ユーザーの登録が完了しました。",
      JSON.stringify(user, null, 4)
    );
    return user;
  } catch (error) {
    console.error(error);
  }
}

async function main() {
  await adminCreateUser();
}

main();

実行結果:

ユーザーの登録が完了しました。 {}

Cognito 上には以下のようにユーザーが作成されます。

アカウントのステータスは FORCE_CHANGE_PASSWORD となっています。
E メールは確認済になっていません。

adminSetUserPassword でユーザーのパスワードを変更する

async function adminSetUserPassword() {
  const { userPoolId, userName, region, password } = getEnvVariables();
  AWS.config.update({
    region,
  });
  const cognito = new AWS.CognitoIdentityServiceProvider({
    apiVersion: "2016-04-18",
  });
  try {
    const result = await cognito
      .adminSetUserPassword({
        UserPoolId: userPoolId,
        Username: userName,
        Password: password,
      })
      .promise();
    console.log("パスワードの変更が完了しました。", result);
  } catch (error) {
    console.error(error);
  }
}

結果:

パスワードの変更が完了しました。 {}

Cognito のステータス FORCE_CHANGE_PASSWORD のまま変化なしです。

Cognito の E メールのステータスを「確認済」にする

async function setEmailVerified() {
  const { userPoolId, userName, region } = getEnvVariables();
  AWS.config.update({
    region,
  });
  const cognito = new AWS.CognitoIdentityServiceProvider({
    apiVersion: "2016-04-18",
  });
  try {
    const param = {
      UserPoolId: userPoolId,
      Username: userName,
      UserAttributes: [
        {
          Name: "email_verified",
          Value: "true",
        },
      ],
    };
    const result = await cognito.adminUpdateUserAttributes(param).promise();
    console.log("Eメールを確認済のステータスに変更しました。", result);
  } catch (error) {
    console.error(error);
  }
}

E メールが「確認済」のステータスになりました。

adminInitiateAuth を使ってサインイン

async function signIn() {
  const { userPoolId, cognitoClientId, userName, password, region } =
    getEnvVariables();
  AWS.config.update({
    region,
  });
  const cognito = new AWS.CognitoIdentityServiceProvider({
    apiVersion: "2016-04-18",
  });
  try {
    const user = await cognito
      .adminInitiateAuth({
        UserPoolId: userPoolId,
        ClientId: cognitoClientId,
        AuthFlow: "ADMIN_USER_PASSWORD_AUTH",
        AuthParameters: {
          USERNAME: userName,
          PASSWORD: password,
        },
      })
      .promise();
    console.log("user.AuthenticationResult", user.AuthenticationResult);
    console.log("user.ChallengeName", user.ChallengeName);
    console.log("user.ChallengeParameters", user.ChallengeParameters);
  } catch (error) {
    console.error(error);
  }
}

結果:

user.AuthenticationResult undefined
user.ChallengeName NEW_PASSWORD_REQUIRED
user.ChallengeParameters {
  USER_ID_FOR_SRP: 'xxxx@gmail.com',
  requiredAttributes: '["userAttributes.email"]',
  userAttributes: '{"email_verified":"true","email":""}'
}

user.ChallengeName NEW_PASSWORD_REQUIRED というチャレンジ名が返ってきているので、「新しいパスワードを設定」する必要がありそうです。
実際の運用では、返ってきたチャレンジ名を見て Cognito とやり取りすることになるでしょう。

adminUserGlobalSignOut でサインアウト

async function signOut() {
  const { userPoolId, userName, region } = getEnvVariables();
  AWS.config.update({
    region,
  });
  const cognito = new AWS.CognitoIdentityServiceProvider({
    apiVersion: "2016-04-18",
  });

  const response = await cognito
    .adminUserGlobalSignOut({
      UserPoolId: userPoolId,
      Username: userName,
    })
    .promise();

  console.log(
    "サインアウトしました。",
    response.$response.httpResponse.statusCode
  );
}

ユーザーのステータスを CONFIRMED にする

async function adminSetUserPasswordAndStatusConfirmed() {
  const { userPoolId, userName, region, password } = getEnvVariables();
  AWS.config.update({
    region,
  });
  const cognito = new AWS.CognitoIdentityServiceProvider({
    apiVersion: "2016-04-18",
  });
  try {
    const result = await cognito
      .adminSetUserPassword({
        UserPoolId: userPoolId,
        Username: userName,
        Password: password,
        // permanent = true にすれば CONFIRMED、指定しなければ FORCE_CHANGE_PASSWORD
        Permanent: true,
      })
      .promise();
    console.log("パスワードの変更が完了しました。", result);
  } catch (error) {
    console.error(error);
  }
}

AccessToken, idToken, RefreshToken を取得する

ユーザーのアカウントのステータスを CONFIRMED に変更した後で、singIn の関数を実行すると、レスポンスで idToken などが取得できます。

async function signIn() {
  const { userPoolId, cognitoClientId, userName, password, region } =
    getEnvVariables();
  AWS.config.update({
    region,
  });
  const cognito = new AWS.CognitoIdentityServiceProvider({
    apiVersion: "2016-04-18",
  });
  try {
    const user = await cognito
      .adminInitiateAuth({
        UserPoolId: userPoolId,
        ClientId: cognitoClientId,
        AuthFlow: "ADMIN_USER_PASSWORD_AUTH",
        AuthParameters: {
          USERNAME: userName,
          PASSWORD: password,
        },
      })
      .promise();
    console.log(user);
    console.log("user.AuthenticationResult", user.AuthenticationResult);
    console.log("user.ChallengeName", user.ChallengeName);
    console.log("user.ChallengeParameters", user.ChallengeParameters);
  } catch (error) {
    console.error(error);
  }
}

user.AuthenticationResultに入ってくるレスポンス:

{
  AccessToken: 'xxx',
  ExpiresIn: 3600,
  TokenType: 'Bearer',
  RefreshToken: 'xxx,
  IdToken: 'xxxxx'
}
GitHubで編集を提案

Discussion