Cognito SAML Sign-In with Microsoft Entra ID and Amplify

Cognito SAML Sign-In with Microsoft Entra ID and Amplify

Configure SAML sign-in between an Amazon Cognito user pool and Microsoft Entra ID, then use it from a Next.js application with Amplify.

Takahiro Iwasa
6 min read

Amazon Cognito user pools support SAML identity providers. This example federates a user pool with Microsoft Entra ID and adds the resulting hosted UI sign-in flow to a Next.js application with AWS Amplify.

ℹ️ Note

Microsoft renamed Azure Active Directory (Azure AD) to Microsoft Entra ID in 2023. See the official page for details.

The following diagram from the official documentation shows the SAML federation flow between Cognito and an external identity provider.

Configuring the Backend

Creating the Microsoft Entra Enterprise Application

Open the Azure portal and go to Microsoft Entra ID.

Select Add > Enterprise application from the menu.

Choose Create your own application and enter a name such as my-cognito-app. Select the option Integrate any other application you don't find in the gallery (Non-gallery).

Go to the Set up single sign on section and choose SAML as the method.

On the SAML setup page, copy the App Federation Metadata URL for the Cognito configuration.

Creating the Cognito User Pool

Create a CloudFormation template:

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

Replace <SAML_METADATA_URL> with the metadata URL copied earlier and deploy the stack:

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

Updating the Microsoft Entra ID SAML Configuration

In the Cognito console, find the user pool ID and Cognito domain prefix.

Open the enterprise application’s SAML settings in Microsoft Entra ID.

Use the following values for the SAML configuration. Refer to the official documentation for more details.

  • Entity ID: urn:amazon:cognito:sp:<your user pool ID>
  • Reply URL: https://<yourDomainPrefix>.auth.<region>.amazoncognito.com/saml2/idpresponse

Edit Attributes & Claims to match the attribute mapping in the Cognito identity provider.

Click Add a group claim and select Groups assigned to the application.

Create a Microsoft Entra ID user to test the integration.

Click New user in the Azure portal.

Fill in the required fields (e.g., username and name).

Specify an email address for the user.

Skip the Assignments tab for now.

Review the settings and create the user.

Assigning the User to the Application

After creating the user, assign the account to the enterprise application.

Select the my-cognito-app enterprise application.

Click Assign users and groups.

Select Add user/group and pick the user you created.

Building the Frontend

Creating the Application

This example uses Next.js. Generate the app with the following command and options:

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? @/*

Change to the project directory and install AWS Amplify:

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

Creating the Environment File

Create a .env.local file in the root of your project with the following content. Replace the placeholders with your actual values:

.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

Updating the Main Page

Update the src/app/page.tsx file with the following content to configure authentication and display user attributes:

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

Testing

Start the development server with:

Terminal window
npm run dev

Open http://localhost:3000/ in your browser. You will be redirected to a sign-in page.

After signing in through Microsoft Entra ID, the application displays the user’s attributes.

Verify that the federated user was created in the Cognito console.

ℹ️ Note

If the user is not assigned to the enterprise application in Microsoft Entra ID, sign-in returns the following error:

Cleaning Up

Delete the stack once finished:

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

Manually delete the enterprise application and any test users in Microsoft Entra ID.

Conclusion

SAML federation between a Cognito user pool and Microsoft Entra ID allows a user to sign in to the Next.js application through the Cognito hosted UI and access mapped attributes with Amplify.

The Entity ID and Reply URL registered in Microsoft Entra ID must exactly match the Cognito user pool ID and domain prefix. The Cognito attribute mapping must also use the claim URIs sent by the enterprise application.

Creating a user does not grant access to the enterprise application. If an otherwise valid user cannot sign in, check the Microsoft Entra application assignment first.

About the author

Takahiro Iwasa

Takahiro Iwasa

Software Developer

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