This guide shows step-by-step how to create and configure Amazon Cognito (User Pool + App Client, optional Identity Pool) and an Amazon API Gateway HTTP API that uses Cognito as a JWT authorizer. It includes console steps, AWS CLI/PowerShell commands, IAM notes and examples for testing.
Architecture assumption: frontend (Vercel) calls API Gateway (HTTP API) -> Gateway authorizer validates Cognito JWTs -> routes to Lambda (business logic). SQL Server runs on EC2 in a private subnet and is accessed by Lambda when needed.
learninghub-userpool.email as required; add name if you need display names.https://learninghub.example.com) for Hosted UI flows.Notes:
Console: In User Pool -> App clients -> “Add an app client”. Name it like learninghub-web-client. Uncheck “Generate client secret” for browser-based apps.
AWS CLI (PowerShell):
# create app client (no secret)
aws cognito-idp create-user-pool-client --user-pool-id <USER_POOL_ID> --client-name learninghub-web-client --no-generate-secret --output json
Record the ClientId and UserPoolId for later.
learninghub-demo-<suffix>).Use an identity pool when you need AWS temporary credentials (e.g., direct S3 access from client). Steps:
CLI example (PowerShell):
aws cognito-identity create-identity-pool --identity-pool-name learninghub-identitypool --allow-unauthenticated-identities false --cognito-identity-providers ProviderName=cognito-idp.<region>.amazonaws.com/<USER_POOL_ID>,ClientId=<CLIENT_ID>
You’ll receive an IdentityPoolId; configure IAM roles and trust policies to allow the pool to assume roles.
If you use Identity Pool, create two roles: CognitoAuthRole (for authenticated users) and CognitoUnauthRole (for unauthenticated, if enabled). Attach minimal policies (S3 GetObject/PutObject if you use direct S3 uploads).
Lambda execution role: create an IAM role that allows Lambda to access S3, Secrets Manager, EC2 (via SSM) or other services required by your backend.
Example trust policy for a role assumed by Cognito identity pool (snippet):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {"Federated": "cognito-identity.amazonaws.com"},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {"cognito-identity.amazonaws.com:aud": "<IDENTITY_POOL_ID>"},
"ForAnyValue:StringLike": {"cognito-identity.amazonaws.com:amr": "authenticated"}
}
}
]
}
We use HTTP API (faster, lower-cost). Configure a JWT authorizer that validates Cognito tokens.
GET /courses, POST /exams). Attach integration.https://cognito-idp.<region>.amazonaws.com/<USER_POOL_ID>client_id as audience. Some setups use the user pool’s aud claim.https://<api-id>.execute-api.<region>.amazonaws.com).# create an HTTP API
$api=$(aws apigatewayv2 create-api --name learninghub-api --protocol-type HTTP --target arn:aws:lambda:<region>:<account-id>:function:YourFunction --output json)
$apiId=$(echo $api | ConvertFrom-Json).ApiId
# create JWT authorizer
aws apigatewayv2 create-authorizer --api-id $apiId --authorizer-type JWT --name CognitoJWTAuth --identity-source "$request.header.Authorization" --jwt-configuration "{\"Issuer\":\"https://cognito-idp.<region>.amazonaws.com/<USER_POOL_ID>\",\"Audience\":[\"<CLIENT_ID>\"]}"
Attach the authorizer to a route (replace routeId as necessary):
aws apigatewayv2 update-route --api-id $apiId --route-key "GET /courses" --authorization-type JWT --authorizer-id <AUTHORZER_ID>
Notes:
Authorization header: Authorization: Bearer <id_token>.id_token for user info (claims). Access tokens may also be acceptable depending on configuration.Add permission for API Gateway to invoke the Lambda:
aws lambda add-permission --function-name YourFunction --statement-id apigw-invoke --action lambda:InvokeFunction --principal apigateway.amazonaws.com --source-arn arn:aws:execute-api:<region>:<account-id>:${apiId}/*/*/*
If your frontend is hosted on https://learninghub.example.com, add CORS to your routes:
Access-Control-Allow-Origin header in integration responses.https://learninghub.example.com or * for quick demos (not recommended for production).CLI example (AdminInitiateAuth) to get tokens (PowerShell):
aws cognito-idp admin-initiate-auth --user-pool-id <USER_POOL_ID> --client-id <CLIENT_ID> --auth-flow ADMIN_NO_SRP_AUTH --auth-parameters USERNAME="testuser",PASSWORD="P@ssw0rd" --output json
Response contains AuthenticationResult.IdToken and AccessToken.
$token = "<ID_TOKEN_FROM_AUTH>"
Invoke-RestMethod -Method Get -Uri "https://<api-id>.execute-api.<region>.amazonaws.com/courses" -Headers @{ Authorization = "Bearer $token" }
If you receive 401: check authorizer configuration (issuer/audience), ensure token is not expired and your route has the authorizer attached.
Issuer URL exactly matches https://cognito-idp.<region>.amazonaws.com/<USER_POOL_ID> and Audience contains the client id used to get the token.add-permission invocation.Access-Control-Allow-Origin header.Resource ARNs in IAM policies in production.