Amazon Cognito + Oktaでシングルサインオン(SAML認証)に入門する

# はじめに
学習の一環でAmazon Cognitoを使用したシングルサインオンをお試しする機会があったので、備忘として手順などを残しておきます。

# 概要
## シングルサインオンとは
シングルサインオン(以降、SSOと記載)は、Single Sign-Onという名の通り、ユーザーが1回限りの認証で複数のアプリケーションにログインできる仕組みです。

### シングルサインオン無の場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/83634164-9fe4-47ea-a6af-d31e73a92a03.png)

### シングルサインオン有の場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/43d06ee8-86f8-4b21-bef8-c8c84da4310e.png)

「この集中管理する奴」が俗に言うIdPにあたります。

### 例えば...
Qiitaの場合は、以下のようにGitHubなどのユーザーでシングルサインオンが可能です。
これはQiitaにユーザーを作らなくても、他のサービスで管理しているユーザーを使ってQiitaにログインすることができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/7ae8ffe7-6807-40b0-b63f-799087e3543b.png)

また実際の企業ではMicrosoftのActiveDirectoryなどで社内のユーザーを管理しているところもあると思います。そういった場合にもActiveDirectoryを使って、社内向けのサービス等でシングルサインオンを実装しているところもあると思います。

## どうやってシングルサインオンを実現するの？
### フェデレーション方式を使う
フェデレーション方式は、1度の認証が通れば、その認証情報を他のサービスに連携し、他のサービスを使えるようにする仕組みです。フェデレーション方式の中でも以下のように複数のやり方があります。
- SAML
- OpenID Connect (OIDC)
- 等

**今回はSAMLを使ってシングルサインオンを実現します。**

## SAMLって何よ？
SAMLは、Security Assertion Markup Languageの略称です。
異なるサービス（ドメイン）間で認証を行うためのXMLベースの規格のことです

#### 登場アクター
SMAL認証で登場する各アクターの説明を記載します。

| アクター               | 役割                                                                                                                                                               | 
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | 
| ユーザー               | Webサイトにログインして、Webサイトからサービスを利用する人です                                                                                                     | 
| SP(Service Provider)   | SPは、IdPと連携して認証情報を受け取り、ユーザーにサービスを提供するサーバです                                                                                                                | 
| IdP(Identity Provider) | IdPは、ユーザーを認証し、認証情報を発行するサーバーです


#### 図説

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/999cf65c-b3bd-4439-b0ff-c880cae61a1f.png)

**今回は、SPにAmazon Cognito、IdPにOktaを使用します。**

## Amazon Cognitoとは

Amazon Cognitoは、アプリケーションに対して「認証」と「認可」の仕組みを提供するサービスです。大きく「ユーザープール」と「IDプール」に分かれますが、今回は「ユーザープール」を使用します。

### ユーザープールとは
ユーザープールは、アプリケーションに認証とユーザー管理の機能を提供します。
アプリケーションと連携することで、サインアップやログインの機能を実現できます。
ユーザー情報は、ユーザープールに保存されます。

## Oktaとは

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/4bcb67ca-0647-40fc-9edf-be292cb580f6.png)

[Okta](https://www.okta.com/ja-jp/)Oktaは、クラウド型のIDaaSサービスです。
IdPに使用すると言った時点でお察しかもしれませんが、複数のサービスのIDやパスワードをクラウド上で一元管理してくれるサービスです。

:::note info
**IDaaS(Identity as a Service)**
クラウドを利用してIDやパスワードなどの認証基盤を管理するサービスです
:::

# 実際に試してみる
## 実現したいこと
### 画面の流れ
ざっくりと以下のような流れです。
- **ログイン(Cognito)**
    - Cognitoがログイン画面を提供してくれる機能(マネージドログイン)があるので、そのまま使用します。
- **ログイン(Okta)**
    - 実際のログインはOktaが用意した画面にリダイレクトされ、ユーザー情報を入力します。
- **メイン画面**
    - ローカル環境(localhost)で適当な画面を立ち上げて、ログイン後はメイン画面として表示します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/d0172bef-aff0-434b-bb25-fea2cfb81ab8.png)

