I\'m using API Gateway\'s Proxy integration to call a Lambda. The output format specification is this follow JSON format:
{
\"statusCode\": httpStatusCode,
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.
Couple of years late, but I just required to implement something like this and this is how I was able to make it work:
...
//15 minutes
var expirationTime = new Date(new Date().getTime() + 15 * 60 * 1000);
//30 minutes
var expirationTime2 = new Date(new Date().getTime() + 30 * 60 * 1000);
var response = {};
var cookies = [];
cookies.push("testCookie={'keyX':'valx', 'keyy':'valy'}; Expires=" + expirationTime + ";");
cookies.push("testCookie2={'key1':'val1', 'key2':'val2'}; Expires=" + expirationTime2 + ";");
response.headers["Set-Cookie"] = cookies;
...
Each array item will be processed independently, so you can add as many cookies to the array with different settings.
i.e.
cookies.push("testCookie3={'key1':'val1', 'key2':'val2'}; Expires=" + expirationTime2 + "; Max-Age=...");
cookies.push("testCookie4={'key1':'val1', 'key2':'val2'}; Expires=" + expirationTime2 + "; Domain=<domain-value>; Path=<path-value>");
Use multiValueHeaders:
response.multiValueHeaders = {
"Set-Cookie": [
'cookie1=value1',
'cookie1=value1'
]
}
or:
{
"statusCode": httpStatusCode,
"headers": { "headerName": "headerValue", ... },
"multiValueHeaders": { "headerName": ["headerValue", "headerValue2",...], ... },
"body": "..."
}
https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format
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.