User Pool#

Let's create an user pool.

AWSTemplateFormatVersion: '2010-09-09'
Resources:
UserPool:
Type: AWS::Cognito::UserPool
DeletionPolicy: Delete
UpdateReplacePolicy: Delete
Properties:
UserPoolName: !Sub ${AWS::StackName}-user-pool
# Deletion protection off
DeletionProtection: 'INACTIVE'
# No MFA
MfaConfiguration: 'OFF'
# Password policy
Policies:
PasswordPolicy:
MinimumLength: 8
RequireLowercase: true
RequireNumbers: true
RequireSymbols: true
RequireUppercase: true
UsernameAttributes:
- email
AutoVerifiedAttributes:
- email
Schema:
- Name: email
AttributeDataType: String
Mutable: true
Required: true
# Email provider
EmailConfiguration:
EmailSendingAccount: COGNITO_DEFAULT
UserPoolClient:
Type: AWS::Cognito::UserPoolClient
Properties:
ClientName: !Sub ${AWS::StackName}-user-pool-client
GenerateSecret: false
UserPoolId: !Ref UserPool
ExplicitAuthFlows:
- ALLOW_USER_PASSWORD_AUTH
- ALLOW_USER_SRP_AUTH
- ALLOW_ADMIN_USER_PASSWORD_AUTH
- ALLOW_CUSTOM_AUTH
- ALLOW_REFRESH_TOKEN_AUTH

Set Password#

Export variables.

export UserPoolId="us-west-2_Pj5YEMwy0"

Register a new user using cli instead of using frontend client.

aws cognito-idp admin-create-user \
--user-pool-id $UserPoolId \
--username hai+2@entest.io \
--user-attributes Name=email,Value=hai+1@entest.io \
--message-action SUPPRESS

Set password by admin instead of confirm from user email.

aws cognito-idp admin-set-user-password \
--user-pool-id $UserPoolId \
--username hai+1@entest.io \
--password Demo@2024 \
--permanent

API Gateway#

From aws apigw console, create a Cognito Authorizer. Send reequest to api gateway with token in header. We can export some variables.

export endpoint=https://9lbz0mxhk5.execute-api.us-west-2.amazonaws.com/Prod/book

Export token.

export token=eyJraWQiOiIwcmxGd1pVNCt0aGZ5WnZBVjZTUWlQSXU0bjc4eEhMV2ZKcmFxaTRuU1ZnPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiI0ODcxYTNlMC0zMDUxLTcwZjctMjM5My04YWUxYTI0OTNjMjciLCJpc3MiOiJodHRwczpcL1wvY29nbml0by1pZHAudXMtd2VzdC0yLmFtYXpvbmF3cy5jb21cL3VzLXdlc3QtMl9QajVZRU13eTAiLCJjb2duaXRvOnVzZXJuYW1lIjoiNDg3MWEzZTAtMzA1MS03MGY3LTIzOTMtOGFlMWEyNDkzYzI3Iiwib3JpZ2luX2p0aSI6IjY1MWMwNjhmLTYxZjQtNGYxYS1iMjg1LWUyODBjNGM0NDcyNCIsImF1ZCI6IjZ1dGMyMmZ1aG5zNjBtb2x0bW9vMDYxdXNmIiwiZXZlbnRfaWQiOiJiNTlmMjEzMS0xODU4LTQ5YmUtODJmZS0yZDNmMTU2OGExYmIiLCJ0b2tlbl91c2UiOiJpZCIsImF1dGhfdGltZSI6MTcxNzYzNzUyOCwiZXhwIjoxNzE3NjQxMTI4LCJpYXQiOjE3MTc2Mzc1MjgsImp0aSI6IjIzMWJmZjBlLWViYWQtNDQ1My04ZDRiLTJjYWY5NTU0NTc2OSIsImVtYWlsIjoiaGFpKzFAZW50ZXN0LmlvIn0.Ac61F59Hg9L5buz89jm7xXI2b3yEHDl0P02wPMsnKOM2_n0fWCNSblhnBLSE-lqvJuM_-nzGpYqTGNtEK-67DhrfRM-eqxqRq6Giu_f8RKtEVzBL1vaoLXDUXr5i3qY2b6FF-dpfuwnD09QT2M12V6Tml0_FEkPjwqEr44bzfZeaHGrZFCZs7_7UzNTNKW5PAu9GT9hpyonh-undmW2OgKlN7TddpqXhPKUlD5X66rzlPPgzBfTf8Bx3sW1vyjcUhvlvZmhQMRB8BAt-oVN-GtgrRD3VgtUcBCqt4JIi5RAgGR7-G2To4mwULaj76EbrVHNu4UaTsdnijeYjtVcofg

