Borislav Hadzhiev
Last updated: Apr 13, 2022
Check out my new book
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 consist 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 snippet we have:
defaultCorsPreflightOptions
prop to set up CORS for all of
the API's routestodos
resource with GET
and POST
methods, just to see
that the CORS configuration will apply to both.The configuration parameters we've used for CORS are:
allowedHeaders
- specifies which HTTP headers the frontend is allowed to use
when making request 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