amazon-web-servicesauthenticationamazon-cognitoopenid-connectaws-amplify

AWS Amplify Auth with Cognito User Pool not returning nonce or at_hash claim in JWT id_token


I'm trying to use Amplify Auth to implement an OpenID Connect Implicit Flow to provide SSO to a number of React clients.

I've been able to get this working with Cognito Hosted UI, but that requires other apps users to click a button to confirm login in order to authenticate. I'd prefer for it to be seamless ie when a user is logged in on one site and navigate to another they are automatically authenticated if they have a session with the auth provider.

To try and achieve this I've set up a separate Amplify app that uses the React Authenticator Component.

I'm able to authenticate with this and redirect back to the client. However the id_token doesn't contain the at_hash or nonce claim. Presumably, the at_hash is missing because the authentication provider app is not sending the responseType of token id_token when it authenticates with Cognito. The nonce is missing because I haven't found a way to pass it in.

  1. Is there a way to get Amplify Authenticator SignIn to request an id_token with the at_hash claim?

  2. Is it possible to pass a nonce value through to the id_token claims?

Note I'm trying to adhere to: https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowSteps Specifically for this part: 3.2.2.10. ID Token

import React from 'react';
import { Authenticator, ConfirmSignIn, SignIn } from 'aws-amplify-react';
import Amplify, { Auth } from 'aws-amplify';
import awsconfig from './aws-exports';

Amplify.configure(awsconfig);

const getSearchParams = () =>
    window.location.search.substr(1);

const getValueFromSearchParam = (key) =>
    new URLSearchParams(getSearchParams()).get(key);

const getRedirectUri = () => {
    const redirect_uri = getValueFromSearchParam('redirect_uri');
    return redirect_uri ? decodeURI(redirect_uri) : null;
};

const Login = () => {
    const handleAuthStateChange = (state) => {
        if(state === 'signedIn') {
            const redirect_uri = getRedirectUri();
            const state = getValueFromSearchParam('state');
            if(redirect_uri === null) {
                throw new Error('No redirect_uri provided');
            }
            Auth.currentSession().then(currentSession => {
                const id_token = currentSession.idToken.jwtToken;
                const access_token = currentSession.accessToken.jwtToken;
                const redirect = `${redirect_uri}#access_token=${access_token}&id_token=${id_token}&state=${state}`;
                window.location.replace(redirect);
            }).catch(err => console.error(err));
        }
    };

    return (
        <Authenticator
            hideDefault={true}
            onStateChange={handleAuthStateChange}
        >
            <SignIn  />
            <ConfirmSignIn/>
        </Authenticator>
    );
};

Solution

  • A few points to consider:

    If it helps, my blog's introductory code example uses Cognito with the Hosted UI (not the custom UI). I can confirm that you can use SSO across multiple apps without prompts.