はじめに
CognitoとOktaをSAML連携する方法を、ハンズオン形式で紹介しています。
もともとは2023年に書いた記事ですが、2025年7月時点での最新の画面や仕様に合わせてリライトしました。
完成イメージ
次の2つを実装していきます。
- ログインすると https://jwt.io/ja に飛ぶ。Cognitoのアクセストークンを確認する
- ローカルで立ち上げたReactアプリにログインする
次のようなイメージです。
- ログインすると jwt.io に飛ぶ。Cognitoのアクセストークンを確認する
一旦、CognitoのOkta連携を確認するための実装です。
↓
- ローカルで立ち上げたReactアプリにログインする
「Sign in」すると自分のアクセストークンが画面に表示されるだけのアプリです。
↓
↓
動画版ハンズオン
動画版ハンズオンも作成しています!
「とりあえず作業を眺めたい」「動画で確認しながら手を動かしたい」と言う方は是非見てみて下さい![]()
前提
- Node.js(私の環境ではv22.14.0)
- AWSのアカウント
- Oktaのアカウント
Oktaのアカウントが無い人は下記で登録して下さい。この記事では「BEST FOR DEVELOPERS」と書かれたプランを使っています。
手順
- Cognito・ユーザープール作成
- Okta・新しいアプリ統合を作成
- CognitoをOktaとSAML連携(アイデンティティプロバイダー追加)
- ログインできるかテスト
- ユーザー名をトークンに入れる(Lambdaトリガー)
- OAuth付与タイプを変更
- Reactにログイン機能を実装
1. Cognito・ユーザープール作成
ユーザープールを作成
Cognitoに移動して「ユーザープールを作成」します。
| 項目名 | 値 |
|---|---|
| アプリケーションタイプ | シングルページアプリケーション(SPA) |
| アプリケーションに名前を付ける | My SPA app |
| サインイン識別子のオプション | メールアドレス |
| サインアップのための必須属性 |
上記のように設定して「ユーザーディレクトリを作成する」をクリックします。
↓のページで特に何も設定しません。下部へスクロールします。
「概要に移動」します。
✅ ユーザープールの作成ができました!
ユーザープール名を変更
「概要」メニューにて「名前変更」します。
| 項目名 | 値 |
|---|---|
| ユーザープール名 | User pool with Okta |
上記のように設定します(※ユーザープール名は別に好きなものを付けて大丈夫です)。
✅「1. Cognito・ユーザープール作成」は完了です!
2. Okta・新しいアプリ統合を作成
OktaのAdmin Consoleにて「アプリケーション」→「アプリケーション」へ移動します。
アプリ統合を作成
「アプリ統合を作成」をします。
「SAML 2.0」を選択して「次へ」移動します。
アプリ名を「Cognito SAML」として「次へ」移動します。
シングルサインオンURL
ユーザーがOktaでログインした後に、OktaがCognitoに対してユーザーのログイン完了を通知する先です。
| 値 | 例 |
|---|---|
| 自分のCognitoドメイン/saml2/idpresponse | https://ap-northeast-1zpzvpl7q4.auth.ap-northeast-1.amazoncognito.com/saml2/idpresponse |
オーディエンスURI(SPエンティティID)
上記通知をCognitoが受け取った際に、ちゃんと自分宛のものだよね?を確認するためのものです。
| 値 | 例 |
|---|---|
| urn:amazon:cognito:sp:ユーザープール ID | urn:amazon:cognito:sp:ap-northeast-1_ZpzVPl7Q4 |
SAMLを構成
上記を参考に「シングルサインオンURL」と「オーディエンスURI(SPエンティティID)」を設定します。
下部にスクロールします。
| 名前 | 値 |
|---|---|
| user.email | |
| displayname | user.displayName |
「属性ステートメント」を上記のように設定します。
Oktaのユーザー情報のどの属性をCognitoに渡すかの設定です(※他にも任意の属性も渡せます)。
設定できたら「次へ」移動します。
「これは当社で作成した社内アプリです」にチェックを入れて「終了」します。
ユーザーに割り当て
ログインできるユーザーの割り当てをします。
「割り当て」タブで「ユーザーに割り当て」(※下図参考)を選択します。
ユーザーを「割り当て」ます。
「保存して戻る」をしたら「完了」します。
ユーザーの属性を変更
先ほど設定したuser.displayNameを編集します(未編集の方のみ)。
割り当てたユーザーのユーザー名(例:Jiro Yoyogi)をクリックします。
「プロファイル」タブに移動して「編集」します。
「displayName」の項目を探してご自身の名前など任意の値を入力して下さい。
IdPメタデータの取得
「サインオン」タブに移動して下部にスクロールします。
「SAML署名証明書」という項目があります。ステータスがアクティブになってるものを「IdPメタデータを表示」します。
XMLが表示されます。Oktaの設定情報のようなものです。この後でCognitoに渡します。
DL(保存)します。
✅ 以上でOktaでの設定は完了です!いよいよCognitoをOktaとSAML連携させていきます!
3. CognitoをOktaとSAML連携
AWSのマネージメントコンソールに戻ります。
アイデンティティプライバイダーを追加
「認証」→「ソーシャルプロバイダーと外部プロバイダー」→「アイデンティティプロバイダーを追加」します。
「SAML」を選択します。
「プロバイダー名」を「Okta」とします。その他はデフォルトのままで大丈夫です。
「ファイルを選択」して先ほどDLしたXMLをアップロードします。
メタデータドキュメントのエンドポイントURLを入力とは?
メタデータドキュメント(Oktaの設定情報)を渡したい場合は2つの方法があります。1つはXMLをアップロードする方法、もう1つはXMLをDLする際に表示した画面のURLを入力する方法です。この記事ではアップロードする方法で進めます。
「SAMLプロバイダーとユーザープール間で属性をマッピング」を下記のように設定します。
| ユーザープール属性 | SAML属性 |
|---|---|
| name | displayname |
Oktaから渡ってくるemail、displaynameというユーザー属性をCognitoで受け止める設定です。ここまでできたら「アイデンティティプロバイダーを追加」します。
ログイン後に飛ばすページを設定
「アプリケーションクライアント」→「My SPA app」をクリックします。
「ログインページ」タブで「編集」します。
| 項目名 | 値 |
|---|---|
| 許可されているコールバックURL | https://jwt.io/ja |
Oktaのログイン画面でログインした後に飛ばすリダイレクト先です。現時点でログインした後に飛ばすページを用意していないので、一旦、上記のURLに飛ばすように設定します。
「IDプロバイダー」にて「Okta」にチェックを入れて追加します。
「OAuth 2.0許可タイプ」は下図のように設定します。
❎ 認証コード付与
✅ 暗黙的な付与
上記のようにすると「許可されているコールバックURL」にリダイレクトする際に、アクセストークンがURLにクエリとして付与されるようになります。何が嬉しいかというと、ログイン後にjwt.ioにリダイレクトした際に、アクセストークンの中身をjwt.ioの画面上で確認できるようになります。視覚的にちゃんとCognitoとOktaが連携されているよねー、ということを確認しやすいかと思い、このようにしています。
あくまでSAML連携の確認のための一時的な設定です。後でまた元に戻します。
ここまでできたら「変更を保存」します。
✅ CognitoとOktaのSAML連携が完了しました!
4. ログインできるかテスト
右上にある「ログインページを表示」をクリックします。
まずはCognitoのログイン画面に飛びます。「Continue with Okta」のボタンを押します。
すると、Oktaのログイン画面に遷移しました。
Oktaでログインすると、「jwt.io」にリダイレクトされます。URLにアクセストークンが付与されてることと、画面に表示されてるトークンの中身を眺めてみて下さい。ご自身のメールアドレスなどがあることを確認できるかと思います。
Okta連携してCognitoに登録されたユーザーも確認しておきます。
「ユーザー管理」→「ユーザー」 します。
すると、okta_と接頭辞のあるユーザーを確認できます。
ユーザーを選択すると、nameの項目でOktaユーザーのdisplayNameが渡って来ている事も確認できます。
✅ これでCognitoとOktaのSAML連携の基本的な部分は完了です!
5. ユーザー名をトークンに入れる(Lambdaトリガー)
で、恐らく気になった人もいるかと思いますが、jwt.ioのページで表示されてるアクセストークンの中に「name」の項目がありません。ただ、場合によっては、nameをトークンに埋めたい要望もあるかと思います。どのようにしたら良いか?
Cognitoがアクセストークンを払い出す際に、Lambdaを挟む事ができます。このLambdaでアクセストークンに埋める値を調整することができます。
Lambdaトリガーを追加
「認証」→「拡張機能」にて「Lambdaトリガーを追加」します。
| 項目名 | 値 |
|---|---|
| トリガータイプ | 認証 |
| 認証 | トークン生成前トリガー |
| トリガーイベントバージョン | 基本機能 + ユーザー ID とマシン ID のアクセストークンのカスタマイズ - 推奨 |
「Lambda関数の作成」をします。
Lambda関数を作成
Lambdaの画面に遷移したら「関数を作成」します。
| 項目名 | 値 |
|---|---|
| 関数名 | cognito-token-customizer |
| ランタイム | Node.js 22.x |
| アーキテクチャ | x86_64 |
| 実行ロール | 基本的なLambdaアクセス権限で新しいロールを作成 |
上記のように設定していきます。
「関数の作成」をします。
index.mjsの中身を次のコードで置き換えます。
export const handler = async (event) => {
// userAttributes から必要な属性をトークンに追加
const attrs = event.request.userAttributes;
event.response = {
claimsAndScopeOverrideDetails: {
idTokenGeneration: {
claimsToAddOrOverride: {
name: attrs.name
},
}
}
};
return event;
};
置き換えられたら「Deploy」します。下図のように「正常に更新されました」という文言が出たら完了です。
Lambda関数を選択
Cognitoに戻り、作成した「cognito-token-customizer」を選択します。
「Lambdaトリガーを追加」します。
✅ これでアクセストークンにnameの項目が入るようになりました。
再び「ログインページを表示」からログインを試します。
すると、nameの項目が現れるようになりました!
6. OAuth付与タイプを変更
ここまでで、SAML連携の確認ができました。OAuth 2.0許可タイプを「暗黙的な付与」→「認証コード付与」へと戻していきます。
URLにアクセストークンが付いてる状態は望ましくない
暗黙的な付与→認証コード付与
「アプリケーション」→「アプリケーションクライアント」→「My SPA app」→「ログインページ」タブにて「編集」します。
「OAuth 2.0許可タイプ」を次のように変更します。
✅ 認証コード付与
❎ 暗黙的な付与
「変更を保存」します。
再度「ログインページを表示」からログインします。
トークンが付いていないことを確認できます。
codeとは?
簡単に言うとトークンの引換券です。キーワードで言うとPKCE認証で使うものです。アクセストークンを取得したい場合は、このcodeをCognitoに送って引き換えて貰います。
この後、Reactで簡単なログイン・ログアウトのアプリを作ります。その中で引き換えてる部分について確認します。
✅ これでよりセキュアな状態になりました。
7. Reactにログイン機能を実装
Viteプロジェクト作成
作業フォルダーに移動して下記コマンドを実行します。
npm create vite@latest
以下のように入力・選択します。
- Project name
- cognito-okta-app
- Select a framework
- React
- Select a variant
- TypeScript
続いてプロジェクトフォルダに移動して下記コマンドを実行します。
npm install
下記コマンドを実行して「http://localhost:5173/」でアプリが立ち上がれば成功です。
npm run dev
次のような画面が現れたら問題無くReactのプロジェクトが作れていますので、先に進めていきます。
2025年7月現在のデフォルト画面です。Vite側で変更される可能性があります。
ライブラリをインストール
Cognitoでログインするためのライブラリをインストールします。
npm install oidc-client-ts react-oidc-context --save
コードの実装
変更するのは下記コードです。
- main.tsx
- App.tsx
main.tsx
下記2つをご自身のものに書き換えて下さい。
- ユーザープールID
- アプリケーションクライアントID
// main.tsx
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { AuthProvider } from "react-oidc-context";
const cognitoAuthConfig = {
// e.g. https://cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_c7NPd74MH
authority: "https://cognito-idp.ap-northeast-1.amazonaws.com/{ユーザープール ID}",
// e.g. 6ehuq2e03ftb5kr5dgl2ke5h0o
client_id: "{アプリケーションクライアントID}",
redirect_uri: "http://localhost:5173/",
response_type: "code",
scope: "email openid phone",
};
const root = ReactDOM.createRoot(document.getElementById("root")!);
// wrap the application with AuthProvider
root.render(
<React.StrictMode>
<AuthProvider {...cognitoAuthConfig}>
<App />
</AuthProvider>
</React.StrictMode>
);
App.tsx
下記2つをご自身のものに書き換えて下さい。
- アプリケーションクライアントID
- Cognito ドメイン
// App.tsx
import { useAuth } from "react-oidc-context";
function App() {
const auth = useAuth();
const signOutRedirect = () => {
// e.g. 6ehuq2e03ftb5kr5dgl2ke5h0o
const clientId = "{アプリケーションクライアントID}";
const logoutUri = "http://localhost:5173/";
// e.g. https://ap-northeast-1c7npd74mh.auth.ap-northeast-1.amazoncognito.com
const cognitoDomain = "{Cognito ドメイン}";
window.location.href = `${cognitoDomain}/logout?client_id=${clientId}&logout_uri=${encodeURIComponent(logoutUri)}`;
};
if (auth.isLoading) {
return <div>Loading...</div>;
}
if (auth.error) {
return <div>Encountering error... {auth.error.message}</div>;
}
if (auth.isAuthenticated) {
return (
<div>
<pre> Hello: {auth.user?.profile.email} </pre>
<pre> ID Token: {auth.user?.id_token} </pre>
<pre> Access Token: {auth.user?.access_token} </pre>
<pre> Refresh Token: {auth.user?.refresh_token} </pre>
<button onClick={() => auth.removeUser()}>Sign out</button>
</div>
);
}
return (
<div>
<button onClick={() => auth.signinRedirect()}>Sign in</button>
<button onClick={() => signOutRedirect()}>Sign out</button>
</div>
);
}
export default App;
変更は以上です。
画面確認
下記コマンドで再度アプリを立ち上げます。
npm run dev
すると下図のようにサインインとサインアウトのボタンだけのページが表示されます。
「Sign in」してみると、今の時点では下記のようにエラー画面になります。
これをちゃんと動くように変更していきます。
許可されているコールバックURLを変更
AWSのマネコンに戻ります。
「アプリケーション」→「アプリケーションクライアント」→「My SPA app」→「ログインページ」にて「編集」します。
許可されているコールバックURLを次のように変更して下さい。
http://localhost:5173/
また、許可されているサインアウトURLにも同じURLを入力します。
「変更を保存」します。
✅ これでログイン後に、ローカルホストで立ち上げてるページにリダイレクトされるようになりました。再度ログインを試していきます。
今度はCognitoのログイン画面に飛びました!
「Continue with Okta」でログインすると下記のような表示がされると思います。
「Quick Setup ガイド」の実装は以上になります。
いくつかこの状態だと気になる部分があります(例えばリロードするとエラー画面になるとか)。この辺りを修正していく実装は、また別の記事で紹介できたらと考えています。
認証コード→アクセストークン交換
やはり、このページのURLにもアクセストークではなくcodeが付与されています。このcodeをどうアクセストークンに交換してるかと言う部分を確認しておきます。
と言っても実装はライブラリ任せです。
ここでは、ちゃんと交換されてるよね?という事だけ確認します。
ブラウザの開発者ツールの「Network」タブを開きます。
文字小さいですが「token」と言う項目があるのを確認できますでしょうか?
クリックして「Payload」を開くと「https://ap-northeast-1_Lmyjqhqf0.auth.ap-northeast-1.amazoncognito.com/oauth2/token(※)」に対してcodeを送ってることを確認できます。
※ドメインは適宜自分のものと読み替えて下さい。
更にその「Response」を確認するとトークンが返って来てる事を確認できます。
この記事でPKCE認証についてこれ以上は触れませんが、一旦、トークンを取得するには認可コードと引き換えないといけないんだな、と覚えておいて貰えたら良いかと思います。
✅ この記事での実装は以上になります!!お疲れ様でしたー!!
終わりに
冒頭でも触れましたが、この記事は、2年前に執筆した内容をもとに、現在(2025年7月)のAWSの画面や仕様に合わせてリライトしたものです。当時からAWSの画面がだいぶ変わってしまっていて「これはもう使えないな…」と思い、最新の内容で書き直しました。
ちなみに、この記事と同じ内容をハンズオン形式で解説した動画をYouTubeにもアップしています。実際の操作画面を見ながら進めたい方は、ぜひチェックしてみてください!
ここまで読んでいただき、ありがとうございましたー!














































































