Single Sign On (SSO) with AWS Cognito’s Hosted UI

SRC Innovations
SRC Innovations
Published in
9 min readApr 3, 2024

Single sign-on (SSO) is a centralised authentication process that allows a user to access multiple applications or services with one set of login credentials (such as username and password).

AWS Cognito User Pools is one such service that facilitates your user authentication, authorisation and user management for web and/or mobile applications that can integrate with Federated Identities to support Single Sign-On capabilities.

If you are trying to get started with AWS Cognito, then keep on reading!

It explains how to enable SSO in AWS Console with AWS Cognito’s Hosted UI with SAML Identity Provider.

Wonder what the default AWS Cognito Hosted UI could look like?

Sign-in flow:

The diagram below shows a standard login flow using AWS Cognito Hosted UI which has been configured with a SAML Identity Provider.

Too Long Didn’t Read (TLDR) Version The TLDR version:

  1. Have an Identity Provider (IdP) SAML2 file for SSO. Examples of an IdP are Azure, Google, Facebook and Apple.
  2. Through AWS Console, navigate to your AWS Cognito Userpool and add an Identity Provider via Sign-in experience tab under the heading Federated identity provider sign-in.
  3. In App Integration tab, under the Domain Panel, you either create a Cognito domain or a custom domain.
  4. Still in App Integration tab, under the App clients and analytics Panel, select your App client. Here you will update the following Hosted UI configuration and Host UI customisation (optional).
  5. Once these are configured for your AWS Cognito Userpool, configure your Identity Provider and prove them with an assertion consumer endpoint.
  • e.g.: https://<Your user pool domain>/saml2/idpresponse
  • With an Amazon Cognito domain: https://<YourDomainPrefix>.auth.<region>.amazoncognito.com/saml2/idpresponse
  • With a custom domain: https://<Your custom domain>/saml2/idpresponse
  • For some SAML identity provides, you also need to provide the service provider (SP) urn / Audience URI / SP Entity ID. e.g., urn:amazon:cognito:sp:<yourUserPoolID>

6. Once the above are done, you can access the hosted UI via the url: https://<cognito-or-custom-domain>/login?response_type=<response-type>&client_id=<userpool-app-client-id>&redirect_uri=<redirect_uri>

  • response_type could either be code or token

7. Your application will have to be modified to handle the trigger logic of the Hosted UI URL and the redirect URL behaviour to use the tokens provided by AWS Cognito Hosted UI flow.

The “Ok, I need a bit more info & pictures” version:

Firstly, have an Identity Provider (IdP) SAML2 file for SSO.

  • Examples of an IdPs are Azure, Google and Facebook
  • This could be a metadata document (typically an XML file) or a metadata document endpoint URL

Then, through AWS Console, navigate to your AWS Cognito Userpool and add an Identity Provider via Sign-in experience tab under the heading Federated identity provider sign-in.

When creating an identity provider we have to take into consideration what we want to display as the Identity Provider Name and how the hosted UI will dynamically select the appropriate identity provider (if there are more than one identity providers).

To allow the Hosted UI logic to dynamically select the appropriate identity provider when inputing a corporate email, we need to provide a Provider name as the corporate domain e.g., corporation.com. Identifiers needs to also be configured with the corporate domain as this will help Cognito determine which identity provider to use when Hosted UI asks for a corporate email.
For more information about this, have a further read HERE.

Add sign-out flow should also be configured.

One last thing that needs to be configured properly before creating the provider is the Map attributes between SAML provider and your user pool. Will need this mapping to provide AWS Cognito the appropriate user pool attributes to successfully authenticate.

Once the identity provider has been created, in App Integration tab, under the Domain Panel, you either create a Cognito domain or a custom domain.

Things to consider when deciding to use Cognito domain or a custom domain.

  1. Branding and User Experience: Custom domains allow you to maintain brand consistency throughout the authentication process. Instead of displaying AWS Cognito URLs to users, you can use your own domain, which enhances trust and provides a seamless user experience.
  2. Security and Trust: Utilising a custom domain can increase trust among users. When users see a familiar domain during the authentication process, they are more likely to trust the application.
  3. Ease of Use: Setting up a custom domain in AWS Cognito is straightforward and well-documented.

Still in App Integration tab, under the App clients and analytics Panel, select your App client. Here you will update the following Hosted UI configuration and Host UI customisation.

In the Hosted UI configuration shown above, you will have to update Allowed callback URLs, Allowed sign-out URLs and add the newly created identity provider in the Identity Providers section.

Hosted UI customisation allows you to modify the css of the hosted UI. More information HERE.

Once these are configured for your AWS Cognito Userpool, configure your SAML Identity Provider and prove them with an assertion consumer endpoint. More information can be found HERE. Below shows the possible endpoints to configure at your SAML Identity Provider.

https://<Your user pool domain>/saml2/idpresponse

With an Amazon Cognito domain:
https://<YourDomainPrefix>.auth.<region>.amazoncognito.com/saml2/idpresponse

With a custom domain:
https://<Your custom domain>/saml2/idpresponse

For some SAML identity provides, you also need to provide the service provider (SP) urn / Audience URI / SP Entity ID.
e.g., urn:amazon:cognito:sp:<yourUserPoolID>

Once the above are done, you can access the hosted UI via the url:

https://<cognito-or-custom-domain>/login?response_type=<response-type>&client_id=<userpool-app-client-id>&redirect_uri=<redirect_uri>

response_type could either be code or token

