Summary#

  • Cognito User Pool and APIs
  • Cognito Hosted UI
  • Federated Sign In

Get Token from Cognito User Pool -> Client JS#

low level api call to get token, follow docs HERE

  • ID token contains claims about the identity of the authenticated user such as name, email, and phone_number. ID token can be used to authenticate users to your resource servers or server application.

  • Access token contains claims about the authenticated user, a list of the user's groups, a list of scopes. The purpose of the access token is to authorize API operations in the context of the user in the user pool. For example, you can use the access token to grant your user access to add, change, or delete user attributes.

import axios from "axios";
import { config } from "./config.js";
const getToken = () => {
axios
.request({
method: "POST",
url: config.url,
headers: {
"Content-Type": "application/x-amz-json-1.1",
"X-Amz-Target": "AWSCognitoIdentityProviderService.InitiateAuth",
},
data: {
AuthFlow: "USER_PASSWORD_AUTH",
AuthParameters: {
PASSWORD: config.password,
USERNAME: config.username,
},
ClientId: config.clientId,
},
})
.then((response) => {
console.log(response.data);
});
};

Example to validate token

calculated_signagure = algorithm(PublicKey_JWK, Header, Payload);

then compare the calculated signature with issuer

compare(calculated_signagure, issuer_signagure)

example using CognitoJwtVerifier

import { CognitoJwtVerifier } from "aws-jwt-verify";
async function verifyAccessToken(accessToken) {
// verifier that expects valid access tokens:
const verifier = CognitoJwtVerifier.create({
userPoolId: process.env.USER_POOL_ID,
tokenUse: "access",
clientId: process.env.APP_CLIENT_ID,
});
// decoded token
let decodedToken;
try {
decodedToken = await verifier.verify(accessToken);
console.log("Token is valid. Payload:", decodedToken);
} catch {
decodedToken = {};
console.log("Token not valid!");
}
return decodedToken;
}

Client JS Auth Flow#

With Authenticator#

Cognito Hosted UI#

  • open the cognito hosted ui link
  • login with username and password
  • redirected to mydomain/?code=12345
  • pasrse the code to exchange for token

exchange the code for token using POST request to cognito token endpoint

const getCurrentUrl = async () => {
const code = "";
axios
.request({
method: "POST",
url: config.tokenEndpoint,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
data: {
grant_type: "authorization_code",
code: code,
redirect_uri: config.redirectUrl,
client_id: config.clientId,
},
})
.then((response) => {
console.log(response.data);
})
.catch((error) => {
console.log(error);
});
};

Simple FrontEnd -> Call Hosted UI#

using window.onload or document.onreadystatechange to detect url change then parse the code.

window.onload = () => {
console.log("location change ", window.location.href);
if (
window.location.href != "http://localhost:5500/index.html" &&
window.location.href != "http://localhost:5500/"
) {
const user = getCurrentUrl();
}
};

parse the current url, get code and exchange for token

const getCurrentUrl = async () => {
const code = window.location.href.split("=").pop();
console.log(code);
axios
.request({
method: "POST",
url: config.tokenEndpoint,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
data: {
grant_type: "authorization_code",
code: code,
redirect_uri: config.redirectUrl,
client_id: config.clientId,
},
})
.then((response) => {
console.log(response.data);
localStorage.setItem("user", response.data.id_token);
window.location.replace("http://localhost:5500/login.html");
return JSON.stringify(response.data);
})
.catch((error) => {
console.log(error);
return null;
});
};

Amplify Auth Federated Signin -> Hosted UI#

it is much easier to use Amplify Auth Federated Sigin method to do the above steps HERE and HERE

import React, { useEffect, useState } from "react";
import { Amplify, Auth, Hub } from "aws-amplify";
import { CognitoHostedUIIdentityProvider } from "@aws-amplify/auth";
import awsconfig from "./aws-exports";
Amplify.configure(awsconfig);
function App() {
const [user, setUser] = useState(null);
const [customState, setCustomState] = useState(null);
useEffect(() => {
const unsubscribe = Hub.listen("auth", ({ payload: { event, data } }) => {
switch (event) {
case "signIn":
setUser(data);
break;
case "signOut":
setUser(null);
break;
case "customOAuthState":
setCustomState(data);
}
});
Auth.currentAuthenticatedUser()
.then((currentUser) => setUser(currentUser))
.catch(() => console.log("Not signed in"));
return unsubscribe;
}, []);
return (
<div className="App">
<button onClick={() => Auth.federatedSignIn()}>Open Hosted UI</button>
<button
onClick={() =>
Auth.federatedSignIn({
provider: CognitoHostedUIIdentityProvider.Google,
})
}
>
Open Google
</button>
<button onClick={() => Auth.signOut()}>Sign Out</button>
<div>{user && user.getUsername()}</div>
</div>
);
}