Secure Your API with Authentication

Add API keys, usage plans, and a Lambda authorizer to your REST API.

Introduction

30 Second Summary

Think about how streaming services check your subscription before playing a single frame of video. Every request is verified before anything loads. APIs need the same kind of gatekeeper to block unauthorized access and prevent abuse.

In this project, you will secure your Lead Intake API with API keys and rate limiting so that only identified callers can submit data, and no single caller can overwhelm your system.

What You'll Build

A secured version of your Lead Intake API with two layers of access control: API keys for caller identification and usage plans for rate limiting, tested through organized Postman collections.

By the end of this project, you'll have:

  • An API key attached to your POST /leads endpoint that rejects unauthenticated requests at the gateway level before they reach your Lambda function.
  • A usage plan with rate limiting and monthly quotas that mirrors how production SaaS platforms manage API access.
  • An organized Postman test folder demonstrating valid key, missing key, and invalid key scenarios with environment variables.
  • Secret Mission: Build a Lambda authorizer that validates bearer tokens and returns IAM policy documents, demonstrating the difference between API keys and real authentication.

Are there any prerequisites?

Yes. This project builds directly on your existing Lead Intake API from Project 1 (Build a Serverless Lead Intake API). You need a working LeadIntakeAPI deployed to a dev stage, a LeadIntakeFunction Lambda function, a Leads DynamoDB table, and a Postman workspace with your test collection.

If you have not completed Project 1, finish that first. This project picks up exactly where that one left off.

Create an API Key and Require It on Your Endpoint

Your Lead Intake API is live and accepting requests from anyone who knows the URL. In production, that's a problem. You need a way to identify who's calling your API and control how much they can use it.

API keys are the first layer of access control. They work like building keycards. They identify the caller and let you set usage limits, but they don't verify identity like a password would.

In this step, get ready to:
  • Create an API key in API Gateway.
  • Require the API key on your POST /leads method.
  • Deploy and verify that unauthorized requests are now rejected.
Create your API key in API Gateway

Every caller to your API needs a unique key. You'll create one now so API Gateway can track who's making requests.

  • In the AWS Management Console, navigate to the API Gateway service.
  • Select your LeadIntakeAPI from the APIs list.
  • In the main navigation pane, choose API keys.
  • Choose Create API key.
  • For Name, enter LeadIntakeKey.
  • For API key, choose Auto generate.
  • Choose Save.
  • Copy the generated API key value and save it somewhere accessible (a text file or sticky note on your desktop).

What is an API key?

An API key is a long, randomly generated string that identifies who is calling your API. Think of it as a membership card at a library. It tells the system who you are, but it doesn't prove you're authorized to access restricted sections.