## バックエンド側の構成
CognitoとOktaで以下のような構成を作り、シングルサインオンを実現します。
厳密に言うと、`アプリケーションクライアント`に`フェデレーションIdP`を紐づけるのですが、ごちゃ付くので線を書いてません。
```mermaid
graph TD;
    subgraph Amazon Cognito
        ユーザープール-->アプリケーションクライアント;
        ユーザープール-->フェデレーテッドIdP;
        ユーザープール-->ドメイン;
    end
    
    subgraph Okta
        フェデレーテッドIdP-->OktaApp[("Okta App")];
        
        OktaApp-->ユーザー管理;
        ユーザー管理-->User1(("User1"));
        ユーザー管理-->User2(("User2"));
        ユーザー管理-->User3(("User3"));
        
        OktaApp-->SAML設定;
    end
```
## 事前準備
### 準備① Oktaの無料トライアルの申請
<details><summary>詳細はこちら</summary>

Oktaでは、30日間の [無料トライアル](https://www.okta.com/jp/free-trial/) が可能です。今回は無料トライアルでお試しします。

１. Oktaの無料トライアルページを開き、各項目を入力します。その後、「無料トライアルを始める」ボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/b8a49dcb-efa6-5ab5-33b9-d04ccc2659ab.png)

２. 「終了」ボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/f872fd05-5ba8-28cf-7d5c-9fa0267b6501.png)

３. 下記の画面が表示されます。メールを確認します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/3c9d229c-22a2-4b41-d66b-52fd5567ad72.png)

4. メールに埋め込まれた「Activate Okta Account」ボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/50f65ceb-dc24-bb71-9eb9-6b98ce0e00c0.png)

５. 画面に戻るとパスワードのセットアップを促されるので、「セットアップ」ボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/2b6abba2-144c-1326-3aec-705b75703e5e.png)

６. パスワード要件に従い任意のパスワードを入力し、「次へ」ボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/81e737f4-89a9-b568-610d-471d95dddbf6.png)

７. Okta Verifyのセットアップを促されるので「セットアップ」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/7bb2f5e4-9149-b8f2-8411-4dcfef984155.png)

８. スマホアプリをインストールし、セットアップします。
 - [Andoridアプリ](https://www.google.com/search?q=okta+verify&rlz=1C1QABZ_jaJP908JP908&oq=Okta+Ve&gs_lcrp=EgZjaHJvbWUqCggAEAAYsQMYgAQyCggAEAAYsQMYgAQyBggBEEUYOTIHCAIQABiABDIHCAMQABiABDIHCAQQABiABDIHCAUQABiABDIHCAYQABiABDIGCAcQRRg80gEINTE3M2owajeoAgCwAgA&sourceid=chrome&ie=UTF-8)
 - [iOSアプリ](https://apps.apple.com/jp/app/okta-verify/id490179405)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/db0f6e0c-47fc-9c0e-3d0e-3a45aaaa38c0.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/ef5fb0d5-f05b-f4cc-d8ac-c4162e5334f9.png)

９. 初期設定が始まります。「Other」ボタンを押すと、入力欄が表示されるのでAmazon Cognitoと入力し、「Submit」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/f075ff85-dcf8-2a89-6108-c4fd41e07f5c.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/6f1b95ae-75cd-c031-4d02-ead9c1c51410.png)

１０. 画面右下の「Next」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/4b35f96f-ef5f-dfcf-c377-0e0a91272a22.png)

１１. 次も同じく「Other」ボタンを押し、Amazon Cognitoと入力し、「Submit」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/8cf41fd4-1e56-535d-7a17-0602083f092d.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/e403314d-2779-22bc-7cb5-a79c51983ff1.png)

１２. 「Single Sign-On (SSO)」を選択し、画面右下の「Next」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/813b83a5-947a-2d9e-d047-5cfde23bf1ae.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/bf6804b1-8489-65e7-5e04-842288e94cde.png)

１３. 「Done」ボタンを押して、設定完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/d1af515a-2d6f-2e83-7ee5-d7c7c74ba174.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/efd1e57b-8d9f-83d6-2bcf-aeb1bda7f483.png)

</details>


### 準備② ユーザープールを作成する

<details><summary>詳細はこちら</summary>

１. AWSマネジメントコンソールにアクセスします。

２. 「Amazon Cognito」>「ユーザープール」の画面を開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/5e8d7810-8def-4524-b7d3-3258d1a0a742.png)

３. 画面右上の「ユーザープールを作成」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/fb199a4e-e4a7-4dcf-a628-1dd68da89a2b.png)

#### アプリケーションのリソースを設定する
４. アプリケーションタイプに「シングルページアプリケーション(SPA)」を選択します。
５. アプリケーションに名前を付けるでは、任意の名前を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/09c1a9c6-4e83-4693-906a-9a43c33fd644.png)

６. サインイン識別子のオプションでは、`メールアドレス`にチェックを入れます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/642447a3-e6a0-42c2-b006-d947853b1559.png)

