Microsoft Entra ID と Amplify による Cognito SAML サインイン
Amazon Cognito ユーザープールと Microsoft Entra ID の間に SAML サインインを設定し、Amplify を使った Next.js アプリから利用します。
Amazon Cognito ユーザープールは SAML ID プロバイダー をサポートしています。この例では、ユーザープールを Microsoft Entra ID とフェデレーションし、AWS Amplify を使って Cognito のホストされた UI によるサインインを Next.js アプリへ追加します。
Microsoft は 2023 年に Azure Active Directory(Azure AD)を Microsoft Entra ID へ名称変更しました。詳細は公式ページを参照してください。
以下の公式ドキュメントの図は、Cognito と外部 ID プロバイダーの間の SAML フェデレーションフローを示しています。

バックエンドの構築
Microsoft Entra エンタープライズアプリケーションの作成
Azure ポータルを開き、Microsoft Entra ID に移動します。

メニューから Add > Enterprise application を選択します。

Create your own application を選び、my-cognito-app のような名前を入力します。Integrate any other application you don't find in the gallery (Non-gallery) を選択します。


Set up single sign on セクションで、方式として SAML を選択します。


SAML 設定ページで App Federation Metadata URL をコピーします。Cognito の設定でこの URL を使用します。

Cognito ユーザープールの作成
CloudFormation テンプレートを作成します。
- 属性マッピング(33〜35 行目):Cognito の属性を、Microsoft Entra ID の Attributes & Claims で設定した SAML クレーム名へマッピングします。リンク先のプロトコルリファレンスに標準のクレーム URI が記載されています。
- OAuth スコープ(51 行目):
aws.cognito.signin.user.adminスコープにより、Amplify アプリケーションからアクセストークンを使ってユーザー属性を取得できます。
AWSTemplateFormatVersion: 2010-09-09Description: Cognito user pool federated with Microsoft Entra ID
Parameters: Domain: Type: String Description: Cognito user pool domain CallbackURLs: Type: CommaDelimitedList Default: 'http://localhost:3000/' LogoutURLs: Type: CommaDelimitedList Default: 'http://localhost:3000/' MetadataURL: Type: String Description: SAML metadata URL of your Microsoft Entra ID application
Resources: CognitoUserPool: Type: AWS::Cognito::UserPool Properties: UserPoolName: cognito-federated-with-azure-entra-id
CognitoUserPoolDomain: Type: AWS::Cognito::UserPoolDomain Properties: Domain: !Ref Domain UserPoolId: !Ref CognitoUserPool
CognitoUserPoolIdentityProvider: Type: AWS::Cognito::UserPoolIdentityProvider Properties: AttributeMapping: email: 'http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress' name: 'http://schemas.microsoft.com/identity/claims/displayname' ProviderDetails: IDPSignout: true MetadataURL: !Ref MetadataURL ProviderName: azure-entra-id ProviderType: SAML UserPoolId: !Ref CognitoUserPool
CognitoUserPoolClient: Type: AWS::Cognito::UserPoolClient Properties: AllowedOAuthFlows: - code AllowedOAuthScopes: - email - openid - aws.cognito.signin.user.admin AllowedOAuthFlowsUserPoolClient: true CallbackURLs: !Ref CallbackURLs LogoutURLs: !Ref LogoutURLs ClientName: public client SupportedIdentityProviders: - COGNITO - !Ref CognitoUserPoolIdentityProvider UserPoolId: !Ref CognitoUserPool先ほどコピーしたメタデータ URL で <SAML_METADATA_URL> を置き換え、スタックをデプロイします。
aws cloudformation deploy \ --template-file cognito.yaml \ --stack-name amplify-with-cognito-and-entra-id \ --parameter-overrides Domain=$(uuidgen | tr "[:upper:]" "[:lower:]") MetadataURL='<SAML_METADATA_URL>'Microsoft Entra ID の SAML 設定を更新する
Cognito コンソールでユーザープール ID と Cognito ドメインプレフィックス を確認します。

Microsoft Entra ID でエンタープライズアプリケーションの SAML 設定を開きます。

SAML 設定に以下の値を指定します。詳細は公式ドキュメントを参照してください。
- Entity ID:
urn:amazon:cognito:sp:<your user pool ID> - Reply URL:
https://<yourDomainPrefix>.auth.<region>.amazoncognito.com/saml2/idpresponse

Attributes & Claims を、Cognito ID プロバイダーの属性マッピングに合わせて編集します。

Add a group claim をクリックし、Groups assigned to the application を選択します。


統合のテスト用に Microsoft Entra ID ユーザーを作成します。
Azure ポータルで New user をクリックします。

必要な項目(ユーザー名や氏名など)を入力します。

ユーザーのメールアドレスを指定します。

Assignments タブはここではスキップします。

設定を確認してユーザーを作成します。

アプリケーションへのユーザー割り当て
作成したユーザーをエンタープライズアプリケーションへ割り当てます。
my-cognito-app エンタープライズアプリケーションを選択します。

Assign users and groups をクリックします。

Add user/group を選択し、作成したユーザーを選びます。


