Last updated: Jan 27, 2024
Reading timeยท5 min
CORS is a mechanism that allows a server to use a combination of HTTP headers to indicate from which domains, other than its own, it receives requests.
Setting CORS configuration is important when we access resources from a different domain.
The API Gateway service hosts APIs on the https://amazonaws.com
domain,
which is different from where we host our client applications, so we have to
enable CORS.
In order to demo how to set up CORS for API Gateway, I'll create a simple CDK app that consists of a single Rest API.
import * as apigateway from 'aws-cdk-lib/aws-apigateway'; import * as cdk from 'aws-cdk-lib'; export class MyCdkStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); const restApi = new apigateway.RestApi(this, 'api', { description: 'example-api', // ๐ set up CORS defaultCorsPreflightOptions: { allowHeaders: [ 'Content-Type', 'X-Amz-Date', 'Authorization', 'X-Api-Key', ], allowMethods: ['OPTIONS', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE'], allowCredentials: true, allowOrigins: ['http://localhost:3000'], }, }); // ๐ add a resource with 2 methods for demo purposes const todos = restApi.root.addResource('todos'); todos.addMethod('GET'); todos.addMethod('POST'); } } const app = new cdk.App(); new MyCdkStack(app, 'my-cdk-stack', { stackName: 'my-cdk-stack', env: { region: process.env.CDK_DEFAULT_REGION, account: process.env.CDK_DEFAULT_ACCOUNT, }, });
In the code sample, we:
defaultCorsPreflightOptions
prop to set up CORS for all of the
API's routes.todos
resource with GET
and POST
methods, just to see that the
CORS configuration will apply to both.The configuration parameters we used for CORS are:
allowedHeaders
- specifies which HTTP headers the frontend is allowed to use
when making requests to our REST APIallowMethods
- an array of the HTTP methods our frontend is allowed to use
when calling our REST APIallowCredentials
- whether to expose the API Gateway response to the
frontend when the request's credentials mode is set to include
. When
credentials mode is set to include
, our frontend will always send user
credentials (i.e. cookies, auth headers) even for CORS calls.allowOrigins
- an array of the origins that are allowed to make requests to
our rest API. If you own a domain https://example.com
that's what you'd set
here.Now, I'll deploy the stack.
npx aws-cdk deploy
At this point, if we open the CloudFormation console, we can see that our API has been deployed.
If we now open the OPTIONS
endpoint for any of the routes, we can see that the
CORS headers are applied at the Integration Response
stage.
If we want a more fine-grained approach to setting cors, we can do it on a per-resource basis, i.e.:
const todos = restApi.root.addResource('todos'); todos.addMethod('GET'); todos.addMethod('POST'); todos.addCorsPreflight({ allowHeaders: ['Content-Type', 'X-Amz-Date', 'Authorization', 'X-Api-Key'], allowMethods: ['OPTIONS', 'GET', 'POST', 'PUT', 'PATCH', 'DELETE'], allowCredentials: true, allowOrigins: ['http://localhost:3000'], });
However, setting CORS globally has been more common in my experience, so the
defaultCorsPreflightOptions
prop is what you'll want to use most of the time.
Note that we often get cors
errors when making HTTP requests to APIs, when we
type in the endpoint or the HTTP method wrong.
For instance, if I make a POST request to
https://api-id.aws.amazon.com/wrong-path
I'll get a CORS error in the console
of my browser.
The same happens if I send a request with an HTTP method that the endpoint does not support, I'll still get a CORS error.
To delete the stack and the provisioned resources, we
can run the cdk destroy
command:
npx aws-cdk destroy
CORS allows us to set up a combination of HTTP headers that our backend server responds with to indicate from which domains, other than its own, it receives requests.
By default, servers only take requests from applications hosted on the same
domain, however HTTP APIs are hosted on the https://amazonaws.com
domain and
our frontend application might be hosted on https://example.com
, which means
that we have to configure CORS.
Let's look at an example of enabling CORS on an HTTP API in CDK:
import {CorsHttpMethod, HttpApi} from 'aws-cdk-lib/aws-apigatewayv2'; import * as cdk from 'aws-cdk-lib'; export class CdkStarterStack extends cdk.Stack { constructor(scope: cdk.App, id: string, props?: cdk.StackProps) { super(scope, id, props); const httpApi = new HttpApi(this, 'cors-demo-api', { description: 'API for CORS demo', corsPreflight: { allowHeaders: [ 'Content-Type', 'X-Amz-Date', 'Authorization', 'X-Api-Key', ], allowMethods: [ CorsHttpMethod.OPTIONS, CorsHttpMethod.GET, CorsHttpMethod.POST, CorsHttpMethod.PUT, CorsHttpMethod.PATCH, CorsHttpMethod.DELETE, ], allowCredentials: true, allowOrigins: ['http://localhost:3000'], // ๐ optionally cache responses to preflight requests // maxAge: cdk.Duration.minutes(5), }, }); } }
We created an HttpApi
, where we've set the corsPreflight
prop to enable
CORS.
The corsPreflight
object consists of the following properties:
Name | Description |
---|---|
allowHeaders | which HTTP headers the frontend is allowed to use when making requests to our HTTP API |
allowMethods | which HTTP methods the frontend is allowed to use when making requests to our HTTP API |
allowCredentials | whether credentials (cookies, auth headers) are included in the CORS requests to the HTTP API |
allowOrigins | which origins are allowed to make requests to our HTTP API. If your domain is https://example.com and it needs to make requests to the API, add it to allowOrigins . |
maxAge | the duration, for which the browser will cache the response from a preflight request. Set this if you're worried about performance. By default responses don't get cached. |
Let's run the deploy command:
npx aws-cdk deploy
If we look at the API named cors-demo-api
, we can see that we've successfully
set up CORS:
To delete the resources we've provisioned, issue the destroy
command:
npx aws-cdk destroy
I've also written tutorials on provisioning and configuring API Gateway and HTTP API using CDK.
You can learn more about the related topics by checking out the following tutorials: