Introduction#
- Create UserPool and Identity Pool using CDK
- Authentication using AWS SDK
- Authetication using axios
Stack#
Let create userpool with
- domain for hosted ui
- client with secrete key for server side auth
- client without secret key for client side auth
const userPool = new aws_cognito.UserPool(this, 'UserPoolForWebEntest', {userPoolName: 'UserPoolForWebEntest',selfSignUpEnabled: true,signInAliases: {email: true},autoVerify: {email: true},removalPolicy: RemovalPolicy.DESTROY})
Then create an identity pool
const clientWithoutSecret = new aws_cognito.UserPoolClient(this,'ClientWithoutSecret',{userPool: userPool,authFlows: {userPassword: true,adminUserPassword: true,custom: true,userSrp: true},userPoolClientName: 'ClientWithoutSecret'})const clientWithSecret = new aws_cognito.UserPoolClient(this,'ClientWithSecret',{userPool: userPool,authFlows: {userPassword: true,adminUserPassword: true,custom: true,userSrp: true},userPoolClientName: 'ClientWithSecret',generateSecret: true,oAuth: {flows: {authorizationCodeGrant: true},callbackUrls: props.callbackUrls,logoutUrls: props.logoutUrls,scopes: [aws_cognito.OAuthScope.EMAIL,aws_cognito.OAuthScope.OPENID,aws_cognito.OAuthScope.PHONE]}})
Add a domain for hosted ui
const domain = userPool.addDomain('domain', {cognitoDomain: {domainPrefix: 'domain-prefix'}})domain.signInUrl(clientWithSecret, {redirectUri: ''})
Finally let add an identity pool
const cognitoIdentityPool = new aws_cognito.CfnIdentityPool(this,"IdentityPoolForWebEntest",{allowUnauthenticatedIdentities: true,identityPoolName: "IdentityPoolForWebEntest",cognitoIdentityProviders: [{clientId: clientWithSecret.userPoolClientId,providerName: userPool.userPoolProviderName,},{clientId: clientWithoutSecret.userPoolClientId,providerName: userPool.userPoolProviderName,},],// supportedLoginProviders: [],});this.userPool = userPool.userPoolArn;this.identityPool = cognitoIdentityPool;}
To grant auth and unauth role for the identity pool
export class CognitoAuthRole extends Stack {constructor(scope: Construct, id: string, props: CognitoAuthProps) {super(scope, id, props)const role = new aws_iam.Role(this, 'RoleForAuthenticatedUserWebEntest', {assumedBy: new aws_iam.FederatedPrincipal('cognito-identity.amazonaws.com',{StringEquals: {'cognito-identity.amazonaws.com:aud': props.cognitoIdentityPool.ref},'ForAnyValue:StringLike': {'cognito-identity.amazonaws.com:amr': 'authenticated'}},'sts:AssumeRoleWithWebIdentity'),roleName: 'RoleForAuthenticatedUserWebEntest'})// auth role access s3role.addToPolicy(new aws_iam.PolicyStatement({effect: aws_iam.Effect.ALLOW,actions: ['s3:PutObject', 's3:GetObject'],resources: [`arn:aws:s3:::${props.bucketName}`,`arn:aws:s3:::${props.bucketName}/*`]}))// unauth roleconst unauthRole = new aws_iam.Role(this,'RoleForUnAuthenticatedUserWebEntest',{assumedBy: new aws_iam.FederatedPrincipal('cognito-identity.amazonaws.com',{StringEquals: {'cognito-identity.amazonaws.com:aud':props.cognitoIdentityPool.ref},'ForAnyValue:StringLike': {'cognito-identity.amazonaws.com:amr': 'unauthenticated'}},'sts:AssumeRoleWithWebIdentity'),roleName: 'RoleForUnAuthenticatedUserWebEntest'})// unauth role access s3unauthRole.addToPolicy(new aws_iam.PolicyStatement({effect: aws_iam.Effect.ALLOW,actions: ['s3:PutObject', 's3:GetObject'],resources: [`arn:aws:s3:::${props.bucketName}`,`arn:aws:s3:::${props.bucketName}/*`]}))// unauth role access pollyunauthRole.addToPolicy(new aws_iam.PolicyStatement({effect: aws_iam.Effect.ALLOW,actions: ['polly:SynthesizeSpeech'],resources: ['*']}))const attach = new aws_cognito.CfnIdentityPoolRoleAttachment(this,'RoleAttachmentForWebEntest',{identityPoolId: props.cognitoIdentityPool.ref,roles: {authenticated: role.roleArn,unauthenticated: unauthRole.roleArn}})}}
Finally add an s3 bucket
interface S3Props extends StackProps {bucketName: string}export class S3Stack extends Stack {public readonly bucket: aws_s3.Bucketconstructor(scope: Construct, id: string, props: S3Props) {super(scope, id, props)this.bucket = new aws_s3.Bucket(this, props.bucketName, {bucketName: props.bucketName,removalPolicy: RemovalPolicy.DESTROY,autoDeleteObjects: true,cors: [{allowedHeaders: ['*'],allowedMethods: [aws_s3.HttpMethods.GET,aws_s3.HttpMethods.PUT,aws_s3.HttpMethods.DELETE,aws_s3.HttpMethods.POST],allowedOrigins: ['*'],exposedHeaders: ['x-amz-server-side-encryption','x-amz-request-id','x-amz-id-2','ETag'],maxAge: 3000}]})}}
Here is full cdk stack
cdk-stack.ts
import { Construct } from 'constructs'import {aws_cognito,aws_iam,aws_s3,RemovalPolicy,Stack,StackProps} from 'aws-cdk-lib'interface CognitoProps extends StackProps {callbackUrls: string[]logoutUrls: string[]}export class CognitoAuthorizer extends Stack {public readonly userPool: stringpublic readonly identityPool: aws_cognito.CfnIdentityPoolconstructor(scope: Construct, id: string, props: CognitoProps) {super(scope, id, props)const userPool = new aws_cognito.UserPool(this, 'UserPoolForWebEntest', {userPoolName: 'UserPoolForWebEntest',selfSignUpEnabled: true,signInAliases: {email: true},autoVerify: {email: true},removalPolicy: RemovalPolicy.DESTROY})const clientWithoutSecret = new aws_cognito.UserPoolClient(this,'ClientWithoutSecret',{userPool: userPool,authFlows: {userPassword: true,adminUserPassword: true,custom: true,userSrp: true},userPoolClientName: 'ClientWithoutSecret'})const clientWithSecret = new aws_cognito.UserPoolClient(this,'ClientWithSecret',{userPool: userPool,authFlows: {userPassword: true,adminUserPassword: true,custom: true,userSrp: true},userPoolClientName: 'ClientWithSecret',generateSecret: true,oAuth: {flows: {authorizationCodeGrant: true},callbackUrls: props.callbackUrls,logoutUrls: props.logoutUrls,scopes: [aws_cognito.OAuthScope.EMAIL,aws_cognito.OAuthScope.OPENID,aws_cognito.OAuthScope.PHONE]}})const domain = userPool.addDomain('domain', {cognitoDomain: {domainPrefix: 'domain-prefix'}})domain.signInUrl(clientWithSecret, {redirectUri: ''})const cognitoIdentityPool = new aws_cognito.CfnIdentityPool(this,'IdentityPoolForWebEntest',{allowUnauthenticatedIdentities: true,identityPoolName: 'IdentityPoolForWebEntest',cognitoIdentityProviders: [{clientId: clientWithSecret.userPoolClientId,providerName: userPool.userPoolProviderName},{clientId: clientWithoutSecret.userPoolClientId,providerName: userPool.userPoolProviderName}]// supportedLoginProviders: [],})this.userPool = userPool.userPoolArnthis.identityPool = cognitoIdentityPool}}interface CognitoAuthProps extends StackProps {cognitoIdentityPool: aws_cognito.CfnIdentityPoolbucketName: string}export class CognitoAuthRole extends Stack {constructor(scope: Construct, id: string, props: CognitoAuthProps) {super(scope, id, props)const role = new aws_iam.Role(this, 'RoleForAuthenticatedUserWebEntest', {assumedBy: new aws_iam.FederatedPrincipal('cognito-identity.amazonaws.com',{StringEquals: {'cognito-identity.amazonaws.com:aud': props.cognitoIdentityPool.ref},'ForAnyValue:StringLike': {'cognito-identity.amazonaws.com:amr': 'authenticated'}},'sts:AssumeRoleWithWebIdentity'),roleName: 'RoleForAuthenticatedUserWebEntest'})// auth role access s3role.addToPolicy(new aws_iam.PolicyStatement({effect: aws_iam.Effect.ALLOW,actions: ['s3:PutObject', 's3:GetObject'],resources: [`arn:aws:s3:::${props.bucketName}`,`arn:aws:s3:::${props.bucketName}/*`]}))// unauth roleconst unauthRole = new aws_iam.Role(this,'RoleForUnAuthenticatedUserWebEntest',{assumedBy: new aws_iam.FederatedPrincipal('cognito-identity.amazonaws.com',{StringEquals: {'cognito-identity.amazonaws.com:aud':props.cognitoIdentityPool.ref},'ForAnyValue:StringLike': {'cognito-identity.amazonaws.com:amr': 'unauthenticated'}},'sts:AssumeRoleWithWebIdentity'),roleName: 'RoleForUnAuthenticatedUserWebEntest'})// unauth role access s3unauthRole.addToPolicy(new aws_iam.PolicyStatement({effect: aws_iam.Effect.ALLOW,actions: ['s3:PutObject', 's3:GetObject'],resources: [`arn:aws:s3:::${props.bucketName}`,`arn:aws:s3:::${props.bucketName}/*`]}))// unauth role access pollyunauthRole.addToPolicy(new aws_iam.PolicyStatement({effect: aws_iam.Effect.ALLOW,actions: ['polly:SynthesizeSpeech'],resources: ['*']}))const attach = new aws_cognito.CfnIdentityPoolRoleAttachment(this,'RoleAttachmentForWebEntest',{identityPoolId: props.cognitoIdentityPool.ref,roles: {authenticated: role.roleArn,unauthenticated: unauthRole.roleArn}})}}interface S3Props extends StackProps {bucketName: string}export class S3Stack extends Stack {public readonly bucket: aws_s3.Bucketconstructor(scope: Construct, id: string, props: S3Props) {super(scope, id, props)this.bucket = new aws_s3.Bucket(this, props.bucketName, {bucketName: props.bucketName,removalPolicy: RemovalPolicy.DESTROY,autoDeleteObjects: true,cors: [{allowedHeaders: ['*'],allowedMethods: [aws_s3.HttpMethods.GET,aws_s3.HttpMethods.PUT,aws_s3.HttpMethods.DELETE,aws_s3.HttpMethods.POST],allowedOrigins: ['*'],exposedHeaders: ['x-amz-server-side-encryption','x-amz-request-id','x-amz-id-2','ETag'],maxAge: 3000}]})}}
Cognito SDK#
Let create a new TypeScript project
npm init
Then install dependencies
{"name": "app","version": "1.0.0","description": "","main": "index.js","scripts": {"test": "echo \"Error: no test specified\" && exit 1"},"author": "","license": "ISC","devDependencies": {"@types/node": "^20.11.19","tslint": "^6.1.3","typescript": "^5.3.3"},"dependencies": {"@aws-sdk/client-cognito-identity-provider": "^3.427.0","@aws-sdk/client-dynamodb": "^3.438.0","@aws-sdk/client-s3": "^3.427.0","@aws-sdk/credential-providers": "^3.427.0","@aws-sdk/s3-presigned-post": "^3.429.0","aws-cloudfront-sign": "^3.0.2","aws-jwt-verify": "^4.0.0","aws-lambda": "^1.0.7","axios": "^1.6.7","package.json": "^2.0.1"}}
Then we can create a Cognito client
import { config } from './config'import {CognitoIdentityProviderClient,SignUpCommand,ConfirmSignUpCommand,InitiateAuthCommand} from '@aws-sdk/client-cognito-identity-provider'import { CognitoJwtVerifier } from 'aws-jwt-verify'const cognitoClient = new CognitoIdentityProviderClient({region: config.REGION})
Perform some actions such as sign up, confirm sign up and sin in
const signUp = async (username: string, password: string) => {try {const response = await cognitoClient.send(new SignUpCommand({ClientId: config.CLIENT_ID,Username: username,Password: password}))console.log(response)} catch (error) {console.log(error)}}const confirmSignUp = async (username: string, code: string) => {try {const response = await cognitoClient.send(new ConfirmSignUpCommand({ClientId: config.CLIENT_ID,Username: username,ConfirmationCode: code}))} catch (error) {console.log(error)}}export const signIn = async (username: string, password: string) => {try {const response = await cognitoClient.send(new InitiateAuthCommand({AuthFlow: 'USER_PASSWORD_AUTH',AuthParameters: {USERNAME: username,PASSWORD: password},ClientId: config.CLIENT_ID}))console.log('cognito auth: ', response)return response} catch (error) {console.log(error)return null}}const decodeToken = async ({ token }: { token: string }) => {// const token = "";// const response = (await decode({// token: token,// secret: "b10cda68fe67233283a06a30a76eb161",// })) as any;// console.log(response.id_token);// const idToken = response.id_token;const tokenUse = 'access'const verifier = CognitoJwtVerifier.create({userPoolId: config.USER_POOL_ID,tokenUse: tokenUse,clientId: config.CLIENT_ID})try {const payload = await verifier.verify(token, {tokenUse: tokenUse,clientId: config.CLIENT_ID})console.log('Token is valid. Payload:', payload)} catch {console.log('Token not valid!')}}// signUp("hai@entest.io", "mypassword");// confirmSignUp("hai@entest.io", "113656");// signIn("hai@entest.io", "mypassword");
Heres is full script
cognito-sdk.ts
// getting started with cognito userpool// without using sdk// 20/02/2024import { config } from './config'import {CognitoIdentityProviderClient,SignUpCommand,ConfirmSignUpCommand,InitiateAuthCommand} from '@aws-sdk/client-cognito-identity-provider'import { CognitoJwtVerifier } from 'aws-jwt-verify'const cognitoClient = new CognitoIdentityProviderClient({region: config.REGION})const signUp = async (username: string, password: string) => {try {const response = await cognitoClient.send(new SignUpCommand({ClientId: config.CLIENT_ID,Username: username,Password: password}))console.log(response)} catch (error) {console.log(error)}}const confirmSignUp = async (username: string, code: string) => {try {const response = await cognitoClient.send(new ConfirmSignUpCommand({ClientId: config.CLIENT_ID,Username: username,ConfirmationCode: code}))} catch (error) {console.log(error)}}export const signIn = async (username: string, password: string) => {try {const response = await cognitoClient.send(new InitiateAuthCommand({AuthFlow: 'USER_PASSWORD_AUTH',AuthParameters: {USERNAME: username,PASSWORD: password},ClientId: config.CLIENT_ID}))console.log('cognito auth: ', response)return response} catch (error) {console.log(error)return null}}const decodeToken = async ({ token }: { token: string }) => {// const token = "";// const response = (await decode({// token: token,// secret: "b10cda68fe67233283a06a30a76eb161",// })) as any;// console.log(response.id_token);// const idToken = response.id_token;const tokenUse = 'access'const verifier = CognitoJwtVerifier.create({userPoolId: config.USER_POOL_ID,tokenUse: tokenUse,clientId: config.CLIENT_ID})try {const payload = await verifier.verify(token, {tokenUse: tokenUse,clientId: config.CLIENT_ID})console.log('Token is valid. Payload:', payload)} catch {console.log('Token not valid!')}}// signUp("hai@entest.io", "mypassword");// confirmSignUp("hai@entest.io", "113656");// signIn("hai@entest.io", "mypassword");
Cognito Axios#
- Cognito without using SDK
- Simple frontend
First, let use axios to send request to Cognito to perform sign up an new account
import { config } from './config'import axios from 'axios'import { CognitoJwtVerifier } from 'aws-jwt-verify'const signUp = async ({username,password}: {username: stringpassword: string}) => {axios.post(config.ENDPOINT,{ClientId: config.CLIENT_ID,Username: username,Password: password},{headers: {'Content-Type': 'application/x-amz-json-1.1',Accept: '*/*','X-Amz-Target': 'AWSCognitoIdentityProviderService.SignUp'}}).then(response => {console.log(response)}).catch(error => {console.log(error)})}
For confirm signup with code received form email
const confirmSignUp = async ({confirmCode,username}: {confirmCode: stringusername: string}) => {axios.post(config.ENDPOINT,{ClientId: config.CLIENT_ID,ConfirmationCode: confirmCode,Username: username},{headers: {'Content-Type': 'application/x-amz-json-1.1',Accept: '*/*','X-Amz-Target': 'AWSCognitoIdentityProviderService.ConfirmSignUp'}}).then(response => {console.log(response)}).catch(error => {console.log(error)})}
Finally, sign in an user with username and password
const signIn = async ({username,password}: {username: stringpassword: string}) => {axios.post(config.ENDPOINT,{AuthFlow: 'USER_PASSWORD_AUTH',ClientId: config.CLIENT_ID,AuthParameters: {USERNAME: username,PASSWORD: password}},{headers: {'Content-Type': 'application/x-amz-json-1.1',Accept: '*/*','X-Amz-Target': 'AWSCognitoIdentityProviderService.InitiateAuth'}}).then(response => {console.log(response)}).catch(error => {console.log(error)})}
Validate and decode token
const validateToken = async ({ token }: { token: string }) => {const tokenUse = 'access'const verifier = CognitoJwtVerifier.create({userPoolId: config.USER_POOL_ID,tokenUse: tokenUse,clientId: config.CLIENT_ID})try {const payload = await verifier.verify(token, {tokenUse: tokenUse,clientId: config.CLIENT_ID})console.log('Token is valid. Payload:', payload)} catch {console.log('Token not valid!')}}signUp({ username: 'myemail@gmail.com', password: 'mypassword' })confirmSignUp({ confirmCode: '711595', username: 'myemail@gmail.com' })signIn({ username: 'myemail@gmail.com', password: 'mypassword' })
Here is full script
cognito-axios.ts
// getting started with cognito userpool// without using sdk// 20/02/2024import { config } from './config'import axios from 'axios'import { CognitoJwtVerifier } from 'aws-jwt-verify'const signUp = async ({username,password}: {username: stringpassword: string}) => {axios.post(config.ENDPOINT,{ClientId: config.CLIENT_ID,Username: username,Password: password},{headers: {'Content-Type': 'application/x-amz-json-1.1',Accept: '*/*','X-Amz-Target': 'AWSCognitoIdentityProviderService.SignUp'}}).then(response => {console.log(response)}).catch(error => {console.log(error)})}const confirmSignUp = async ({confirmCode,username}: {confirmCode: stringusername: string}) => {axios.post(config.ENDPOINT,{ClientId: config.CLIENT_ID,ConfirmationCode: confirmCode,Username: username},{headers: {'Content-Type': 'application/x-amz-json-1.1',Accept: '*/*','X-Amz-Target': 'AWSCognitoIdentityProviderService.ConfirmSignUp'}}).then(response => {console.log(response)}).catch(error => {console.log(error)})}const signIn = async ({username,password}: {username: stringpassword: string}) => {axios.post(config.ENDPOINT,{AuthFlow: 'USER_PASSWORD_AUTH',ClientId: config.CLIENT_ID,AuthParameters: {USERNAME: username,PASSWORD: password}},{headers: {'Content-Type': 'application/x-amz-json-1.1',Accept: '*/*','X-Amz-Target': 'AWSCognitoIdentityProviderService.InitiateAuth'}}).then(response => {console.log(response)}).catch(error => {console.log(error)})}const validateToken = async ({ token }: { token: string }) => {const tokenUse = 'access'const verifier = CognitoJwtVerifier.create({userPoolId: config.USER_POOL_ID,tokenUse: tokenUse,clientId: config.CLIENT_ID})try {const payload = await verifier.verify(token, {tokenUse: tokenUse,clientId: config.CLIENT_ID})console.log('Token is valid. Payload:', payload)} catch {console.log('Token not valid!')}}signUp({ username: 'myemail@gmail.com', password: 'mypassword' })confirmSignUp({ confirmCode: '711595', username: 'myemail@gmail.com' })signIn({ username: 'myemail@gmail.com', password: 'mypassword' })
FrontEnd#
Let create a simple frontend for client side auth
- index.html with login form
- profile.html for authenticated page
Here is index.html
index.html
<html><head><title>simple cognito</title><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><style>:root {box-sizing: border-box;}*,::before,::after {box-sizing: inherit;}body {background-color: antiquewhite;}.container {max-width: 800px;margin-left: auto;margin-right: auto;justify-content: center;align-items: center;display: flex;flex-direction: column;min-height: 100%;}.form {display: grid;row-gap: 10px;grid-template-columns: repeat(1, minmax(0, 1fr));gap: 15px;background-color: gainsboro;padding: 20px 20px;min-width: 350px;}.button-submit {padding: 10px 15px;border-radius: 5px;background-color: greenyellow;border: none;cursor: pointer;}.button-submit:hover {background-color: aqua;}.input-username {padding: 5px 10px;width: 100%;}</style></head><body><div class="container"><form class="form" id="form"><div><label for="username">username</label><inputtype="text"id="username"name="username"class="input-username"placeholder="htranminhhai20@gmail.com"/></div><div><label for="password">password</label><inputtype="password"id="password"name="password"class="input-username"placeholder="PasswordPlacehoder"/></div><button class="button-submit" id="submit">Sign In</button></form></div></body><script>const config = {REGION: 'us-east-1',BUCKET: 'bucket-name',// client authUSER_POOL_ID: 'USER_POOL_ID',COGNITO_POOL_ID: 'cognito-idp.us-east-1.amazonaws.com/USER_POOL_ID',IDENTITY_POOL_ID: 'us-east-1:IDENTITY_POOL_ID',CLIENT_ID: 'CLIENT_ID',//ENDPOINT: 'https://cognito-idp.us-east-1.amazonaws.com'}const signIn = async (username, password) => {axios.post(config.ENDPOINT,{AuthFlow: 'USER_PASSWORD_AUTH',ClientId: config.CLIENT_ID,AuthParameters: {USERNAME: username,PASSWORD: password}},{headers: {'Content-Type': 'application/x-amz-json-1.1',Accept: '*/*','X-Amz-Target': 'AWSCognitoIdentityProviderService.InitiateAuth'}}).then(response => {console.log(response)// store access token in local storagelocalStorage.setItem('AccessToken',response.data.AuthenticationResult.AccessToken)// store id token in local storagelocalStorage.setItem('IdToken',response.data.AuthenticationResult.IdToken)// open profile pagewindow.location.href = 'profile.html'}).catch(error => {console.log(error)})}document.getElementById('submit').addEventListener('click', async event => {event.preventDefault()const username = document.getElementById('username').valueconst password = document.getElementById('password').valuesignIn(username, password)})</script></html>
And here is profile.html
profile.html
<!DOCTYPE html><html><head><title>profile page</title><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><style>.main {max-width: 1000px;margin: auto;background-color: gainsboro;height: 100vh;}.token {width: 90%;height: 200px;margin: auto;padding: 10px;overflow: auto;background-color: beige;word-wrap: break-word;}.button-decode {background-color: orange;padding: 10px 20px;cursor: pointer;}.decoded-token {background-color: beige;}</style></head><body><div class="main"><div><h3>Access Token</h3><textarea id="AccessToken" class="token"></textarea><h3>Id Token</h3><textarea id="IdToken" class="token"></textarea><button class="button-decode" id="decode-access-token">Decode Token</button><h3>Decoded Id Token</h3><pre id="DecodedIdToken" class="decoded-token"></pre></div></div><script>// get access token from local storagedocument.getElementById('AccessToken').innerHTML =localStorage.getItem('AccessToken')// get id token from local storagedocument.getElementById('IdToken').innerHTML =localStorage.getItem('IdToken')// cognito configurationconst config = {REGION: 'us-east-1',BUCKET: 'bucket-name',// client authUSER_POOL_ID: 'USER_POOL_ID',COGNITO_POOL_ID: 'cognito-idp.us-east-1.amazonaws.com/USER_POOL_ID',IDENTITY_POOL_ID: 'us-east-1:IDENTITY_POOL_ID',CLIENT_ID: 'CLIENT_ID',//ENDPOINT: 'https://cognito-idp.us-east-1.amazonaws.com'}// only decode not validateconst decodeToken = () => {var token = localStorage.getItem('IdToken')var base64Url = token.split('.')[1]var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/')var jsonPayload = decodeURIComponent(window.atob(base64).split('').map(function (c) {return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2)}).join(''))let obj = JSON.parse(jsonPayload)let dec = document.getElementById('DecodedIdToken')dec.innerHTML = JSON.stringify(obj, undefined, 2).toString()console.log(JSON.stringify(obj, undefined, 2))return JSON.parse(jsonPayload)}document.getElementById('decode-access-token').addEventListener('click', decodeToken)</script></body></html>