AWS explicitly states: "Don't use API keys for authentication or authorization to control access to your APIs." API keys handle identification and throttling. Actual authentication requires something stronger, like a Lambda authorizer (which you'll build in the Secret Mission).

Don't see the API key value?

After saving, the key value should appear on the API key detail page. If you navigated away before copying it, go back to API keys in the navigation pane, select LeadIntakeKey, and the value will be visible there.

help me find my API key value in the API Gateway console

Require the API key on your POST method

Creating the key alone doesn't protect anything. You need to tell API Gateway that your POST /leads method should reject requests that don't include a valid key.

  • In the main navigation pane, choose Resources.
  • Select the /leads resource in the resource tree.
  • Select the POST method.
  • On the Method request tab, under Method request settings, choose Edit.
  • Set API key required to true.
  • Choose Save.

Why does this setting matter?

Setting API key required to true tells API Gateway to check for a valid x-api-key header on every incoming request. If the header is missing or contains an invalid key, API Gateway immediately returns a 403 Forbidden response without ever invoking your Lambda function.

This is called gateway-level rejection. It saves you compute costs because bad requests never reach your function.

Deploy and verify the key is required

Changes to method settings don't go live until you redeploy the API. You'll deploy now and then confirm that requests without a key are rejected.

  • In the Resources pane, choose Deploy API.
  • For Stage, select your existing dev stage from the dropdown.
  • Choose Deploy.

Why redeploy?

API Gateway treats each deployment as a snapshot of your API's configuration. When you changed the API key required setting, that update only exists in your working copy until you deploy it. Redeploying pushes your changes live to the dev stage.

Now confirm that your API rejects requests without a key.

  • Switch to Postman.
  • Open your existing POST request to the /leads endpoint (from your Lead Intake API Tests collection).
  • Make sure there is no x-api-key header set on the request.
  • Click Send.
  • Confirm you receive a 403 Forbidden response.

Still seeing 200 OK instead of 403?

If your request still succeeds without an API key, double-check two things. First, confirm you selected API key required = true on the POST method and saved. Second, make sure you redeployed to the dev stage after saving the method settings.

Changes may take a minute or two to propagate. Wait 30 seconds and try sending the request again.

help me troubleshoot why my API still returns 200 without an API key after I set API key required to true

Your endpoint is now locked down. Any request without a valid x-api-key header gets rejected before it ever reaches your Lambda function. Next up, you'll create a usage plan that attaches rate limits and quotas to your key.

Create a Usage Plan and Attach Your Key

Your API key is now blocking unauthorized requests at the gateway level. Next, you'll control how much an authorized caller can use your API.

Without limits, a single caller could flood your API with thousands of requests per second. A usage plan sets rate limits and quotas on API keys, which is exactly how SaaS platforms prevent one customer from overwhelming shared infrastructure.

In this step, get ready to:
  • Create a usage plan with rate limiting and a monthly request quota.
  • Associate your API stage and API key with the plan.
Create the usage plan

A usage plan ties together three settings: how fast requests can come in (rate), how many can burst at once, and the total allowed per month (quota).

  • In the API Gateway main navigation pane, choose Usage plans.
  • Choose Create usage plan.
  • For Name, enter LeadIntakePlan.
  • Set Rate to 5 requests per second.
  • Set Burst to 10.
  • For Requests (quota), enter 1000 per Month.
  • Choose Create usage plan.

What do rate, burst, and quota mean?

  • Rate is the steady-state number of requests per second your API allows from a single key.
  • Burst is the maximum number of concurrent requests API Gateway buffers during a short traffic spike.
  • Quota is the total number of requests an API key can make within the time period you set (in this case, 1000 per month).
Associate your API stage

The usage plan needs to know which deployed API stage it applies to.

  • Under the Associated stages tab, choose Add stage.
  • For API, select LeadIntakeAPI.
  • For Stage, select dev.
  • Choose Add to usage plan.

Why associate a stage?

A usage plan can cover multiple APIs and stages. By associating only the dev stage, your rate limiting settings apply specifically to that deployment without affecting other stages you might create later (like a production stage).

Attach your API key to the plan

The final connection links your specific API key to the usage plan so that its rate and quota limits apply to requests made with that key.

  • Under the Associated API keys tab, choose Add API key.
  • Select Add existing key.
  • Choose LeadIntakeKey from the dropdown.
  • Choose Add API key.

You should now see LeadIntakeAPI/dev listed under Associated stages and LeadIntakeKey listed under Associated API keys.

Are these limits hard or soft?

Usage plan throttling and quotas are not hard limits. They are applied on a best-effort basis, meaning clients may occasionally exceed the quotas you set.

For cost control and hard blocking, AWS recommends using AWS Budgets and AWS WAF alongside usage plans. For this project, best-effort throttling is more than sufficient to demonstrate the pattern.

Don't see LeadIntakeKey in the dropdown?

After adding an API key to a usage plan, the update operation might take a few minutes to complete. Wait a moment and refresh the page.

Also confirm that you created the API key in the same region as your LeadIntakeAPI. API keys are region-specific.

Still stuck? Help me troubleshoot my usage plan setup in API Gateway.

Your API now has rate limits and a monthly quota in place. Next, you'll test both authorized and unauthorized requests in Postman to see these controls in action.

Test Authorized vs Unauthorized Access

Your API key is created and your usage plan enforces rate limits. Now it is time to prove the setup actually works by testing both sides of the access gate.

In this step, you will store your API key as a Postman environment variable and fire test requests to confirm the key grants access while missing or invalid keys get rejected.

In this step, get ready to:
  • Create a Postman environment to store your API key securely as a reusable variable.
  • Send a request with a valid API key and confirm a 200 OK response.
  • Send requests without a key and with an invalid key to confirm 403 Forbidden responses.
Create a Postman environment for your API key

Hardcoding your API key into every request is fragile. If the key changes, you would need to update every single request manually.

Postman environments let you store a value once and reference it across all your requests with the {{variable_name}} syntax.

  • In Postman, click Environments in the left sidebar.
  • Click the + icon to create a new environment.
  • Enter Dev as the environment name.
  • In the variable table, click Add variable and enter api_key as the variable name.
  • Paste your LeadIntakeKey value (the one you copied in Step 1) into the Initial value field.
  • Your changes save automatically. Select Dev from the environment dropdown in the top-right corner of the workbench to make it the active environment.

What is a Postman environment?

A Postman environment is a named set of variables that you can swap in and out depending on your context. For example, you might have a Dev environment pointing at your development stage and a Prod environment pointing at production.

When an environment is active, Postman resolves any {{variable}} references in your requests using that environment's values.

Don't see your variable resolving?

Make sure Dev is selected as the active environment in the top-right dropdown. If it still shows No Environment, the variable will not resolve.

Help me set up my Postman environment variable.

Send a request with your valid API key

With the environment active, you can reference your key in any request header using {{api_key}} instead of pasting the raw value.

  • Open your existing Submit Valid Lead request in your Lead Intake API Tests collection (or create a new POST request pointing at your invoke URL).
  • Click the Headers tab.
  • Add a new header with key x-api-key and value {{api_key}}.
  • Click Send.

You should see a 200 OK response with the success message from your Lambda function. This confirms your API key is valid and API Gateway allowed the request through.

Why use a variable instead of pasting the key directly?

Storing the key in an environment variable means you update it in one place if it ever rotates. Every request that references {{api_key}} automatically picks up the new value.

Getting a 403 even with the key?

Double check that the header key is exactly x-api-key (all lowercase with dashes). Also confirm your Dev environment is active in the top-right dropdown.

If you just attached the key to the usage plan, wait a minute or two for the association to propagate, then try again.

Help me troubleshoot my 403 response with a valid API key.

Test unauthorized access patterns

The whole point of requiring an API key is that requests without one get rejected at the gateway level. This means Lambda never runs, saving you compute costs on illegitimate traffic.

  • In the same request, clear the value of the x-api-key header (or uncheck it to disable it).
  • Click Send.

You should see a 403 Forbidden response with the body {"message":"Forbidden"}. This confirms API Gateway rejected the request before it reached your Lambda function.

  • Now type a random string like invalid-key-12345 as the x-api-key header value.
  • Click Send.

You should see another 403 Forbidden response. An invalid key is treated the same as a missing key.

Why does this matter?

API Gateway validates the key before invoking Lambda. If you check the response times, you will notice the 403 responses come back faster than the 200 response. That is because the request never travels to Lambda and back.

This gateway-level rejection is how production APIs protect themselves from unauthorized traffic without burning compute resources.

Still getting 200 without a key?

Make sure you redeployed your API to the dev stage after setting API key required to true in Step 1. Changes to method settings do not take effect until you deploy.

Help me figure out why my API is not rejecting requests without a key.

  • Reset your x-api-key header value back to {{api_key}} so your request is ready for the next step.

Your API now has a working access gate. In the next step, you will organize these test scenarios into a dedicated folder so you have a repeatable test suite for your API's security behavior.

Organize Security Tests in Postman

You've confirmed that your API accepts authenticated requests and rejects unauthenticated ones. Now it's time to organize those tests into a repeatable structure.

A dedicated test folder makes it easy to re-verify your security setup whenever you make changes to the API. In this step, you'll build a Security Tests folder in Postman that covers all three access scenarios and confirm that usage tracking is recording your requests.

In this step, get ready to:
  • Create a Security Tests folder with three organized test requests.
  • Verify each request returns the correct response code.
  • Confirm your usage plan is tracking API key activity.
Create the Security Tests folder and requests

Grouping related requests into a folder keeps your collection clean and lets you run all security checks in one go.

  • Switch back to Postman and find your Lead Intake API Tests collection in the left sidebar.
  • Click View more actions (the three-dot icon) next to the collection name, then click Add folder.
  • Name the folder Security Tests.

Now you'll create three requests inside this folder, each testing a different access scenario.

  • Click View more actions next to your new Security Tests folder, then click Add request.
  • Name the request Valid API Key.
  • Set the method to POST and paste your LeadIntakeAPI invoke URL.
  • In the Headers tab, add a header with key x-api-key and value {{api_key}}.
  • In the Body tab, select raw and JSON, then paste a valid lead body (the same JSON you used in your earlier test requests).
  • Click Save.
  • Create a second request in the Security Tests folder named Missing API Key.
  • Set the method to POST and paste the same invoke URL.
  • Do not add an x-api-key header.
  • In the Body tab, add the same valid lead JSON body.
  • Click Save.
  • Create a third request in the Security Tests folder named Invalid API Key.
  • Set the method to POST and paste the same invoke URL.
  • In the Headers tab, add a header with key x-api-key and value invalid-key-12345.
  • In the Body tab, add the same valid lead JSON body.
  • Click Save.

Why organize tests into a folder?

A Security Tests folder groups all your access-control checks in one place. When you add new endpoints or change your API key configuration later, you can run the entire folder at once to confirm nothing broke.

Run the requests and verify responses
  • Open the Valid API Key request and click Send.
  • Confirm you receive a 200 OK response with the success message from your Lambda function.
  • Open the Missing API Key request and click Send.
  • Confirm you receive a 403 Forbidden response with the message {"message":"Forbidden"}.
  • Open the Invalid API Key request and click Send.
  • Confirm you also receive a 403 Forbidden response.

Why are the 403 responses faster?

The 403 Forbidden responses come back noticeably faster than the 200 OK response. This is because API Gateway rejects them at the gateway level without ever invoking your Lambda function.

This is one of the key benefits of API keys. Bad requests never consume Lambda compute time or hit your DynamoDB table.

Getting 200 on all three requests?

If the Missing API Key and Invalid API Key requests also return 200 OK, your API may not have been redeployed after enabling API key required. Return to API Gateway, click Deploy API, select the dev stage, and redeploy.

Also verify that the Dev environment is selected as active in the top-right corner of Postman. Without it, the {{api_key}} variable won't resolve.

Still stuck? Help me troubleshoot why my API is not requiring an API key.

Confirm usage tracking in API Gateway

Every request that includes a valid API key gets counted against your usage plan quota. You can see these counts in the API Gateway console.

  • Return to the AWS Management Console.
  • In the API Gateway main navigation pane, choose Usage plans.
  • Select LeadIntakePlan.
  • Click the Usage tab.
  • Confirm you can see your API key's request count incrementing.

What does the Usage tab show?

The Usage tab displays a graph of requests made with each API key attached to this plan. You should see a count reflecting the successful requests you just sent from Postman.

Only requests that pass the API key check count toward your quota. The 403 responses from missing or invalid keys do not consume quota.

Usage tab showing zero requests?

Usage data can take a few minutes to propagate. Wait 2-3 minutes and refresh the page. If it still shows zero, confirm that LeadIntakeKey is listed under the Associated API keys tab of your usage plan.

Need help? Why is my API Gateway usage plan not showing any request counts?

Secret mission

Build a Lambda Authorizer

API keys identify who is calling your API. But they don't actually authenticate anyone. In this mission, you'll build a Lambda authorizer that validates bearer tokens and returns IAM policy documents, adding real authentication to your Lead Intake API.

Clean Up Your Resources

Clean Up Your Resources

Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project uses serverless AWS resources that cost nothing while idle within Free Tier limits.

Resources you used:

  • LeadIntakeKey (API key in API Gateway).
  • LeadIntakePlan (usage plan in API Gateway).
  • LeadIntakeAuthorizer (Lambda function, if Secret Mission completed).

Keep everything running

No action needed. Choose this if you plan to continue building on your secured API.

  • All resources are serverless and cost nothing while idle within AWS Free Tier limits.
  • API Gateway free tier covers 1 million REST API calls per month for the first 12 months.
  • Lambda free tier covers 1 million requests per month (always free, not limited to first 12 months).

Pause - I'll come back to this later

No action needed. Serverless resources do not run continuously, so there is nothing to pause.

  • Your API key, usage plan, and Lambda authorizer remain configured but incur no charges while idle.
  • When you return, everything will be exactly as you left it.

Delete - I don't want to use this again

Remove all resources created in this project. Follow each step below in order.

Delete the API key:

  • In the API Gateway console, choose API keys in the main navigation pane.
  • Select LeadIntakeKey.
  • Choose Actions, then Delete.

Delete the usage plan:

  • In the main navigation pane, choose Usage plans.
  • Select LeadIntakePlan.
  • Under the Associated API keys tab, remove LeadIntakeKey.
  • Under the Associated stages tab, remove the LeadIntakeAPI/dev stage.
  • Once both associations are removed, delete the usage plan.

Delete the authorizer Lambda (if Secret Mission completed):

  • Open the Functions page of the Lambda console.
  • Select LeadIntakeAuthorizer.
  • Choose Actions, then Delete.
  • Type confirm in the text input field and choose Delete.

Nice Work!

Nice Work!

You just secured your Lead Intake API with two layers of access control. Your API now rejects unauthenticated requests at the gateway level before they ever reach your Lambda function.

You've learned how to:

  • Created an API key and required it on your POST /leads endpoint, enforcing gateway-level rejection that blocks unauthenticated calls before they reach Lambda.
  • Built a usage plan with rate limiting and a monthly quota that mirrors how production SaaS platforms manage API access.
  • Organized Postman security tests with environment variables demonstrating valid, missing, and invalid key scenarios.
  • Secret Mission: Built a Lambda authorizer that validates bearer tokens and returns IAM policy documents, demonstrating the critical difference between API keys (identification/throttling) and token-based authorization (actual authentication).

Ready to quiz yourself?