I'm using API Gateway's Proxy integration to call a Lambda. The output format specification is this follow JSON format:
{
"statusCode": httpStatusCode,
"headers": { "headerName": "headerValue", ... },
"body": "..."
}
In one response I wish to set two cookies (two different auth cookies) but JSON doesn't allow having two identical keys in the headers
object (OK, technically the spec does but most libraries do not).
RFC 7230 notes that Set-Cookie should be handled specially but I can't see how I can send multiple Set-Cookie values through API gateway.
Does anyone know whether this is possible?
To pass custom headers from an API Gateway API to a Lambda function, use a body mapping template. The API sends the updated API request to a Lambda function to process the headers. Then, the Lambda function returns one or more header values from the original API request.
You can create a web API with an HTTP endpoint for your Lambda function by using Amazon API Gateway. API Gateway provides tools for creating and documenting web APIs that route HTTP requests to Lambda functions.
When the user agent generates an HTTP request, the user agent MUST NOT attach more than one Cookie header field. It looks like the use of multiple Cookie headers is, in fact, prohibited!
The easiest way to set custom HTTP status code is to setup a Lambda Proxy Integration in API Gateway. In API Gateway > Resource > Actions Dropdown > Create Method > tick Lambda Proxy Integration and select appropriate Lambda function. For async functions just return with an object with statusCode and body .
Note: API gateway now has a version 2 payload that is fundamentally different from that described here (and the default for new APIs). Documentation on the differences here. See other accepted answer from Samuel for some more details.
As of November 2018 this is possible using the multiValueHeaders
field in the response instead of headers
(see announcement).
As an example instead of:
{
"statusCode": 200,
"body": "testing multiple set-cookie headers",
"headers": {
"X-Test-Header": "baking experiment",
"Set-Cookie": "cookie1=chocolate-chip",
"Set-Cookie": "cookie2=oatmeal",
"Content-Type": "text/plain"
}
}
You can respond with:
{
"statusCode": 200,
"body": "testing multiple set-cookie headers",
"multiValueHeaders": {
"X-Test-Header": ["baking experiment"],
"Set-Cookie": ["cookie1=chocolate-chip", "cookie2=oatmeal"],
"Content-Type": ["text/plain"]
}
}
Note that you can use a mix of headers
and multiValueHeaders
:
{
"statusCode": 200,
"body": "testing multiple set-cookie headers",
"headers": {
"X-Test-Header": "baking experiment",
"Content-Type": "text/plain"
},
"multiValueHeaders": {
"Set-Cookie": ["cookie1=chocolate-chip", "cookie2=oatmeal"]
}
}
However using the same header in both will mean that the value under headers
is dropped.
See the documentation for more details.
When using only the header field (as available prior to Nov 2018) I tried sending the following manually curated JSON as a response:
{
"statusCode": 200,
"body": "testing multiple set-cookie headers",
"headers": {
"X-Test-Header": "baking experiment",
"Set-Cookie": "cookie1=chocolate-chip",
"Set-Cookie": "cookie2=oatmeal",
"Content-Type": "text/plain"
}
}
The cookies that API gateway returns in response to a CURL request are:
< Content-Type: text/plain
< Content-Length: 35
< Connection: keep-alive
< Date: Thu, 29 Sep 2016 11:22:09 GMT
< Set-Cookie: cookie2=oatmeal
< X-Test-Header: baking experiment
< X-Cache: Miss from cloudfront
As you can see the first Set-Cookie
is dropped on the floor.
As answered, to date, API Gateway will drop identical keys, only setting one of the cookies.
However, a workaround exists. You can change the casing of the string 'Set-Cookie'
so the keys are not unique. For example, you could use the keys set-cookie
, Set-cookie
, sEt-cookie
, and the headers will be preserved and 3 different cookies would be set.
Because the RFC standard makes headers case-insensitive this should work with all RFC-compliant clients.
So, you could rewrite your set-cookie headers, permuting all the possible casings of "Set-Cookie" to get around this.
This technique (hack) is employed by Zappa, a popular serverless framework written in Python.
As Mark B pointed out, you can/should achieve this by setting multiple cookie name/value pairs in a single Set-Cookie header. The browser should interpret this correctly.
Cookie: a=1; b=2
Edit: as pointed out by OP, there are use cases that require multiple instances of the header. We've added it our backlog along with supporting multiple header names on incoming requests.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With