フロントエンドの構築
アプリケーションの作成
この例では Next.js を使用します。以下のコマンドとオプションでアプリを生成します。
npx create-next-app@latest✔ What is your project named? … amplify-with-cognito-and-entra-id✔ Would you like to use TypeScript? … Yes✔ Would you like to use ESLint? … Yes✔ Would you like to use Tailwind CSS? … Yes✔ Would you like to use `src/` directory? … Yes✔ Would you like to use App Router? (recommended) … Yes✔ Would you like to customize the default import alias (@/*)? … Yes✔ What import alias would you like configured? … @/*プロジェクトディレクトリへ移動し、AWS Amplify をインストールします。
cd amplify-with-cognito-and-entra-idnpm i aws-amplify環境変数ファイルの作成
プロジェクトルートに以下の .env.local を作成し、プレースホルダーを実際の値に置き換えます。
NEXT_PUBLIC_USER_POOL_ID=<USER_POOL_ID>NEXT_PUBLIC_USER_POOL_CLIENT_ID=<USER_POOL_CLIENT_ID>NEXT_PUBLIC_USER_POOL_ID_PROVIDER=azure-entra-idNEXT_PUBLIC_OAUTH_DOMAIN=<DOMAIN_PREFIX>.auth.ap-northeast-1.amazoncognito.comメインページの更新
認証を設定してユーザー属性を表示するため、src/app/page.tsx を以下の内容に更新します。
'use client'
import { useEffect, useState } from 'react';import { Amplify } from 'aws-amplify';import { FetchUserAttributesOutput, fetchUserAttributes, getCurrentUser, signInWithRedirect, signOut } from 'aws-amplify/auth';
Amplify.configure({ Auth: { Cognito: { userPoolId: process.env.NEXT_PUBLIC_USER_POOL_ID as string, userPoolClientId: process.env.NEXT_PUBLIC_USER_POOL_CLIENT_ID as string, loginWith: { oauth: { domain: process.env.NEXT_PUBLIC_OAUTH_DOMAIN as string, scopes: [ 'email', 'openid', 'aws.cognito.signin.user.admin', ], redirectSignIn: ['http://localhost:3000/'], redirectSignOut: ['http://localhost:3000/'], responseType: 'code', }, }, }, },});
export default function Home() { const [attributes, setAttributes] = useState<FetchUserAttributesOutput>();
useEffect(() => { (async () => { try { await getCurrentUser(); const attributes = await fetchUserAttributes(); setAttributes(attributes); } catch (error) { await signInWithRedirect({ provider: { custom: process.env.NEXT_PUBLIC_USER_POOL_ID_PROVIDER as string } }); } })(); }, []);
return ( <div className='flex flex-col gap-2 max-w-sm mx-auto my-4'> <div className='flex gap-2'> <div>Sub:</div> <div>{attributes?.sub}</div> </div>
<div className='flex gap-2'> <div>Name:</div> <div>{attributes?.name}</div> </div>
<div className='flex gap-2'> <div>Email:</div> <div>{attributes?.email}</div> </div>
<button type="button" className="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 me-2 mb-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800" onClick={() => signOut()} > Sign out </button> </div> );}テスト
開発サーバーを起動します。
npm run devブラウザで http://localhost:3000/ を開くと、サインインページへリダイレクトされます。

Microsoft Entra ID でサインインすると、アプリにユーザー属性が表示されます。

Cognito コンソールで、フェデレーションユーザーが作成されていることを確認します。

Microsoft Entra ID のエンタープライズアプリケーションにユーザーが割り当てられていない場合、サインイン時に以下のエラーが発生します。

クリーンアップ
作業が終わったらスタックを削除します。
aws cloudformation delete-stack \ --stack-name amplify-with-cognito-and-entra-idMicrosoft Entra ID のエンタープライズアプリケーションとテストユーザーは手動で削除してください。
まとめ
Cognito ユーザープールと Microsoft Entra ID を SAML でフェデレーションすると、ユーザーは Cognito のホストされた UI を介して Next.js アプリへサインインし、Amplify からマッピング済みの属性を取得できます。
Microsoft Entra ID に登録する Entity ID と Reply URL は、Cognito のユーザープール ID とドメインプレフィックスに正確に一致させます。また、Cognito の属性マッピングには、エンタープライズアプリケーションが送信するクレーム URI を指定します。
ユーザーを作成しただけでは、エンタープライズアプリケーションへのアクセス権は付与されません。有効なユーザーがサインインできない場合は、Microsoft Entra ID のアプリケーション割り当てを最初に確認してください。
Related posts
Cognito User Pools と OIDC で Slack サインインを実装する
Cognito user pool を OIDC 経由で Slack と連携させ、"Sign in with Slack" を Amplify で Next.js アプリケーションに組み込みます。

AWS Amplify と Eclipse Mosquitto を連携した MQTT メッセージング
AWS Amplify の PubSub モジュールを AWS IoT Core に接続する前に、ローカルの Eclipse Mosquitto ブローカーでテストする方法を紹介します。
Lambda Web Adapter で FastAPI を AWS Lambda にデプロイする
FastAPI で書いた API バックエンドをコンテナ化し、Lambda Web Adapter と AWS CDK を使って単一の Lambda 関数へデプロイします。
API Gateway WebSocket:モック統合の実装
バックエンドの Lambda を使わず、モック統合のみで API Gateway WebSocket API を構築し、あらかじめ用意したレスポンスを返します。
CloudFront 署名付き URL 経由で S3 にアップロードする
CloudFront の署名付き URL を使い、独自ドメイン経由で S3 にアップロードする方法を紹介します。S3 の署名付き URL を直接使えない場合に有用です。
