個人的備忘録：Amazon Cognitoのsubの仕組みが面白いと思ったので、自分なりに体系的にまとめてみた

## はじめに  
Amazon Cognito は、ユーザー認証を簡単に管理できる便利なサービスです。  

:::note info
**その中で、各ユーザーに一意に付与される `sub` は、変更されることがない識別子として重要な役割を持ちます。**
:::

本記事では、`sub` の概要や特徴、活用方法について解説します。***Cognito を活用したアプリケーション開発に役立ててください。***

**過去の関連記事**

https://qiita.com/free-honda/items/3e0abb85d6a4cbdb501e

## 書こうと思ったきっかけ  
Cognito を使ったユーザー認証では、`email` や `username` ではなく、`sub` を識別子として利用することが推奨されています。  

:::note warn
***しかし、`sub` の詳細な仕様や活用方法についての情報は、意外と整理されていないことが多いです。***
:::

そこで、Cognito の `sub` の基本から実践的な活用方法までを体系的にまとめることで、開発者がスムーズに理解できるようにしたいと考えました。

https://aws.amazon.com/jp/cognito/

## Amazon Cognitoのsubについてのまとめ

### 1. subとは？
`sub`（Subjectの略）は、Amazon Cognitoのユーザープールで各ユーザーに一意に割り当てられる識別子（UUID）です。  

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

この値は一意性が保証されており、変更されることはありません。

例えば、Cognitoから取得したユーザー情報のJSONには、以下のように`sub`が含まれています。

```json
{
  "sub": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
  "email": "user@example.com",
  "username": "user123"
}
```

### 2. subの特徴
- **一意性**：各ユーザーごとに一意のUUIDが付与される。  
- **変更不可**：ユーザーがメールアドレスやユーザー名を変更しても、`sub` の値は変わらない。  
- **認証トークンに含まれる**：Cognitoの `id_token` や `access_token` に含まれる。  
- **識別子として利用**：データベースのユーザー識別子として使うことが推奨される。  

### 3. subの利用方法

#### (1) IDトークンからsubを取得  
Cognitoの認証後、`id_token` をデコードすると `sub` を取得できます。

```json
{
  "sub": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
  "email": "user@example.com",
  "username": "user123",
  "exp": 1710000000
}
```

#### (2) subをユーザーの識別子として使う  
アプリケーションのデータベースで、ユーザーを識別する主キー（Primary Key）として `sub` を保存すると、  
メールアドレス変更やユーザー名変更による影響を受けないため、安定したユーザー識別が可能になります。

```sql
CREATE TABLE users (
    id UUID PRIMARY KEY,
    email VARCHAR(255),
    username VARCHAR(255)
);
```

#### (3) データベースのIDとしてsubを使用  
Cognitoの認証後、取得した `sub` をデータベースの `id` として使用することで、一意性が保証され、ユーザー識別が安定します。  

メールアドレスやユーザー名が変更されても影響を受けないため、推奨される方法です。

```py
import jwt

def get_sub_from_token(id_token):
    decoded = jwt.decode(id_token, options={"verify_signature": False})
    return decoded.get("sub")

id_token = "eyJraWQiOiJrMWF..."
sub = get_sub_from_token(id_token)
print(f"User ID (sub): {sub}")
```

### 4. subと他の識別子の違い

| 識別子     | 説明                                   | 変更の可能性 |
|------------|--------------------------------------|--------------|
| `sub`      | Cognitoが発行する一意のUUID         | **変更不可** |
| `email`    | ユーザーのメールアドレス             | **変更可能** |
| `username` | ユーザー名                           | **変更可能** |

### 5. 注意点

- **UUIDのため、人間が読める形式ではない**  
  `sub` はUUID形式（例：`aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee`）なので、  
  直接ユーザーに表示するのではなく、`username` や `email` を表示に使うと良い。  

- **外部サービスのユーザーIDとは異なる**  
  Cognitoの `sub` は、GoogleやFacebook認証時のIDとは異なるため、  
  SNS認証を利用する場合は、`sub` とは別に `identities` フィールドをチェックする必要がある。  

### 6. subの総括

- `sub` は Amazon Cognito が発行する **変更されない** ユーザー識別子（UUID）。  
- `id_token` に含まれ、アプリケーションでのユーザー識別に利用できる。  
- データベースのユーザー識別キーとして使うと、メールアドレス変更などの影響を受けずに管理できる。  
- `sub` は人間にとって読みにくいため、表示用途には `username` や `email` を使うのが望ましい。  


## 3. まとめ  
`sub` は Cognito が発行する一意の識別子であり、ユーザー情報の管理に適しています。  

:::note warn
**`id_token` から取得し、データベースの主キーとして利用することで、メールアドレス変更の影響を受けずに安定した識別が可能です。**
:::

また、SNS ログイン時には `identities` のチェックも重要です。***Cognito を利用する際には、`sub` の特性を理解し、適切に活用することが重要です。***