Skip to main content

Using Lambda Authorizers

You can use a lambda as an Authorizer in API Gateways. This will enable you to use SuperTokens in a lambda to authorize requests to other integrations (e.g., AppSync). An Authorizer pointed to this lambda will add context.authorizer.principalId that you can map to a header. For example, you can map this to an "x-user-id" header which will be set to the id of the logged-in user. If there is no valid session for the request, this header won't exist.

1) Add configurations and dependencies#

Follow step 1 and step 2.

2) Create a new file index.js#

Use the code below as the handler for the lambda. Remember that whenever we want to use any functions from the supertokens-node lib, we have to call the supertokens.init function at the top of that serverless function file. We can then use getSession() to get the session.

import supertokens from "supertokens-node";import { SessionEvent } from "supertokens-node/framework/awsLambda";import { APIGatewayAuthorizerEvent, PolicyDocument, Statement, AuthResponse } from "aws-lambda";import Session from "supertokens-node/recipe/session";
import { getBackendConfig } from "./config";
type AuthorizerEvent = SessionEvent & APIGatewayAuthorizerEvent;
exports.handler = async function (event: AuthorizerEvent) {    try {        const session = await Session.getSession(event, event, { sessionRequired: false });        if (session) {            // We need to add setCookie to the context, since later we will be mapping this to a Set-Cookie header on the response            // getSession has to set cookies on the first call after a refresh.            return generateAllow(session.getUserId(), event.methodArn, {                setCookie: event.supertokens.response.cookies.join(', '),            });        } else {            // You can allow requests without sessions            return generateAllow("", event.methodArn, {                setCookie: event.supertokens.response.cookies.join(', '),            });            // You can also return explicit deny with additional context, but you should configure these as 401s so the frontend SDK can handle them.            // return generateDeny(undefined, event.methodArn);            // throw new Error("Unauthorized");        }    } catch (ex: any) {        if (ex.type === "TRY_REFRESH_TOKEN") {            throw new Error("Unauthorized");        }        throw ex;    }}
// Help function to generate an IAM policyconst generatePolicy = function (principalId: string, effect: string, resource: string, context?: any) {    // Required output:    const policyDocument: PolicyDocument = {        Version: '2012-10-17',        Statement: [],    };
    const statementOne: Statement = {        Action: 'execute-api:Invoke',        Effect: effect,        Resource: resource,    };
    policyDocument.Statement[0] = statementOne;
    const authResponse: AuthResponse = {        principalId: principalId,        policyDocument: policyDocument,        // Optional output with custom properties of the String, Number or Boolean type.        context,    };
    return authResponse;}
const generateAllow = function (principalId: string, resource: string, context?: any) {    return generatePolicy(principalId, 'Allow', resource, context);};
const generateDeny = function (principalId: string, resource: string, context?: any) {    return generatePolicy(principalId, 'Deny', resource, context);};

3) Configure the Authorizer#

  • Go to the "Authorizers" tab in the API Gateway configuration
  • Click "Create new Authorizer" and add the new Authorizer
    • Fill the name field
    • Set "Lambda function" to the one created above
    • Set "Lambda Event Payload" to Request
    • Delete the empty "Identity Source"
    • Click "Create"

4) Configure API Gateway#

  • In your API Gateway, create the resources and methods you require, enabling CORS if necessary (see step 4 for details)

  • Select each Method you want to enable the Authorizer on and configure it to use the new Authorizer

    • Click on "Method Request"

    • Edit the "Authorization" field in Settings and set it to the one we just created.

    • Go back to the method configuration and click on "Integration Request"

      • Set up the integration you require (see AppSync for an example)
      • Add a header mapping to make use of the context set in the lambda.
        • Open "HTTP Headers"
        • Add all headers required (e.g., "x-user-id" mapped to "context.authorizer.principalId")
        • Repeat for any values from the context you want to add as a Header
    • Go back to the method configuration and click on "Method Response"

      • Open the dropdown next to the 200 status code
      • Add the "Set-Cookie" header
      • Add any other headers that should be present on the response.
    • Go back to the method configuration and click on "Integration Response"

      • Open the dropdown
      • Open "Header Mappings"
      • Add "Set-Cookie" mapped to "context.authorizer.setCookie"
  • Deploy your API and test it