７. リターンURLを追加欄にログイン成功後、どの画面に遷移させるかを指定します。今回は、「http://localhost:5174」としました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/90f781ba-99bf-4b5a-b5ad-4342e61ed0c7.png)

８. 最後に「ユーザーディレクトリを作成する」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/df004067-7188-4943-9fbb-e9c0b38afa8b.png)

これでユーザープールが出来上がりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/728602b7-e8ff-40e4-8f10-7798508b7829.png)

既にログイン画面も用意されているので、ブラウザで開いてみましょう。
「ログインページを表示」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/79526817-f592-429a-a29c-c92fe7ef21c9.png)

以下のようなログイン画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/5b9155f8-b175-43ba-a92b-6b3adb2e18c0.png)

</details>

### 準備③ ログイン後に表示する画面を作成する

<details><summary>詳細はこちら</summary>

１. viteを使用して空のプロジェクトを作成します。
```
> npm create vite@latest

Need to install the following packages:
create-vite@6.0.1
Ok to proceed? (y) y
√ Project name: ... test_cognito_app
√ Select a framework: » React
√ Select a variant: » JavaScript

Scaffolding project in D:\\test_cognito_app...

Done. Now run:
```

:::note info
**vite**
Viteは、モダンなWebアプリケーション開発のための高速なビルドツールです。
従来のビルドツールよりも高速な開発サーバーの起動と、効率的な本番ビルドを提供し、React、Vue、Svelteなど様々なフレームワークをサポートしています。
:::

２.依存パッケージをインストールします。
```
cd test_cognito_app
npm install
```

３. ローカル環境で画面を立ち上げてみます。
```
npm run dev
```

ブラウザでhttp://localhost:5173/ にアクセスし、以下の画面が表示されればOKです。
今回はこの画面をログイン後に表示されるメイン画面として扱います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/99b13ca3-0c95-4896-85d5-b224d8e96e93.png)

</details>

事前準備で以下のところまで作りました。この後、実際にSAML周りの設定を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/84b28a56-4614-45fb-82ed-11306fc42502.png)


## Step1. OktaにSAMLの設定をする
Okta側にSAML認証を行うために必要な設定をしていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/85447c9e-8290-47a2-9eb1-1eaee3212fc7.png)

### アプリケーションの作成
１. Oktaに`管理者`でログインします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/699bd2e7-8dec-4579-9176-4cf31a2caf8b.png)

２. 画面左のメニューから「アプリケーション」 > 「アプリケーション」を開き、「アプリ統合を作成」を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/13c65352-4da6-40e7-8419-3915bfbcf9cb.png)


３. 「SAML 2.0」のラジオボタンを選択し、「次へ」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/640e36ff-86f2-f3b4-b8ce-d4508d459c64.png)

４. 「アプリ名」欄に任意の名称を入力し、「次へ」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/7004bad9-2520-06c8-c5ff-ba5396fa44f7.png)

５. SAMLの設定値を入力します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/f6d0c13f-7b44-10f9-84f7-ee2b449733d8.png)

**シングルサインオンURLの入力**
ユーザープールの`ドメインURL` + 固定`/saml2/idpresponse`がシングルサインオンURLとなります。

```:
https://okta-saml.auth.ap-northeast-1.amazoncognito.com/saml2/idpresponse
```

**オーディエンスURL (SPエンティティID)の入力**

固定で`urn:amazon:cognito:sp:`+ Cognitoの`ユーザープールID`がオーディエンスURLとなります。
```:オーディエンスURL (SPエンティティID)
urn:amazon:cognito:sp:ap-northeast-1_xq0EZffDF
```

**属性ステートメントの入力**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/677aa977-a324-b67c-345d-d2009a17969b.png)


６. 画面下までスクロールし、「次へ」ボタンを押します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/428154df-318d-44f2-a322-2e0ded5c7c68.png)

７. そのまま「終了」ボタンを押します。これでOktaのSAMLの設定は完了です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/536f943d-996e-4edd-a060-12c5de2c6e6f.png)

### アプリケーションにユーザーを割り当てる

1. 作成したアプリケーションの画面から「割り当て」タブを開き、「割り当て」>「ユーザーに割り当て」を押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/75bcd07d-f7d3-464e-85c6-7fa0839dfbb5.png)

2. 登録した自分のユーザーがいると思うので、「割り当て」ボタン > 「保存して戻る」ボタン>「完了」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/81c1c081-b69d-49e0-8034-b43d4770baf3.png)

