Azure Entra IDとAmplifyによるCognito SAMLサインイン

Azure Entra IDとAmplifyによるCognito SAMLサインイン

AWS Amplify、Cognitoユーザープール、Azure Entra IDを使ったSAML認証について解説します。

Takahiro Iwasa
8 min read

CognitoユーザープールはSAMLベースのIDプロバイダーをサポートしており、エンタープライズのID管理システムとシームレスに統合できます。ここでは、AWS Amplify、Cognito、Azure Entra IDを組み合わせて認証を構成します。

ℹ️ Note

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テンプレートを作成します。

cognito.yaml
AWSTemplateFormatVersion: 2010-09-09
Description: 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>を置き換え、スタックをデプロイします。

Terminal window
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管理コンソールでユーザープールIDCognitoドメインプレフィックスを確認します。

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を使用します。以下のコマンドとオプションでアプリを生成します。

Terminal window
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をインストールします。

Terminal window
cd amplify-with-cognito-and-entra-id
npm i aws-amplify

Dot Envファイルの作成

プロジェクトルートに以下の内容で.env.localファイルを作成します。プレースホルダーは実際の値に置き換えてください。

.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-id
NEXT_PUBLIC_OAUTH_DOMAIN=<DOMAIN_PREFIX>.auth.ap-northeast-1.amazoncognito.com

メインページの更新

認証を設定し、ユーザー属性を表示するために、src/app/page.tsxファイルを以下の内容に更新します。

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>
);
}

テスト

開発サーバーを起動します。

Terminal window
npm run dev

ブラウザでhttp://localhost:3000/を開きます。サインインページにリダイレクトされます。

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

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

ℹ️ Note

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

クリーンアップ

作業が終わったらスタックを削除します。

Terminal window
aws cloudformation delete-stack \
--stack-name amplify-with-cognito-and-entra-id

Azure上のエンタープライズアプリケーションと作成したユーザーは手動で削除してください。

まとめ

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のアプリケーション割り当てが、ユーザー作成とは別の、見落としやすいステップであることを思い出させてくれます。本来アクセスできるはずのユーザーでサインインに失敗した場合は、まずこの割り当てを確認する価値があります。

About the author

Takahiro Iwasa

Takahiro Iwasa

Software Developer

This blog shares technical notes from hands-on projects—architecture, implementation, and AWS service integrations.