Azure Entra IDとAmplifyによるCognito SAMLサインイン
AWS Amplify、Cognitoユーザープール、Azure Entra IDを使ったSAML認証について解説します。
CognitoユーザープールはSAMLベースのIDプロバイダーをサポートしており、エンタープライズのID管理システムとシームレスに統合できます。ここでは、AWS Amplify、Cognito、Azure Entra IDを組み合わせて認証を構成します。
Azure ADはMicrosoft Entra IDに名称変更されました。詳細は公式ページを参照してください。
認証フローは、SAMLを介してCognitoとAzure Entra IDを統合することで実現されます。以下の図は公式ドキュメントからの引用で、このプロセスを可視化しています。

バックエンドの構築
Azure Entra IDの作成
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設定ページが表示されたら、メタデータURLを探してコピーします。これはCognitoの設定で使用します。

Cognitoユーザープールの作成
CloudFormationテンプレートを作成します。
- 属性マッピング(33〜35行目): 属性マッピング用のURLは、Azure Entra IDから取得したメタデータURLから確認できます。
- OAuthスコープ(51行目): Amplifyを使ったフロントエンドアプリケーションからユーザー情報を照会するには、
aws.cognito.signin.user.adminスコープが必要です。
AWSTemplateFormatVersion: 2010-09-09Description: Cognito user pool federated with Azure 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 Azure Entra ID
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>'Entra IDのSAML設定を更新する
Cognito管理コンソールでユーザープールIDとCognitoドメインプレフィックスを確認します。

Azure 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 and Claimsを編集します。

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


統合をテストするために、Azure 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-amplifyDot Envファイルの作成
プロジェクトルートに以下の内容で.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/を開きます。サインインページにリダイレクトされます。

サインイン後、アプリ内にユーザー属性が表示されます。

Cognito管理コンソールで、ユーザーが作成されていることを確認します。

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

クリーンアップ
作業が終わったらスタックを削除します。
aws cloudformation delete-stack \ --stack-name amplify-with-cognito-and-entra-idAzure上のエンタープライズアプリケーションと作成したユーザーは手動で削除してください。
まとめ
CognitoユーザープールをSAML経由でAzure Entra IDとフェデレーションし、Amplifyを使ってNext.jsアプリに組み込んだところ、ユーザーがEntra ID経由でサインインし、その属性がアプリに表示されるようになりました。この統合における摩擦の大部分は、SAMLハンドシェイクの両側を正確に一致させる点にあります。Entra ID側に登録するEntity IDとReply URLは、ユーザープールIDとドメインプレフィックスに至るまでCognitoが期待する値と一致していなければならず、CloudFormationテンプレート内の属性マッピングも、Entra IDが実際に送信するクレームURIと整合している必要があります。記事の最後に示したエラー画面(エンタープライズアプリケーションにユーザーが割り当てられていない)は、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にデプロイする
Lambda Web Adapterを使うと、FastAPIで書いたAPIバックエンドをコンテナのまま単一のLambda関数にデプロイできます。
API Gateway WebSocket:モック統合の実装
バックエンドのLambdaを一切使わず、モック統合のみでAPI Gateway WebSocket APIを構築し、あらかじめ用意されたレスポンスを返します。
CloudFront署名付きURL経由でS3にアップロードする
CloudFrontの署名付きURLを使えば、独自ドメイン経由でS3にアップロードできます。S3の直接の署名付きURLが使えない場合に有用です。
