Authenticating with AWS Amplify, Amazon Cognito, and Azure Entra ID (Azure AD)

Authenticating with AWS Amplify, Amazon Cognito, and Azure Entra ID (Azure AD)

Takahiro Iwasa
Takahiro Iwasa
7 min read
Cognito Entra ID Amplify

Introduction

Amazon Cognito user pools provide support for SAML-based identity providers, enabling seamless integration with enterprise identity systems. In this guide, we’ll walk through the process of setting up authentication using AWS Amplify, Amazon Cognito, and Azure Entra ID.

Overview

The authentication workflow involves integrating Cognito with Azure Entra ID via SAML. The following diagram, from official documentation, visualizes the process.

Cloud Resources

Creating Azure Entra ID

To integrate Azure Entra ID with Amazon Cognito, follow these steps:

1. Navigate to Microsoft Entra ID

Open the Azure portal and navigate to the Microsoft Entra ID section.

2. Add an Enterprise Application

Select Add > Enterprise application from the menu.

3. Create a Custom Application

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).

4. Configure Single Sign-On (SSO)

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

Copy the Metadata URL:

Once the SAML setup page appears, locate and copy the metadata URL. This will be used in the Cognito configuration.

Creating Amazon Cognito User Pool

To integrate Amazon Cognito with Azure Entra ID, you need to create a Cognito user pool. This can be accomplished by defining a CloudFormation template (cognito.yaml) with the following content:

CloudFormation Template

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

Keynotes

  • Attribute Mapping (Lines 33-35): The URLs for attribute mapping can be found in the metadata URL retrieved from Azure Entra ID.
  • OAuth Scope (Line 51): The scope aws.cognito.signin.user.admin is required for querying user information from frontend applications using Amplify.

For more details on SAML 2.0 requests and responses supported by Entra ID, refer to the official documentation. Additionally, learn more about Cognito resource servers and scopes in the AWS documentation.

Deploying the CloudFormation Stack

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

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

This command deploys the Cognito user pool configured for SAML-based authentication with Azure Entra ID.

Once the deployment is successful, you can proceed with configuring Entra ID’s SAML settings and assigning users to the application.

Updating Entra ID SAML Configuration

To enable Azure Entra ID to work with Amazon Cognito, update the SAML configuration as follows:

1. Retrieve the Cognito Details

Check the User pool ID and the Cognito domain prefix in the Amazon Cognito management console.

2. Edit the SAML Configuration

Open the SAML settings in Azure Entra ID and begin editing.

3. Add Entity ID and Reply URL

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

KeyValue
Entity IDurn:amazon:cognito:sp:<your user pool ID>
Reply URLhttps://<yourDomainPrefix>.auth.<region>.amazoncognito.com/saml2/idpresponse

4. Configure Attributes and Claims

Edit the attributes and claims to match your application requirements.

5. Add a Group Claim

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

Creating a User

To test the integration, create a new user in Azure Entra ID:

1. Open the Users Section

Click New user in the Azure portal.

2. Enter User Details

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

3. Add Email Address

Specify an email address for the user.

4. Skip Assignments

Skip the Assignments tab for now.

5. Complete User Creation

Finalize the process to create the user.

Assigning a User to the Application

Once the user is created, assign them to the application:

1. Navigate to the Application

Select the my-cognito-app enterprise application.

2. Assign Users and Groups

Click Assign users and groups.

3. Add User/Group

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

React App

Creating the Application

To create the frontend app, this post uses Next.js. Generate the app with the following command and options:

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 the working directory to the project root and install AWS Amplify with:

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

Creating an Environment File

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

  • <USER_POOL_ID>
  • <USER_POOL_CLIENT_ID>
  • <DOMAIN_PREFIX>
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:

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

Start the development server with

npm run dev

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

After signing in, you can see the user attributes displayed in the app.

Verify that the user is created in the Cognito management console.

Cleaning Up

AWS Resources

Remove the provisioned AWS resources using the following command:

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

Azure Resources

Manually delete the enterprise application and any created users in Azure.

Conclusion

Federating Amazon Cognito with Azure Entra ID is an essential step for enterprises that rely on centralized identity management, particularly those using Active Directory. This integration allows for seamless, secure authentication workflows while leveraging existing organizational user directories.

In this guide, we’ve provided a comprehensive, step-by-step walkthrough of the integration process, covering both backend setup with AWS and Azure and frontend implementation using AWS Amplify.

If you’re interested in implementing Sign-in with Slack using Cognito, check out this related post:

I hope you find this guide helpful.

Happy Coding! 🚀

Takahiro Iwasa

Takahiro Iwasa

Software Developer at KAKEHASHI Inc.
Involved in the requirements definition, design, and development of cloud-native applications using AWS. Now, building a new prescription data collection platform at KAKEHASHI Inc. Japan AWS Top Engineers 2020-2023.