The response_type value will depend on the implementation of the application to integrate AWS Cognito's Hosted UI.

When code is used as a response_type, an extra step is required to be done by your application. response_type code returns a code as a parameter that's appended to your redirect URL. Your application needs to make a request to the authorisation endpoint to retrieve the identity/access token from Cognito.

Whilst token appends the identity and access tokens as parameters to the redirect URL.

With this, your AWS Cognito is configured to support SSO.

Sample Implementation

As mentioned above, depending on how you integrate Hosted UI into your application will help determine if you will be using response_type value of code or token.

Below will show an example of how you can use AWS Amplify to integrate AWS Cognito Hosted UI to your application. These examples will use Javascript as the programming language with React as the framework of a web application. This example will use a response_type value of token.

Install aws-amplify

npm i aws-amplify

Once installed, we have to configure aws-amplify.

The file below will setup the configuration required by aws-amplify.

// authConfig.js file which help configure AWS Amplify
const awsConfig = {
Auth: {
// REQUIRED - Amazon Cognito Region
region: <region>,
// OPTIONAL - Amazon Cognito Federated Identity Pool Region
// Required only if it's different from Amazon Cognito Region
identityPoolRegion: <AWS_REGION>,
// OPTIONAL - Amazon Cognito User Pool ID
userPoolId: <USER_POOL_ID>,
// OPTIONAL - Amazon Cognito Web Client ID (26-char alphanumeric string)
userPoolWebClientId: <CLIENT_ID>,
// OPTIONAL - Hosted UI configuration
oauth: {
domain: <USER_POOL_DOMAIN>,
scope: [
"phone",
"email",
"profile",
"openid",
"aws.cognito.signin.user.admin",
],
redirectSignIn: <REDIRECT_SIGNIN_URL>,
redirectSignOut: <REDIRECT_SIGNOUT_URL>,
responseType: "token", // note that REFRESH token will only be generated when the responseType is code
},
},
};
export default awsConfig;

Now that you have a function to set the configuration for aws-amplify, the code below shows you how you would use the function. On your main app file, import aws-amplify and configure.

// App.jsx
import { Amplify, Auth, Hub } from "aws-amplify";
import awsConfig from "./utils/authConfig";
Amplify.configure(awsConfig);

The following function ssoCognito will trigger the Hosted UI flow when function is called.

// src/api/ssoCognito.js
import { Auth } from "aws-amplify";

export const signInWithSSO = () => {
// eslint-disable-next-line no-async-promise-executor
return new Promise(async (resolve, reject) => {
try {
const user = await Auth.federatedSignIn();
resolve(user);
} catch (e) {
reject(e);
}
}).catch((err) => {
throw err;
});
};

The following code snippet displays a sample usage of the signInWithSSO function in React.

// src/pages/login.jsx
import { useEffect } from "react";
import { useState } from "react";
import { signInWithSSO } from "~/api/ssoCognito";
import { Button } from "~/components";

export const Login = () => {
const [error, setError] = useState("");

const signInSSO = async () => {
try {
setError("");
await signInWithSSO();
} catch (err) {
setError(err.message);
}
};

return (
<div>
<p>Sample Text</p>
<Button onClick={signInSSO}>"Sign in"</Button>
<p>{error}&nbsp;</p>
</div>
);
};

When Hosted UI flow is complete and redirects the user, you will need to have a way to handle the Cognito session, the following code snippet shows an example of how to handle Cognito sessions via useEffect.

// App.jsx
import { Amplify, Auth } from "aws-amplify";
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
import awsConfig from "./utils/authConfig";

Amplify.configure(awsConfig);

const App = () => {
const navigate = useNavigate();

useEffect(() => {
async function handleSession() {
// Handle the Cognito session
try {
await Auth.currentSession();
// You can also access user information like this:
await Auth.currentAuthenticatedUser();
// Redirect to the appropriate page if the session is valid.
navigate("/sample");
} catch (error) {
console.warn("No valid session");
}
}

handleSession();
}, []);

return (<div>Sample Code</div>)
};

export default App;

When the Cognito session is valid, it will redirect the user to the appropriate page. From here, application should continue as normal.

Advantages/Disadvantages Advantage:

  • Easy Integration: straightforward way to integrate user authentication without having to build a custom authentication system from scratch.
  • Support for Social Identity Providers: AWS Cognito supports integration with social identity providers
  • Scalability
  • Customisation: Allows the customisation of the look and feel of the UI to some extent. e.g. colours, logos and some aspects of the user interface.

Disadvantages:

  • Limited customisation: customisation may not meet the specific design requirements of all applications.
  • Vendor Lock-in: you are tying your application to the AWS ecosystem. Migrating away from AWS Cognito to another authentication solution may require significant effort and resources
  • Learning Curve: integrating and configuring AWS Cognito, including the Hosted UI, may require a learning curve, especially for developers who are new to AWS services or identity management concepts
  • Reliability on AWS Services: Your application’s authentication functionality relies on the reliability and availability of AWS infrastructure

Last Words

I hope that this one has helped you figure out how to configure AWS Cognito to use Hosted UI to enable Single Sign On (SSO) capabilities and get an idea on how you can integrate it to your application.

This is a basic way to do it. If you need help, OR wanted to discuss the right solution for you, contact us HERE.

References:

Originally published at https://blog.srcinnovations.com.au on April 3, 2024.

--

--

SRC Innovations
SRC Innovations
0 Followers
Editor for

IT Consultancy based in Melbourne.