And

curl -v -H "Authorization: Bearer eyJraWQiOiIwcmxGd1pVNCt0aGZ5WnZBVjZTUWlQSXU0bjc4eEhMV2ZKcmFxaTRuU1ZnPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiI0ODcxYTNlMC0zMDUxLTcwZjctMjM5My04YWUxYTI0OTNjMjciLCJpc3MiOiJodHRwczpcL1wvY29nbml0by1pZHAudXMtd2VzdC0yLmFtYXpvbmF3cy5jb21cL3VzLXdlc3QtMl9QajVZRU13eTAiLCJjb2duaXRvOnVzZXJuYW1lIjoiNDg3MWEzZTAtMzA1MS03MGY3LTIzOTMtOGFlMWEyNDkzYzI3Iiwib3JpZ2luX2p0aSI6IjY1MWMwNjhmLTYxZjQtNGYxYS1iMjg1LWUyODBjNGM0NDcyNCIsImF1ZCI6IjZ1dGMyMmZ1aG5zNjBtb2x0bW9vMDYxdXNmIiwiZXZlbnRfaWQiOiJiNTlmMjEzMS0xODU4LTQ5YmUtODJmZS0yZDNmMTU2OGExYmIiLCJ0b2tlbl91c2UiOiJpZCIsImF1dGhfdGltZSI6MTcxNzYzNzUyOCwiZXhwIjoxNzE3NjQxMTI4LCJpYXQiOjE3MTc2Mzc1MjgsImp0aSI6IjIzMWJmZjBlLWViYWQtNDQ1My04ZDRiLTJjYWY5NTU0NTc2OSIsImVtYWlsIjoiaGFpKzFAZW50ZXN0LmlvIn0.Ac61F59Hg9L5buz89jm7xXI2b3yEHDl0P02wPMsnKOM2_n0fWCNSblhnBLSE-lqvJuM_-nzGpYqTGNtEK-67DhrfRM-eqxqRq6Giu_f8RKtEVzBL1vaoLXDUXr5i3qY2b6FF-dpfuwnD09QT2M12V6Tml0_FEkPjwqEr44bzfZeaHGrZFCZs7_7UzNTNKW5PAu9GT9hpyonh-undmW2OgKlN7TddpqXhPKUlD5X66rzlPPgzBfTf8Bx3sW1vyjcUhvlvZmhQMRB8BAt-oVN-GtgrRD3VgtUcBCqt4JIi5RAgGR7-G2To4mwULaj76EbrVHNu4UaTsdnijeYjtVcofg" https://9lbz0mxhk5.execute-api.us-west-2.amazonaws.com/Prod/book

FrontEnd#

Let's create a home page to sign in and get token.

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>
<input
type="text"
id="username"
name="username"
class="input-username"
placeholder="htranminhhai20@gmail.com"
/>
</div>
<div>
<label for="password">password</label>
<input
type="password"
id="password"
name="password"
class="input-username"
placeholder="Demo@2024"
/>
</div>
<button class="button-submit" id="submit">Sign In</button>
</form>
</div>
</body>
<script>
const config = {
CLIENT_ID: '1fo164cp8c6mnpbp9915gmgm3d',
ENDPOINT: 'https://cognito-idp.us-west-2.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 storage
localStorage.setItem(
'AccessToken',
response.data.AuthenticationResult.AccessToken
)
// store id token in local storage
localStorage.setItem(
'IdToken',
response.data.AuthenticationResult.IdToken
)
// open profile page
window.location.href = 'profile.html'
})
.catch(error => {
console.log(error)
})
}
document.getElementById('submit').addEventListener('click', async event => {
event.preventDefault()
const username = document.getElementById('username').value
const password = document.getElementById('password').value
signIn(username, password)
})
</script>
</html>

Let's create a profile page to decode token.

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 storage
document.getElementById('AccessToken').innerHTML =
localStorage.getItem('AccessToken')
// get id token from local storage
document.getElementById('IdToken').innerHTML =
localStorage.getItem('IdToken')
// cognito configuration
const config = {
CLIENT_ID: '1cakmv86je8vm15nu8ufbpb4la',
ENDPOINT: 'https://cognito-idp.us-east-1.amazonaws.com'
}
// only decode not validate
const 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>