Introduction#

GitHub this shows how to use aws cognito for authentication and authorization.

  • cognito user pool for authentication
  • cognito identity pool for authorization
  • get credentials and create s3 client
Cognito SDK JavaScript

Setup Backend#

setup CORS rule for a bucket

const bucket = new aws_s3.Bucket(this, 'CognitoDemoBucket', {
bucketName: `cognito-demo-bucket-${this.account}-1`,
removalPolicy: RemovalPolicy.DESTROY,
// so webapp runnning local host can access s3
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
}
]
})

user pool

const userPool = new aws_cognito.UserPool(this, 'UserPoolDemo', {
userPoolName: 'UserPoolDemo',
selfSignUpEnabled: true,
signInAliases: {
email: true
},
autoVerify: {
email: true
},
removalPolicy: RemovalPolicy.DESTROY
})
const client = userPool.addClient('NextJsWebAppClient', {
authFlows: {
userPassword: true,
adminUserPassword: true,
custom: true,
userSrp: true
},
userPoolClientName: 'WebAppClient'
})

associate userpool with an identity pool

const identityPool = new IdentityPool(this, 'IdentityPoolDemo', {
identityPoolName: 'IdentityPoolDemo',
authenticationProviders: {
userPools: [
new UserPoolAuthenticationProvider({
userPool,
userPoolClient: client
})
]
}
})

grant read write s3 permission to the identity pool

bucket.grantReadWrite(identityPool.authenticatedRole)
bucket.grantRead(identityPool.authenticatedRole)

Setup NextJS and AWS SDK#

create a new nextjs project

npx create-next-app@latest --typescript

install dependencies

npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion react-icons @chakra-ui/icons

install aws sdk clients (v3)

npm i @aws-sdk/client-cognito-identity-provider @aws-sdk/client-s3 @aws-sdk/credential-providers @aws-sdk/s3-request-presigner

Cognito#

sign up a new account

export 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)
}
}

then confirm sign up. The issue is how to redirect after success confirmed

export const confirm = async (username: string, code: string) => {
try {
const response = await cognitoClient.send(
new ConfirmSignUpCommand({
ClientId: config.CLIENT_ID,
ConfirmationCode: code,
Username: username
})
)
console.log(response)
} catch (error) {
console.log(error)
}
}

sign in (an user already setup and confirmed)

const cognitoClient = new CognitoIdentityProviderClient({
region: config.REGION
})
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
}
}

TODO: sign up (Amplify is faster here)

TODO: confirmation (Amplify is faster here)

S3 Client#

credentials and s3 client

const s3Client = new S3Client({
region: config.REGION,
credentials: fromCognitoIdentityPool({
clientConfig: { region: config.REGION },
identityPoolId: config.IDENTITY_POOL_ID,
logins: {
[config.COGNITO_POOL_ID]: idToken
}
})
})

list objects

const command = new ListObjectsCommand({
Bucket: config.BUCKET,
Prefix: "public/",
})
try {
const result = await s3Client.send(command)
console.log('s3 list: ', result)
return result['Contents']
} catch (error) {
console.log(error)
return []
}

set signed url object

const command = new GetObjectCommand({
Bucket: config.BUCKET,
Key: key
})
const signUrl = await getSignedUrl(s3Client, command)