【AWS】Cognitoでユーザー名を使用せず、メールアドレスのみ使用する

# はじめに

Cognito ではユーザー名属性を使用しない設定が可能。

> ユーザー名が不要の場合は、ユーザーにユーザー名を指定するように求める必要はありません。アプリでユーザー用の一意のユーザー名をバックグラウンドで作成できます。例えば、E メールアドレスとパスワードを登録しそれを使用してサインインするようにユーザーに求める場合は便利です。

https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-usernames

# ユーザー名属性としてメールアドレスを使用する

この場合、下記のように表示上ユーザー名は sub の値となるが、ユーザーからすればこの値はわからないため、メールアドレスとパスワードでログイン可能となる。

![スクリーンショット 2024-07-13 185238.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/3d797560-22fa-2e92-8b5b-ed7f249ea84c.png)

設定方法はドキュメントにある通り、ユーザープール作成時に「Eメール」のみチェックを入れる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/621414/749956a0-5836-bf04-7a4e-3b030dfeee9e.png)

> ユーザー名属性を選択するには、ユーザープールを作成するときに、サインインオプションとして [ユーザー名] を選択しないでください。

https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-aliases

この sub の値は、サインアップ時に Cognito 内部で生成される。サインイン時にはこの sub の値は不要である（下記参照）。

> ListUsers API を除くすべての API で、E メールアドレスまたは電話番号をエイリアスとしてユーザー名の代わりに使用できます。

例えば、[サインイン(AWS SDK for JavaScript v3)](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/cognito-identity-provider/command/InitiateAuthCommand/) 時には次のように `USERNAME` パラメータにユーザーのメールアドレスを渡すことでサインインが可能となる。

```js
const command = new InitiateAuthCommand({
  AuthFlow: AuthFlowType.USER_PASSWORD_AUTH,
  AuthParameters: {
    USERNAME: email, // sub の値ではなく, メールアドレスを渡す
    PASSWORD: password,
  },
  ClientId: clientId,
});
```



# サンプルコード

## サインアップ

```sign-up.js
const {
  SignUpCommand,
  CognitoIdentityProviderClient,
} = require('@aws-sdk/client-cognito-identity-provider');

const config = {
  region: 'your-region',
};

// サインアップメソッド
const signUp = async ({ clientId, username, password, email }) => {
  const client = new CognitoIdentityProviderClient(config);

  // サインアップ
  const command = new SignUpCommand({
    ClientId: clientId,
    Username: username, // 必須属性
    Password: password,
    UserAttributes: [
      {
        Name: 'email',
        Value: email,
      },
    ],
  });

  return client.send(command);
};

// サインアップメソッド呼び出し
signUp({
  clientId: 'xxxxxxxx',
  username: 'test@example.com', // emailと同一でなければならない
  email: 'test@example.com',
  password: 'yyyy',
})
  .then((res) => {
    console.log(res);
  })
  .catch((error) => {
    console.error(error);
  });

module.exports = { signUp };

```

- ユーザー名属性を使用していなくても、`Username` 属性は必要。 `Username` 属性を `SignUpCommand` に渡さないと下記のエラーが発生する

```
InvalidParameterException: 1 validation error detected: Value at 'username' failed to satisfy constraint: Member must not be null
```

- `Username` 属性が `email` 属性と異なる値の状態で `SignUpCommand` が呼び出した場合、下記のエラーが発生する

```
InvalidParameterException: User email should be empty or same as username, since username attribute is email.
```

- `Username` 属性にメールアドレス形式ではない文字列を渡して `SignUpCommand` を呼び出した場合、下記のエラーが発生する

```
InvalidParameterException: Username should be an email.
```

## サインイン

```initiate-auth.js
const {
  AuthFlowType,
  CognitoIdentityProviderClient,
  InitiateAuthCommand,
} = require('@aws-sdk/client-cognito-identity-provider');

const config = {
  region: 'your-region',
};

// サインインメソッド
const initiateAuth = ({ email, password, clientId }) => {
  const client = new CognitoIdentityProviderClient(config);

  // サインイン
  const command = new InitiateAuthCommand({
    AuthFlow: AuthFlowType.USER_PASSWORD_AUTH,
    AuthParameters: {
      USERNAME: email, // sub の値ではなく, メールアドレスを渡す
      PASSWORD: password,
    },
    ClientId: clientId,
  });

  return client.send(command);
};

// サインインメソッド呼び出し
initiateAuth({
  email: 'test@example.com',
  password: 'yyyy',
  clientId: 'xxxxxxxx',
})
  .then((res) => {
    console.log(res);
  })
  .catch((error) => {
    console.error(error);
  });

module.exports = { initiateAuth };
```

# 参考

https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-usernames

https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-aliases