> For AI agents: [llms.txt](https://docs.trustedauth.com/llms.txt) provides a Markdown index of this documentation.

# Protect AWS API Gateway

warning

Please note that this guide applies specifically to the AWS **REST** API Gateway. If You are using the AWS **HTTP** API Gateway, you can use the [built-in authorizer](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-jwt-authorizer.html).

Secure your AWS API Gateway endpoints using a custom Lambda authorizer that
accepts OIDC access tokens. To do this, you configure your API with API Gateway,
create and configure your AWS Lambda functions (including the lambda authorizer)
to secure your API endpoints, and implement the authorization flow so that your
users can retrieve the access tokens needed to gain access to your API from
IDaaS.

![OIDC Architecture Diagram](/assets/images/oidc-architecture-87ea5094c843d48bd5d9fd1a5233ef90.png)

To learn more, visit [AWS Lambda Overview](https://aws.amazon.com/lambda/) once
you log into your [AWS API Gateway](https://aws.amazon.com/api-gateway/).

The API Gateway extends the capabilities of Lambda by adding a service layer in
front of your Lambda functions to extend security, manage input and output
message transformations, and provide capabilities like throttling and auditing.
A serverless approach simplifies your operational demands since concerns like
scaling out and fault tolerance are now the responsibility of the compute
service that is executing your code.

The lambda authorizer will:

- Confirm that the access token has been passed via the authorization header of
  the request to access the API in the form `Bearer <token>`.
- Verify the RS256 signature of the Access Token using a public key obtained via
  a JWKS endpoint.
- Ensure the access token has the required Issuer `iss` and audience `aud` claims and is not expired.

## Quick Start

info

This assumes that you are familiar with AWS Lambda and API Gateway
configuration. If you are not, refer to the detailed guide below.

Steps to protect a resource using AWS REST API Gateway lambda authorizer with
IDaaS OIDC:

1. Create an OIDC application in IDaaS

2. Create a new API/URL in IDaaS to define your protected resource/audience

3. Upload [this sample lambda authorizer](https://github.com/EntrustCorporation/aws-api-gateway-authorizer-sample) to a new AWS Lambda, and configure the `ISSUER`, `JWKS_URI`, and `AUDIENCE` environment variables:

   | Parameter  | Value                                                                                                                                                                      |
   | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
   | `ISSUER`   | The issuer of the token. If IDaaS is the token issuer, use `https://{yourIdaasDomain}/api/oidc`.                                                                           |
   | `JWKS_URI` | The URL of the JWKS endpoint. If IDaaS is the token issuer, use `https://{yourIdaasDomain}/api/oidc/jwks`.                                                                 |
   | `AUDIENCE` | The URL of the domain of the endpoint you are trying to secure. E.g. `https://{yourApiGateway}`. This should be the same address as the API/URL defined in IDaaS (Step 2). |

4. Configure your API Gateway to use the new Lambda as a `Token` authorizer
   using the `Authorization` header as the source

5. Configure any endpoints in your API Gateway that need to be protected to use
   the lambda authorizer

## How API Gateway Lambda Authorizers Work

An API Gateway lambda authorizer is a Lambda function you provide to control
access to your API using bearer token authentication strategies, such as OAuth
or SAML.

Whenever a person or a machine attempts to call your API, API Gateway checks to
see if There is a lambda authorizer configured for the API.

If **there is a lambda authorizer for the API**, API Gateway calls the lambda
authorizer and provides the authorization token extracted from the request
header received.

You can use the lambda authorizer to implement different types of authorization
strategies, including JWT verification, to return IAM policies authorizing the
request. If the policy returned is invalid or if the permissions are denied, the
API call fails.

For a valid policy, API caches the returned policy, associating it with the
incoming token and using it for the current and subsequent requests. You can
configure the amount of time for which the policy is cached. The default value
is 300 seconds and the maximum length of caching is 3600 seconds (you can also
set the value to 0 to disable caching).

To read more, visit [What is Amazon API Gateway?](https://docs.aws.amazon.com/apigateway/latest/developerguide/welcome.html) in the Amazon Developer's Guide.

## Prerequisites

You need to [sign up for an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html).
This grants you access to the AWS features, including API Gateway and Lambda.
All new members receive twelve months of free tier access to AWS. You will also
need to [create and configure an IDaaS OIDC application.](/docs/applications-and-sso/oidc/protecting-spa.md)

## Import and deploy the AWS API Gateway API

This portion of the tutorial has been adapted from the [official AWS example](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-create-api-from-example.html).
Please refer to this example for in-depth notes and discussion.

In this step, you will:

- Import an API into API Gateway
- Test an API import
- Deploy an API for use with any front-end applications
- Test an API deployment

### Import and configure the Pets API

1. Log in to your AWS account, and using the **Services** drop-down located in
   the top navigation bar, go to the **API Gateway** Console.

2. If You have previously created an API, simply navigate to the API Gateway
   Console and click **Create API**. You will be given the option to create the **Example API** on the Create new API form. If You have never created an API
   using API Gateway, click **Get Started with API Gateway** to proceed.

   You will see a pop-up message welcoming you to API Gateway. Click **OK** to proceed.

3. Select the **Create API** button in the top right. You will be prompted to
   select an API type. Select **Build** under **REST API**. See the difference
   between the REST API and HTTP API types [here](https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-vs-rest.html).

4. On the **Create REST API** form, select the **Example API**. We will use this
   API for the rest of the tutorial, so begin the API creation process by
   clicking **Create API**.

   ![AWS Create REST API form](/assets/images/aws-create-rest-api-3ba850c5eba9ab7bc293f97b1d3bf355.png)

   When done, AWS displays a message indicating that your API created and populated with the provided data. Notice the API
   already has methods associated with it (namely, `GET` and `POST`). You can view the details of a method, modify its
   configuration, or test the method invocation by clicking the method name from the resource tree.

   ![AWS API Resources](/assets/images/aws-api-resources-63195c950d2b506486a8660e13cfa8aa.png)

### Test your API

To test your API, click **POST** under `/pets`. This brings up the **Method
Execution** window that provides an overview of the `POST` method's structure
and behaviors:

- **Method Request** and **Method Response**: the API's interface with the
  front-end
- **Integration Request** and **Integration Response**: the API's interface with
  the back-end
- **Test**: send test requests to your API

We can use this area to test the API.

1. Click **Test** (shown on the **Client** sliver located in the middle of the
   page). You will be redirected to the `/pets POST` test form. Scroll to the
   bottom of the page, and provide the following snippet as the **Request
   Body**:

   ```json
   {
     "type": "dog",
     "price": 249.99
   }
   ```

   The request body indicates the attributes of the pet we want to add to the database, as well as the cost for the pet.

   ![AWS Test endpoint form](/assets/images/aws-api-test-887f4433d11a51f0262f21de561d0aa6.png)

2. Click **Test** to proceed. You will see the results of the test at the bottom
   of the page.

   ![AWS API test results](/assets/images/aws-api-test-results-1606eed25306cb11e60434871acd53c9.png)

### Deploy the API

The test we just completed was done using the API Gateway console. To use the
API with a different application, You will need to deploy the API to a stage.

1. At the top right of the screen, select **Deploy API**.
2. Provide the following values, and click **Deploy**:

| Parameter              | Value                                         |
| ---------------------- | --------------------------------------------- |
| Stage                  | Choose `New Stage`                            |
| Stage name             | Provide a name for your stage                 |
| Deployment description | Provide a description for your API deployment |

### Test the deployment

When the API has successfully deployed, You will be redirected to the **Stage
Overview**. You can, at this point, test the API to see if it deployed
correctly.

1. In the middle of the window is your **Invoke URL**. This is the URL used to
   invoke the `GET` endpoint of your API. Copy the link into a new tab to
   submit the `GET /` method request in a browser. This should result in the
   following success response:

   ![AWS GET Petstore results](/assets/images/aws-get-petstore-b78a6de9b1e4c450c8e48432eec023cb.png)

2. In the **Stages** page, expand the tree under the stage you created. Click **GET** under `/pets/{petId}`.

   ![AWS GET individual pet method ARN](/assets/images/aws-api-method-arn-edce941da7c27f0c185004d6e269b09e.png)

3. You will see an **Invoke URL** displayed in the middle of the screen. The
   final portion, `{petID}`, stands for a path variable. Replace this variable
   with `1`, and navigate to the new URL using your browser. You should receive
   an HTTP 200 response with the following JSON payload:

   ```json
   {
     "id": 1,
     "type": "dog",
     "price": 249.99
   }
   ```

## Create the lambda authorizers

Now that we have a fully functional API That is managed by API Gateway, secure
this API so only those with the appropriate authorization may access the
back-end behind the API.

Use API Gateway's custom request authorizers to authorize your APIs using bearer
token authorization strategies, such as OAuth 2.0 or SAML. For each incoming
request, the following happens:

1. API Gateway checks for a properly-configured lambda authorizer.
2. API Gateway calls the lambda authorizer (which is a Lambda function) with the
   authorization token.
3. If the authorization token is valid, the lambda authorizer returns the
   appropriate AWS Identity and Access Management (IAM) policies.
4. API Gateway uses the policies returned in step 3 to authorize the request.

### Prepare the lambda authorizer

You can [download a sample lambda authorizer](https://github.com/EntrustCorporation/aws-api-gateway-authorizer-sample) that supports IDaaS OIDC tokens. Afterward, You will need to customize the files
so that the lambda authorizer works for your environment.

1. Unzip the folder containing the sample files you downloaded above to the
   location of your choice, and navigate to the folder using the command line.

2. Within the sample folder, run `bun install` to install the Node.js packages
   required for deployment; AWS requires that these files be included in the
   bundle you will upload to AWS during a later step.

3. Configure your local environment with a `.env` file. You can copy the `.sample-env` file (while simultaneously renaming it `.env`) using `cp .sample-env .env`. Make the following changes:

   | Parameter                                                                                | Value                                                                                                      |
   | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- |
   | `ISSUER`                                                                                 | The issuer of the token. If IDaaS is the token issuer, use `https://{yourIdaasDomain}/api/oidc`.           |
   | `JWKS_URI`                                                                               | The URL of the JWKS endpoint. If IDaaS is the token issuer, use `https://{yourIdaasDomain}/api/oidc/jwks`. |
   | `AUDIENCE`                                                                               | The URL of the domain of the endpoint you are trying to secure. E.g. `https://{yourApiGateway}`.           |
   | As an example, the text of your .env file should look something like this when complete: |

   ```bash
   JWKS_URI=https://{yourIdaasDomain}/api/oidc/jwks
   AUDIENCE=https://{yourApiGateway}
   ISSUER=https://{yourIdaasDomain}/api/oidc
   ```

### Test the lambda authorizer locally

Obtain a valid JWT access token from IDaaS for the relevant audience. There are
multiple ways you can get one and the method you choose depends on your
application's type, trust level, or overall end-user experience.

Create a local `event.json` file containing the token. You can copy the sample
file (run `cp sample-event.json event.json`). Add your JWT token to `authorizationToken`. You can also replace `methodArn` with a method ARN of your
API that you intend to protect (optional for local tests).

To get the `methodArn`:

1. Using the API Gateway Console, open the **PetStore** API.
2. In the middle **Resources** panel, expand the resource tree. Underneath
   `/pets`, select **GET**.
3. In the **Method Execution** box, You will see the **ARN**.
4. Run the test using `bun run test`.

The test uses the lambda-local package to test the lambda authorizer using your
token. If the test was successful, You will see output similar to the following:

```bash
info: START RequestId: 3df095ef-8876-c996-919f-cca592e01a62
info: End - Result:
info: {
        "principalId": "userId",
        "policyDocument": {
                "Version": "2012-10-17",
                "Statement": [
                        {
                                "Action": "execute-api:Invoke",
                                "Effect": "Allow",
                                "Resource": "arn:aws:execute-api:us-east-1:1234567890:apiId/stage/method/resourcePath"
                        }
                ]
        }
}
info: Lambda successfully executed in 316ms.
```

If the value of `Effect` is `Allow`, your authorizer Would have allowed the call
to API Gateway.

To learn more, visit [Lambda-local](https://www.npmjs.com/package/lambda-local) at NPM.

### Create the Lambda function and deploy the lambda authorizer

Now that You have configured your lambda authorizer for your environment and
tested it to see it works, deploy it to AWS.

1. Create a bundle that you can upload to AWS by running `bun run bundle`. This
   generates a `token-authorizer.zip` bundle containing the source,
   configuration, and node modules required by AWS Lambda.

2. Navigate to the [Lambda console](https://console.aws.amazon.com/lambda), and
   click **Create function**.

3. The default should be **Author from scratch** to create a blank function.
   Under **Basic information**, provide values for the following parameters:

   | Parameter     | Value                                                          |
   | ------------- | -------------------------------------------------------------- |
   | Function Name | A name for your Lambda function, such as `jwtCustomAuthorizer` |
   | Runtime       | Select `Node.js 20.x`                                          |

4. Click **Create Function** to continue.

5. On the **Code** page of your function, select the **Upload From** dropdown
   menu and select **.zip file**.

6. Click **Upload** and select the `token-authorizer.zip` bundle you created
   earlier.

7. Then create the following three **Environment variables**. Note that this
   information is identical to the contents of `.env` file:

   | Parameter  | Value                                                                                                      |
   | ---------- | ---------------------------------------------------------------------------------------------------------- |
   | `ISSUER`   | The issuer of the token. If IDaaS is the token issuer, use `https://{yourIdaasDomain}/api/oidc`.           |
   | `JWKS_URI` | The URL of the JWKS endpoint. If IDaaS is the token issuer, use `https://{yourIdaasDomain}/api/oidc/jwks`. |
   | `AUDIENCE` | The URL of the domain of the endpoint you are trying to secure. E.g. `https://{yourApiGateway}`.           |

8. To test the Lambda function you just created, click the **Test** tab.

9. Copy the contents of your `event.json` file into the **Event JSON** form. You
   can use the default "Hello World" event template. The methodArn _must_ be set
   to a valid method ARN in your gateway.

10. Click **Save**.

11. Run your test by selecting it and clicking **Test**. If the test was
    successful, You will see: "Execution result: succeeded". Expanding the output
    window should show a message similar to the one you received after your
    successful local test.

### Configure API Gateway lambda authorizer

1. Return to API Gateway Console and open the **PetStore** API we created
   earlier.

2. Using the left-hand navigation, open **Authorizers** and select **Create an
   Authorizer**, then set the following parameters, and click **Create
   authorizer**.

   | Parameter            | Value                      |
   | -------------------- | -------------------------- |
   | Authorizer Name      | `jwt-custom-authorizer`    |
   | Type                 | Select **Lambda**          |
   | Lambda Function      | jwtRsaCustomAuthorizer     |
   | Lambda Event Payload | Select **Token**           |
   | Token Source         | `Authorization`            |
   | Token Validation     | `^Bearer [-0-9a-zA-z\.]*$` |
   | TTL (seconds)        | `3600`                     |

3. After AWS creates the authorizer and the page refreshes, test your authorizer
   by clicking **Test** and providing the Access token (`Bearer ey...`) you
   previously used. If the test was successful, You will see a response similar to
   the following.

```bash
200
Policy
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action: "execute-api:Invoke",
            "Effect": "Allow",
            "Resource": "arn:aws:execute-api:us-east-1:1234567890:apiId/stage/method/resourcePath"
        }
    ]
}

Log
Execution log for ...
```

## Secure the API using Lambda authorizers

To learn how to secure your API's endpoints, see the Amazon API Gateway
developer guide article: [Use API Gateway Lambda Authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html).

### Configure API Gateway resources to use the lambda authorizer

1. Log in to AWS, and navigate to the [API Gateway Console](http://console.aws.amazon.com/apigateway). Custom
   authorizers are set on a method by method basis; if you want to secure
   multiple methods using a single authorizer, You will need to repeat the
   following instructions for each method.

2. Open the **PetStore** API we created in step 2 of this tutorial. Under the **Resource** tree in the center pane, select the **GET** method under the `/pets` resource:

   ![AWS Configure Method Authorizer](/assets/images/aws-configure-authorizer-49f1f7d9ba3722be50aa96c9a8edea38.png)

3. Select **Method Request**.

4. Click **Edit** on the right hand side and under **Authorization** choose the `jwt-custom-authorizer` custom authorizer you created in step 3.

5. Click **save** to save your choice of lambda authorizer. Make sure the **API
   Key Required** field is set to `false`.

### Deploy the API

To make your changes public, deploy your API.

1. At the top right of the screen, select **Deploy API**.
2. Provide the following values, and click **Deploy** and choose the stage you
   created previously.

If successful, You will be redirected to the **Stage Overview**. Note the **Invoke
URL** provided under the **Stage Details** because you need this to test your
deployment.

### Test your deployment

To test your deployment, make a `GET` call to the **Invoke URL** you noted in
the previous step. If this test fails, check that you obtained the JWT access
token correctly.