### Cognitoに設定するメタデータを取得する
１. 「サインオン」タブを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/b301a596-85ed-45d3-b661-630cd67a720b.png)

２. 「サインイン方法」にメタデータURLがあるので、コピーしておきます。(このURLを後ほどCognitoに設定します)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/d24da846-0a5f-4b64-80d4-527c8f3a5456.png)

:::note info
Cognitoでは、XMLファイルとしてもメタデータを設定することができます。
その場合、画面を下までスクロールすると、「SAML署名照明書」欄があります。
その中の「SHA-2」の行の「アクション」を押し、メニューから「IdPメタデータを表示」押して内容をファイル保存してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/0e80bbe7-9ad4-0a1c-d909-2b5d1cae6aac.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/9bee982c-8a3a-a4a6-ddf5-05ffdf019578.png)
:::

これでOkta側の設定は以上となります。次からはCognito側の設定に移ります。

## Step2. Cognitoにアイデンティティプロバイダーを追加する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/2f51f658-3d58-4be0-bcdc-397c9331ccc0.png)

1. ユーザープールを開き、画面左のメニューから「認証」>「ソーシャルプロバイダーと外部プロバイダー」を開きます。開いたら「アイデンティティプロバイダーを追加」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/8e61f8e8-aa15-4982-a29a-31a295754b44.png)

２.アイデンティティプロバイダーでは、「SAML」のラジオボタンを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/91fc79f4-5a8a-4fe6-a750-0247d6fd9338.png)

３. SAMLでは「プロバイダー名」、「識別子」に任意の値を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/cb35e0a5-205f-49d9-bde9-f950046d88a9.png)

４．続けて「メタデータドキュメントのエンドポイントURLを入力」のラジオボタンを選択し、先ほどOktaの設定でコピーしたメタデータURLを入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/acb8e1d5-2ffb-406a-974d-52440947ebfa.png)

５. 最後に「SAML属性」欄に`email`属性を入力し、画面下の「アイデンティティプロバイダーを追加」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/1a75e6de-61dc-4c99-9f81-f25a3ee19d97.png)

６．追加できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/6d2cab99-fad7-a6bf-cfb3-af94b73fca13.png)

## Step3. アプリケーションクライアントにアイデンティティプロバイダーを紐づける

１. ユーザープールを開き、「アプリケーション」>「アプリケーションクライアント」>「(任意のアプリケーションクライアント)」を選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/3aa97f97-0a13-4502-91e7-fbf3c5845c66.png)

２. タブの中から「ログイン」タブを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/83da7028-ba03-4c30-aa0e-593da8769693.png)

３. 「編集」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/598a355b-3c6d-4e53-baa7-dfcb00f83012.png)

４. IDプロバイダー欄のセレクトボックスを押すとプルダウンが表示されるので、先ほど作成したアイデンティティプロバイダーが選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/63116796-d3ad-4428-a320-5b1e322b5af7.png)

５. 下までスクロールし、「変更を保存」ボタンを押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/b19228d7-fb84-4090-ab65-28acd7bd9f88.png)

## Step4. 動作確認
期待値は以下の画面遷移となることです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/fcc519fa-869c-45fd-bd4d-60582fc14ada.png)

先ほどのログイン画面を再度開いてみます。「Continue with okta-saml-provider」ボタンが増えているので、押します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/24513990-88e9-4426-b61e-530921f2290b.png)

Oktaのログイン画面が表示されるので、Oktaのユーザー情報を入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/f641648e-5ac6-4aa7-ba7e-3d4ce0c3394d.png)

それぞれ「コードを入力する」、「パスワード」の項目を「選択」ボタンから入力します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/0c26bacb-4f1a-4e6c-8611-2edbf7ffa656.png)

すると...

期待通りローカル環境で実行した画面(http://localhost:5174) が表示されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/560123/42b649b8-ced3-4602-bfa3-0f8e4cc4b349.png)

# まとめ
今回、SAML認証によるシングルサインオンを試してみました。
各要素の関係性が理解しづらかったため、図にすることで理解を深めることができました。

実際に試してみると、動作自体は意外と容易でしたが、これがSAMLではなくOpenID Connectに変わったり、IdPがOktaではなくMicrosoft ADに変わることを考えると、設定や覚えることが多くて大変だと感じました。

また、実運用を考えると、IdP側とSP側が別会社ということも往々にしてあると思うので、そのあたりのコミュニケーションも骨が折れそうだなと思いました。

今後の展望としては、今回のCognitoの設定をCloudFormationで自動化してみたいと思います。