Using AWS Gateway API, can I access the cookies?

25,429

Solution 1

To access cookies sent by the client in your backend you'll have to setup a mapping from the method request header to your integration request header.

These instructions assume you've already setup a simple method in API Gateway.

Access cookies in your backend

  1. Under Method Request, create an HTTP Request Header with the name of "Cookie"
  2. Under Integration Request, create an HTTP header with name "Cookie" and "Mapped from" value of method.request.header.Cookie.
  3. You'll also likely need to setup CORS for this method. See: http://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-cors.html
  4. Deploy your API and make a request to your API Gateway endpoint with your browser/client. You should see requests coming in to your HTTP backend with the Cookie header value sent from the browser.

Add cookie to response

You can setup a Set-Cookie response header in an analogous fashion for the the integration response/method response side of the method configuration.

  1. Under Method Response, create a Response header with name Set-Cookie
  2. Under Integration Response setup a Header Mapping with Response header Set-Cookie and Mapping value integration.response.header.Set-Cookie

Please note that at this time, API Gateway supports setting just a single Set-Cookie response header. If your backend attempts to set multiple Set-Cookie headers, only the last one will be set. See this forum post for more details: https://forums.aws.amazon.com/thread.jspa?messageID=701434

Solution 2

If you check the "Use Lambda Proxy integration" option in your API Gateway method, the request headers will be passed to your Lambda function via the event variable. API Gateway will also expect a different response from your callback function. This response format can be use to dictate a Set-Cookie header. e.g.:

callback(null, {
    statusCode: 200,
    headers: {'Set-Cookie': 'key=val'},
    body: 'Some response'
})`

This approach has the advantage of not requiring any Method Request or Method Response tweaks.

Here's a sample Lambda function using this logic to rotate a cookie value after each request.

exports.handler = (event, context, callback) => {

    var cookies = getCookiesFromHeader(event.headers);

    var old_cookie = cookies.flavor;
    var new_cookie = pickCookieFlavor(old_cookie);

    return callback(null, {
        statusCode: 200,
        headers: {
            'Set-Cookie': setCookieString('flavor', new_cookie),
            'Content-Type': 'text/plain'
        },
        body: 'Your cookie flavor was ' + old_cookie + '. Your new flavor is ' + new_cookie + '.'
    });
};

/**
 * Rotate the cookie flavor
 */
function pickCookieFlavor(cookie) {
    switch (cookie) {
        case 'peanut':
            return 'chocolate';
        case 'chocolate':
            return 'raisin and oat';
        default:
            return 'peanut';
    }
}

/**
 * Receives an array of headers and extract the value from the cookie header
 * @param  {String}   errors List of errors
 * @return {Object}
 */
function getCookiesFromHeader(headers) {

    if (headers === null || headers === undefined || headers.Cookie === undefined) {
        return {};
    }

    // Split a cookie string in an array (Originally found http://stackoverflow.com/a/3409200/1427439)
    var list = {},
        rc = headers.Cookie;

    rc && rc.split(';').forEach(function( cookie ) {
        var parts = cookie.split('=');
        var key = parts.shift().trim()
        var value = decodeURI(parts.join('='));
        if (key != '') {
            list[key] = value
        }
    });

    return list;
};


/**
 * Build a string appropriate for a `Set-Cookie` header.
 * @param {string} key     Key-name for the cookie.
 * @param {string} value   Value to assign to the cookie.
 * @param {object} options Optional parameter that can be use to define additional option for the cookie.
 * ```
 * {
 *     secure: boolean // Watever to output the secure flag. Defaults to true.
 *     httpOnly: boolean // Watever to ouput the HttpOnly flag. Defaults to true.
 *     domain: string // Domain to which the limit the cookie. Default to not being outputted.
 *     path: string // Path to which to limit the cookie. Defaults to '/'
 *     expires: UTC string or Date // When this cookie should expire.  Default to not being outputted.
 *     maxAge: integer // Max age of the cookie in seconds. For compatibility with IE, this will be converted to a
*          `expires` flag. If both the expires and maxAge flags are set, maxAge will be ignores. Default to not being
*           outputted.
 * }
 * ```
 * @return string
 */
function setCookieString(key, value, options) {
    var defaults = {
        secure: true,
        httpOnly: true,
        domain: false,
        path: '/',
        expires: false,
        maxAge: false
    }
    if (typeof options == 'object') {
        options = Object.assign({}, defaults, options);
    } else {
        options = defaults;
    }

    var cookie = key + '=' + value;

    if (options.domain) {
        cookie = cookie + '; domain=' + options.domain;
    }

    if (options.path) {
        cookie = cookie + '; path=' + options.path;
    }

    if (!options.expires && options.maxAge) {
        options.expires = new Date(new Date().getTime() + parseInt(options.maxAge) * 1000); // JS operate in Milli-seconds
    }

    if (typeof options.expires == "object" && typeof options.expires.toUTCString) {
        options.expires = options.expires.toUTCString();
    }

    if (options.expires) {
        cookie = cookie + '; expires=' + options.expires.toString();
    }

    if (options.secure) {
        cookie = cookie + '; Secure';
    }

    if (options.httpOnly) {
        cookie = cookie + '; HttpOnly';
    }

    return cookie;
}
Share:
25,429

Related videos on Youtube

Barry King
Author by

Barry King

Passionate about technology. Thats it.

Updated on December 14, 2020

Comments

  • Barry King
    Barry King almost 2 years

    Using a HTTP Proxy Integration I want to access the cookies and add one to the json response. Is that possible?

  • Sergey Potapov
    Sergey Potapov over 6 years
    Logically it should help and I do the same thing. However, what do I do, if API gateway in logs show that server does not return "Set-Cookie" header, even I am 100% sure that it does. Maybe you've faced same problem before? Any ideas? Thanks)
  • Glenn Van Schil
    Glenn Van Schil almost 5 years
    @SergeyPotapov It'll not work if you are testing this on localhost because domains don't match. when you open the lambda's url itself it should work. If this is not the case you will have to validate your Method/Integration response
  • Miguel Coder
    Miguel Coder over 4 years
    the proxy integration strips the cookie header from the request
  • Vyacheslav Tsivina
    Vyacheslav Tsivina about 4 years
    Can add one thing, I tried to get cookie from request in CloudFront(I use lambda as proxy). The actual value of cookies is actually stored in event.Records[0].cf.request.headers.cookie[0].value so one may need to slightly change function to find cookies.