Repository navigation
RFC: Simplifying CORS #1029
Copy link
Copy link
Closed
Labels
Description
Key information
- RFC PR: feat: module to ease cors configuration #831
- Related issue(s), if known:
- Area: new module
- Meet tenets: Yes
Summary
When working with API Gateway + Lambda, developers need to handle CORS Headers properly, to make sure their API can be called by a web frontend and to avoid cross origin requests to be blocked. This module would simplify adding CORS headers in the response of their Lambda function when used with an API Gateway Proxy.
Motivation
Adding CORS in the response headers is either forgotten (and nothing works as expected), either boring (a lot of boilerplate code, with very specific syntax). With the wish to simplify developer life, Lambda Powertools could bring something.
Proposal
- Adding a new annotation for the function handler method:
@CrossOrigin - When using this annotation with a handler implementing
RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent>, the annotation will automatically add the headersAccess-Control-Expose-Headers,Access-Control-Allow-Origin,Access-Control-Allow-Methods,Access-Control-Allow-Credentials,Access-Control-Max-Ageto the response object.
public class FunctionProxy implements RequestHandler<APIGatewayProxyRequestEvent, APIGatewayProxyResponseEvent> {
@CrossOrigin
public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
// CORS headers will be automatically added in the following object:
return new APIGatewayProxyResponseEvent()
.withStatusCode(200)
.withBody(body);
}
}- The annotation can obviously be configured to specify the different values (there are some default values to simplify the job of developpers):
| parameter | Default | Description |
|---|---|---|
| allowedHeaders | Authorization, * (*) |
Access-Control-Allow-Headers header |
| exposedHeaders | * |
Access-Control-Expose-Headers header |
| origins | * |
Access-Control-Allow-Origin header |
| methods | * |
Access-Control-Allow-Methods header |
| allowCredentials | true |
Access-Control-Allow-Credentials header |
| maxAge | 29 |
Access-Control-Max-Age header |
Example:
@CrossOrigin(
origins = "http://origin.com, https://other.origin.com",
allowedHeaders = "Authorization, Content-Type, X-API-Key",
methods = "POST, OPTIONS"
)
public APIGatewayProxyResponseEvent handleRequest(final APIGatewayProxyRequestEvent input, final Context context) {
// ...
}- The annotation can also be configured with environment variables, to simplify even further and allow configuration in infra as code (SAM for example)
| Environment variable | Default | Description |
|---|---|---|
| ACCESS_CONTROL_ALLOW_HEADERS | Authorization, * (*) |
Access-Control-Allow-Headers header |
| ACCESS_CONTROL_EXPOSE_HEADERS | * |
Access-Control-Expose-Headers header |
| ACCESS_CONTROL_ALLOW_ORIGIN | * |
Access-Control-Allow-Origin header |
| ACCESS_CONTROL_ALLOW_METHODS | * |
Access-Control-Allow-Methods header |
| ACCESS_CONTROL_ALLOW_CREDENTIALS | true |
Access-Control-Allow-Credentials header |
| ACCESS_CONTROL_MAX_AGE | 29 |
Access-Control-Max-Age header |
- When using multiple origins in the configuration (comma-separated), the annotation will find the one matching the request and use this specific one in the header, as browsers don't support multiple origins in the header.
Drawbacks
This new module can bring a few additional kb to the lambda package size. It does not use any dependency which is not already in the core module.
Rationale and alternatives
- What other designs have been considered? Why not them? N/A
- What is the impact of not doing this? N/A
Unresolved questions
N/A
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsNo status
Activity
ijemmy commentedon Jan 13, 2023
@jeromevdl
This is one of the most common issues people face. It will greatly improve DX.
Some comments:
'*'as a default. Many developers do not know why we have CORS and may use the default values (out of convenient) in production without knowing the consequence.originheader doesn't support multiple value. I use usually information from request header to determine which value should I return (e.g. dev.site.com, staging.site.com, etc.). But I think we should leave this to clients to keep this feature generic..withHeader()with the same key. I suggest not to override so that the handler can override theoriginheader value fromevent/contextdata.