DEV Community

iAmSherif πŸ’Ž
iAmSherif πŸ’Ž

Posted on

How to set up CORS in AWS Lambda and API Gateway (RestApi)

How to set up CORS in AWS Lambda and API Gateway (RestApi)Cross-Origin Resource Sharing (CORS) is a security feature implemented by web browsers that restricts how resources on a web server can be requested from a different domain. When building serverless applications using AWS Lambda and API Gateway, you need to configure CORS properly to allow client applications from different origins to access your API.

CORS is enforced at the browser level. When you deploy a REST API service to a domain, the browser must agree to the service's terms before communicating with it.

Imagine you have a Lambda backend service exposed through API Gateway's REST API. You integrate this API into your client application using communication services like Axios or JavaScript's fetch. You expect it to work smoothly because you've tested it with API testing tools such as Postman or even the AWS Management Console. But then poof! a strange 403 error appears. Why is this happening?

Why Do You Get a CORS Error from the Browser?

The reason is simple: unlike tools like Postman that make direct requests, browsers enforce the same-origin policy as a security measure. If your frontend is hosted on https://frontend.com and it tries to fetch data from https://api.com, the browser blocks the request unless the API explicitly allows it.

CORS settings in API Gateway define whether such cross-origin requests should be permitted. The key configurations involve setting allowed origins, HTTP methods, and headers.

Understanding the Request Flow: Preflight and Actual Requests

When a client’s browser makes a request to an API hosted on a different origin, the process typically involves two steps: The Preflight Request and the Actual Request.

  • Preflight Request:

Preflight Request

Before sending the actual request, the browser sends an OPTIONS request to the API.

This request asks the server: β€œAm I allowed to send this request? If so, what methods and headers can I use?”

API Gateway (if configured correctly) responds with the allowed origins, methods, and headers.

  • Actual Request:

Once the browser receives a successful response from the preflight check, it proceeds to send the actual request (GET, POST, etc.) to the API.

Actual Request

If the API response includes the required CORS headers, the browser allows the data to be accessed by the client application.

Without proper CORS settings, the browser will block the request at the preflight stage, preventing the client from communicating with the API.

Setting Up CORS in AWS API Gateway and Lambda in (CDK)

There are two places you are required to set your headers in other for the two requests (Preflight and Actual) to be successful.

First, Set up defaultCorsPreflightOptions in your API-Gateway.

const restApi = new RestApi(this, `YourApi`, {
      defaultCorsPreflightOptions: {
        allowOrigins: 'https://frontend.com',
        allowMethods: ['GET', 'POST', 'OPTIONS'],
        allowHeaders: [
          'Content-Type',
          'Authorization',
          'Accept',
          'X-Requested-With'
        ],
        allowCredentials: true,
      },
    });
Enter fullscreen mode Exit fullscreen mode

defaultCorsPreflightOptions: adds a CORS preflight configuration to this resource and all child resources.

  • allowOrigins: Defines the permitted origins for requests to this resource. To allow all origins, use Cors.ALL_ORIGINS or [*]. The response will include the Access-Control-Allow-Origin header, and if Cors.ALL_ORIGINS is used, the Vary: Origin header will also be included.
  • allowMethods: The Access-Control-Allow-Methods response header defines the permitted HTTP methods for a resource in response to a preflight request. Here, only GET, POST, and OPTIONS are allowed, enforcing the principle of least privilege by restricting access to necessary methods. If ANY is specified, it will be expanded to Cors.ALL_METHODS.
  • allowHeaders: The Access-Control-Allow-Headers response header specifies the allowed HTTP headers in response to a preflight request, based on the Access-Control-Request-Headers.

allowCredentials: The Access-Control-Allow-Credentials response header determines whether the response is accessible to frontend JavaScript when the request's credentials mode is set to "include". If true, browsers expose the response only when credentials (cookies, authorization headers, or TLS client certificates) are included.

In API Gateway, this ensures a successful preflight request but does not guarantee the actual request's success.
Successful preflight request
Why? Because the API response does not include the necessary CORS headers. How can we fix that?

Second, Add CORS headers to your lambda response.

exports.handler = async (event) => {
  return {
    statusCode: 200,
    headers: {
      "Access-Control-Allow-Origin": "*", // Allow all origins
      "Access-Control-Allow-Methods": "GET,OPTIONS",
      "Access-Control-Allow-Headers": "Content-Type,Authorization",
    },
    body: JSON.stringify({ message: "We Are Fixing CORS!" }),
  };
};
Enter fullscreen mode Exit fullscreen mode

We added CORS headers to the Lambda response. After a successful preflight request, the browser verifies these headers in the actual response. If present, the data becomes accessible.

Conclusion

Setting up CORS for AWS Lambda and API Gateway is crucial when exposing APIs to frontend applications hosted on different domains. By configuring API Gateway’s preflight options and ensuring Lambda responses include CORS headers, you can successfully enable cross-origin access.

β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”β€”

For more articles, follow my social handles:

Top comments (1)

Collapse
 
reynaldichernando profile image
reynaldi

lambda should just make the options request not count towards the request count, because then every request will be double (preflight + actual request)