# Session Verification

Verify user sessions when integrating SuperTokens with AWS Lambda.

The following page shows three ways to verify sessions in a Lambda integration. Choose the one that works best based on the particularities of your use case.

## Using Session Verification

When building your own APIs, you may need to verify the session of the user before proceeding further. SuperTokens SDK exposes a `verifySession` function that can be utilized for this. In this guide, we will be creating a `/user` GET route that will return the current session information.

### 1. Add `/user` GET route in your API Gateway

Create a `/user` resource and then `GET` method in your API Gateway. Configure the lambda integration and CORS just like we did [for the auth routes](/content/docs/integrations/aws-lambda/quickstart-guide#13-attach-lambda-to-the-any-method-of-the-proxy-resource/index.html).

### 2. Create a file in your Lambda function to handle the `/user` route

Node.js

An example of this is [here](https://github.com/supertokens/supertokens-node/blob/master/examples/aws/with-emailpassword/backend/user.mjs).

```javascript
import supertokens from "supertokens-node";
import { getBackendConfig } from "./config.mjs";
import { verifySession } from "supertokens-node/recipe/session/framework/awsLambda";
import middy from "@middy/core";
import cors from "@middy/http-cors";

supertokens.init(getBackendConfig());

const lambdaHandler = async (event) => {
  return {
    body: JSON.stringify({
      sessionHandle: event.session?.getHandle(),
      userId: event.session?.getUserId(),
      accessTokenPayload: event.session?.getAccessTokenPayload(),
    }),
    statusCode: 200,
  };
};

export const handler = middy(verifySession(lambdaHandler))
  .use(
    cors({
      origin: getBackendConfig().appInfo.websiteDomain,
      credentials: true,
      headers: ["Content-Type", ...supertokens.getAllCORSHeaders()].join(", "),
      methods: "OPTIONS,POST,GET,PUT,DELETE",
    }),
  )
  .onError((request) => {
    throw request.error;
  });
```

### Using Lambda Authorizers

You can use a Lambda authorizer with an API Gateway REST API to authorize requests to another integration, such as AppSync. The authorizer below requires a valid session and returns its user ID as `principalId`. API Gateway can map `$context.authorizer.principalId` to an integration header. Missing and invalid sessions are rejected; this guide does not claim support for optional sessions because AWS’s behavior for an empty principal is not established here.

### 1. Add configurations and dependencies

Refer to the [frontend](/content/docs/quickstart#1-integrate-the-frontend-sdk/index.html), [lambda layer](/content/docs/integrations/aws-lambda/quickstart-guide#2-set-up-lambda-layer/index.html), and [lambda setup](/content/docs/integrations/aws-lambda/quickstart-guide#3-set-up-lambda/index.html).

### 2. Add code to the lambda function handler

Python

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

Node.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.

```javascript
import supertokens from "supertokens-node";
import Session from "supertokens-node/recipe/session";
import { getBackendConfig } from "./config.mjs";

supertokens.init(getBackendConfig());

export const handler = async function (event) {
  try {
    const session = await Session.getSession(event, event);
    return generateAllow(session.getUserId(), event.methodArn);
  } catch (ex) {
    if (ex.type === "TRY_REFRESH_TOKEN" || ex.type === "UNAUTHORISED") {
      throw new Error("Unauthorized");
    }
    if (ex.type === "INVALID_CLAIMS") {
      return generateDeny("invalid-claims", event.methodArn, {
        body: JSON.stringify({
          message: "invalid claim",
          claimValidationErrors: ex.payload,
        }),
      });
    }
    throw ex;
  }
};

const generatePolicy = function (principalId, effect, resource, context = {}) {
  const policyDocument = {
    Version: "2012-10-17",
    Statement: [],
  };

const statementOne = {
    Action: "execute-api:Invoke",
    Effect: effect,
    Resource: resource,
  };

policyDocument.Statement[0] = statementOne;

const authResponse = {
    principalId: principalId,
    policyDocument: policyDocument,
    context,
  };

return authResponse;
};

const generateAllow = function (principalId, resource, context) {
  return generatePolicy(principalId, "Allow", resource, context);
};

const generateDeny = function (principalId, resource, context) {
  return generatePolicy(principalId, "Deny", resource, context);
};
```

### 3. Configure the authorizer

Create a request-based Lambda authorizer for the REST API and point it to the function above. AWS changes console labels; capture this configuration in IaC and verify that the deployed authorizer receives the headers and cookies required by your selected SuperTokens token-transfer method.

### 4. Configure API Gateway

- Require the authorizer on each protected method.
- In the integration request, overwrite `x-user-id` from `context.authorizer.principalId`. Never forward a client-supplied identity header.
- If the browser must read gateway-generated `401` or `403` responses, configure them with the exact trusted `Access-Control-Allow-Origin` and `Access-Control-Allow-Credentials: true`. Do not combine credentials with a wildcard origin.
- Deploy and test the API. The IaC fixture must prove that a spoofed identity header cannot reach the integration.

## Using JWT Authorizers

### 1. Add the `aud` claim in the JWT based on the authorizer configuration

Node.js

```javascript
import Session from "supertokens-node/recipe/session";

export function getBackendConfig() {
  return {
    framework: "awsLambda",
    supertokens: {
      connectionURI: "<CORE_API_ENDPOINT>",
    },
    appInfo: {
      appName: "<YOUR_APP_NAME>",
      apiDomain: "<YOUR_API_DOMAIN>",
      websiteDomain: "<YOUR_WEBSITE_DOMAIN>",
      apiBasePath: "/auth",
      websiteBasePath: "/auth",
      apiGatewayPath: "/dev",
    },
    recipeList: [
      Session.init({
        exposeAccessTokenToFrontendInCookieBasedAuth: true,
        override: {
          functions: function (originalImplementation) {
            return {
              ...originalImplementation,
              createNewSession: async function (input) {
                input.accessTokenPayload = {
                  ...input.accessTokenPayload,
                  aud: "jwtAuthorizers",
                };
                return originalImplementation.createNewSession(input);
              },
            };
          },
        },
      }),
    ],
    isInServerlessEnv: true,
  };
}
```

### 2. Configure your authorizer

- Go to the “Authorizers” tab in the API Gateway configuration and select the “Manage authorizers” tab
- Click “Create”, in the creation screen select “JWT” as the “Authorizer type”
- Enter a name for your authorizer (You can enter any name for this field)
- Use `$request.header.Authorization` for the “Identity source”. This means that API requests will contain the JWT as a Bearer token under the request header “Authorization”.
- Use the exact normalized issuer emitted by SuperTokens for this configuration: `<YOUR_API_DOMAIN>/dev/auth`. This is `apiDomain + apiGatewayPath + apiBasePath`, with one slash at each boundary.
- Set a value for the “Audience” field, this will be the value you expect the JWT to have under the `aud` claim. In the backend config above the value is set to `"jwtAuthorizers"`

### 3. Add the authorizer to your API

- In the “Authorization” section select the “Attach authorizers to routes” tab
- Click on the route you want to add the authorizer to and select the authorizer you created from the dropdown
- Click “Attach authorizer”
- Deploy your changes and test your API

### 4. Send the access token as a bearer token

Exposing the access token does not automatically copy it to the JWT authorizer’s identity source in cookie-based auth. Set the header explicitly on requests to protected routes:

```javascript
import Session from "supertokens-web-js/recipe/session";

async function fetchProtectedUser() {
  const accessToken = await Session.getAccessToken();

if (accessToken === undefined) {
    throw new Error("No session access token is available");
  }

return fetch("<YOUR_API_DOMAIN>/dev/user", {
    headers: {
      Authorization: `Bearer ${accessToken}`,
    },
  });
}
```

### 5. Check authorization claims in the JWT

Once the JWT authorizer successfully validates the JWT, the claims of the JWT will be available to your lambda functions via `$event.requestContext.authorizer.jwt.claims`. You should check for the right authorization access here.
