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

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

Amazon Cognito ユーザープールと Microsoft Entra ID の間に SAML サインインを設定し、Amplify を使った Next.js アプリから利用します。

Takahiro Iwasa
8 min read

Amazon Cognito ユーザープールは SAML ID プロバイダー をサポートしています。この例では、ユーザープールを Microsoft Entra ID とフェデレーションし、AWS Amplify を使って Cognito のホストされた UI によるサインインを Next.js アプリへ追加します。

ℹ️ Note

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

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

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>'

Microsoft Entra ID の SAML 設定を更新する

Cognito コンソールでユーザープール IDCognito ドメインプレフィックス を確認します。

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

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

環境変数ファイルの作成

プロジェクトルートに以下の .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/ を開くと、サインインページへリダイレクトされます。

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

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

ℹ️ Note

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

クリーンアップ

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

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

Microsoft 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 のアプリケーション割り当てを最初に確認してください。

About the author

Takahiro Iwasa

Takahiro Iwasa

Software Developer

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