Using the API Gateway Authorizer with multi user-pools

biglucas

Lucas Ferreira

Posted on September 24, 2021

Using the API Gateway Authorizer with multi user-pools

Context

I've been working on a project with a multi-tenancy architecture, and during the refactor from single-tenant to multi-tenant, we had a problem with AWS Cognito and the AWS API Gateway Authorizer.

The problem was, we wanted to add multi Cognito User Pools to our Authorizer and use it to check the token in Cognito, something like this:

  • With SDK:
import { APIGateway } from 'aws-sdk';

const update_authorizer = async (apigateway: APIGateway, op: 'remove' | 'add') => {
    const params: APIGateway.Types.UpdateAuthorizerRequest = {
        authorizerId: 'x99xxx', /* required */
        restApiId: 'xxxx99xxxx', /* required */
        patchOperations: [ // adding all user pools to the same authorizer
            { // CognitoUserPoolTenantA
                op,
                path: '/providerARNs',
                value: 'arn:aws:cognito-idp:us-east-1:xxxxxxxxxxxx:userpool/us-east-1_xxxxxxxxx',
            },
            { // CognitoUserPoolTenantB
                op,
                path: '/providerARNs',
                value: 'arn:aws:cognito-idp:us-east-1:xxxxxxxxxxxx:userpool/us-east-1_yyyyyyyyy',
            },
            // and keep going adding new User Pools
        ],
    };
    await apigateway.updateAuthorizer(params).promise();
};

// calling the script
const apigateway = new APIGateway({ region: 'us-east-1' });
await update_authorizer(apigateway, 'add');
Enter fullscreen mode Exit fullscreen mode
  • With Cloud Formation:
Resources:
  ApiGatewayAuthorizer:
    DependsOn:
      - SharedApiGateway
    Type: AWS::ApiGateway::Authorizer
    Properties:
      Name: Authorizer
      IdentitySource: method.request.header.Authorization
      RestApiId:
        Ref: SharedApiGateway
      Type: COGNITO_USER_POOLS
      ProviderARNs:
        - Fn::GetAtt: ['CognitoUserPoolTenantA', Arn]
        - Fn::GetAtt: ['CognitoUserPoolTenantB', Arn]
        # keep going adding new User Pools in the file
        # or adding with the SDK.
Enter fullscreen mode Exit fullscreen mode

Problems during implementation

  • The API Authorizer has a default cache with the time for invalidation equal to 300 seconds. See more here.

  • After the changes made by the update_authorizer() function, we saw that the tokens were taking some time to work until we found the createDeployment() inside the AWS SDK for API Gateway.

Final solution

We had to add new functions to the same file where we wrote the first function (update_authorizer).

// ...
const release_api_deployment = async (apigateway: APIGateway) => {
    const params: APIGateway.Types.CreateDeploymentRequest = {
        restApiId: 'xxxx99xxxx', /* required */
        stageName: 'dev',
    };
    await apigateway.createDeployment(params).promise();
};

const flush_authorizers = async (apigateway: APIGateway) => {
    const params: APIGateway.Types.FlushStageAuthorizersCacheRequest = {
        restApiId: 'xxxx99xxxx', /* required */
        stageName: 'dev', /* required */
    };
    await apigateway.flushStageAuthorizersCache(params).promise();
};

// final call
const execute = async () => {
    const apigateway = new APIGateway({ region: 'us-east-1' });
    await update_authorizer(apigateway, 'remove');
    await flush_authorizers(apigateway); // clean cache
    await release_api_deployment(apigateway); // release a new version of the API

    // ... and to test the API we need to generate new tokens
};

try {
    execute();
} catch (error) {
    console.error(error);
}
Enter fullscreen mode Exit fullscreen mode

So with those scripts, we can update the API Gateway Authorizer to works with multi Cognito User Pools without implement a Custom Authorization Lambda.

💖 💪 🙅 🚩
biglucas
Lucas Ferreira

Posted on September 24, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related