Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Amazon Cognito App Client authorization
#!/usr/bin/env bash
# Discover Cognito User Pool and API Gateway params,
# authorize with Cognito App Client ID and Secret
# and make request to the API.
# set Cognito and API Gateway params
REGION="eu-west-1"
USER_POOL_NAME="apiAuth-dev"
CLIENT_NAME="MyServiceClient"
DOMAIN_PREFIX="example-apiauth-dev"
API_GATEWAY_NAME="apiAuth-dev"
echo "Getting Cognito User Pool ID..."
USER_POOL_ID=$(aws cognito-idp list-user-pools --max-results 50 | jq -r --arg USER_POOL_NAME "$USER_POOL_NAME" '.UserPools[] | select(.Name == $USER_POOL_NAME).Id')
echo "Getting Cognito User Pool domain prefix..."
DOMAIN_PREFIX=$(aws cognito-idp describe-user-pool --user-pool-id "$USER_POOL_ID" | jq -r '.UserPool.Domain')
echo "Getting Cognito User Pool Client ID..."
CLIENT_ID=$(aws cognito-idp list-user-pool-clients --user-pool-id "$USER_POOL_ID" | jq -r --arg CLIENT_NAME "$CLIENT_NAME" '.UserPoolClients[] | select(.ClientName == $CLIENT_NAME).ClientId')
echo "Getting Cognito User Pool Client Secret..."
CLIENT_SECRET=$(aws cognito-idp describe-user-pool-client --user-pool-id "$USER_POOL_ID" --client-id "$CLIENT_ID" | jq -r '.UserPoolClient.ClientSecret')
echo "Authorizing App Client..."
ACCESS_TOKEN=$(curl -s -X POST -H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=client_credentials&client_id=$CLIENT_ID&client_secret=$CLIENT_SECRET" \
"https://$DOMAIN_PREFIX.auth.eu-west-1.amazoncognito.com/oauth2/token" | jq -r '.access_token')
echo "Getting API Gateway ID..."
API_GATEWAY_ID=$(aws apigateway get-rest-apis | jq -r --arg API_GATEWAY_NAME "$API_GATEWAY_NAME" '.items[] | select(.name == $API_GATEWAY_NAME).id')
API_GATEWAY_DOMAIN="$API_GATEWAY_ID.execute-api.$REGION.amazonaws.com"
echo "Making request to API Gateway..."
curl -X GET -H "Authorization: Bearer $ACCESS_TOKEN" "https://$API_GATEWAY_DOMAIN/v1/"
service: apiAuth
custom:
oauth:
resourceServerId: com.example
readScope: read
provider:
name: aws
region: ${opt:region, 'eu-west-1'}
stage: ${opt:stage, 'dev'}
resources:
Resources:
# API GATEWAY
ApiGateway:
Type: AWS::ApiGateway::RestApi
Properties:
Name: ${self:service}-${self:provider.stage}
ApiGatewayGet:
Type: AWS::ApiGateway::Method
Properties:
RestApiId: !Ref ApiGateway
ResourceId: !GetAtt ApiGateway.RootResourceId
HttpMethod: GET
AuthorizationType: COGNITO_USER_POOLS
AuthorizerId: !Ref ApiCognitoAuthorizer
AuthorizationScopes:
- ${self:custom.oauth.resourceServerId}/${self:custom.oauth.readScope}
Integration:
Type: MOCK
IntegrationResponses:
- SelectionPattern: 2\d{2}
StatusCode: 200
ResponseTemplates:
application/json: "{\"message\": \"Hello!\"}"
PassthroughBehavior: WHEN_NO_TEMPLATES
RequestTemplates:
application/json: "{\"statusCode\": 200}"
MethodResponses:
- StatusCode: 200
ApiCognitoAuthorizer:
Type: AWS::ApiGateway::Authorizer
Properties:
Name: CognitoAuthorizer
RestApiId: !Ref ApiGateway
Type: COGNITO_USER_POOLS
IdentitySource: method.request.header.Authorization
ProviderARNs:
- !GetAtt UserPool.Arn
ApiGatewayStage:
Type: AWS::ApiGateway::Stage
Properties:
StageName: v1
RestApiId: !Ref ApiGateway
DeploymentId: !Ref ApiGatewayDeployment
# API deployment is done only on the first deployment!
# After making changes in resources, change this resource name to force new deployment.
ApiGatewayDeployment:
Type: AWS::ApiGateway::Deployment
DependsOn: ApiGatewayGet
Properties:
RestApiId: !Ref ApiGateway
# COGNITO
UserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: ${self:service}-${self:provider.stage}
MyServiceClient:
Type: AWS::Cognito::UserPoolClient
DependsOn:
- UserPoolResourceServer
Properties:
ClientName: MyServiceClient
UserPoolId: !Ref UserPool
GenerateSecret: true
AllowedOAuthFlowsUserPoolClient: true
AllowedOAuthFlows:
- client_credentials
AllowedOAuthScopes:
- ${self:custom.oauth.resourceServerId}/${self:custom.oauth.readScope}
UserPoolResourceServer:
Type: AWS::Cognito::UserPoolResourceServer
Properties:
Name: Example
UserPoolId: !Ref UserPool
Identifier: ${self:custom.oauth.resourceServerId}
Scopes:
- ScopeName: ${self:custom.oauth.readScope}
ScopeDescription: Read
UserPoolDomain:
Type: AWS::Cognito::UserPoolDomain
Properties:
UserPoolId: !Ref UserPool
Domain: example-apiauth-${self:provider.stage} # make it unique
@m-radzikowski
Copy link
Author

m-radzikowski commented May 24, 2021

  1. Deploy Serverless Framework stack with sls deploy
  2. Update params in the bash script if needed
  3. Run script to fetch required params, authorize in Cognito with Client ID and Secret, and make a request to API Gateway

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment