Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what is the correct way to get the origin header in a serverless deployed lambda fronted by api gateway?

I am using the serverless framework to deploy a simple lambda (written in node/ express) behind api gateway...

In a GET I can see the origin header, but in a POST I cannot - it's not passed into my lambda function!

Anyone know why not and how to make it pass?

Background:

I did notice that in the POST the origin appears to be appended to the query string in the logs:

originalUrl: '/dev/endpoint?Origin=MY%20ORIGIN%20HERE',

So, I could extract the origin from the query string values, but I want to know if this is the correct way to do things on the serverless framework or should I be setting something to allow the API Gateway to send the origin through on a POST like it does on a GET ? Why are the 2 verbs behaving differently?

My Code/ Config:

the function definition in the serverless.yml looks like:

myGetFunction:
  handler: lambda/index.handler
  events:
    - http:
        path: /endpoint
        method: get
        cors: true
myPostFunction:
  handler: lambda/index.handler
  events:
    - http:
        path: /endpoint
        method: post
        cors: true

If I just put the following in my index.handler:

app.use((req, res) => {
  console.log('LOG REQUEST', req)
  res.send('interesting')
})

In my handler function, I only want to get the origin request header that was sent. In the GET it's easy: the cloudwatch logs show that it's available in the GET request in the headers object:

headers: 
  {
    accept: '*/*',
    'accept-encoding': 'gzip, deflate',
    'cache-control': 'no-cache',
    'cloudfront-forwarded-proto': 'https',
    'cloudfront-is-desktop-viewer': 'true',
    'cloudfront-is-mobile-viewer': 'false',
    'cloudfront-is-smarttv-viewer': 'false',
    'cloudfront-is-tablet-viewer': 'false',
    'cloudfront-viewer-country': 'GB',
    host: 'X.execute-api.us-east-1.amazonaws.com',
    origin: 'MY ORIGIN HERE',

BUT: in the POST all the other headers are there, but origin is blank.

like image 858
Nick Meldrum Avatar asked Dec 05 '18 07:12

Nick Meldrum


People also ask

How do I pass headers from API gateway to Lambda?

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.

How do I enable CORS on API gateway with Lambda proxy integration?

To enable CORS for the Lambda proxy integration, you must add Access-Control-Allow-Origin: domain-name to the output headers . domain-name can be * for any domain name. The output body is marshalled to the frontend as the method response payload.


1 Answers

I did a bit of digging on this and ran into a couple realizations.

By default, it seems that no "origin" header passed in the API Gateway events. (I created a fresh serverless project, and just echoed back exactly what the API gateway event was.) So this is coming from some other source. I figured it may be a custom domain, and tested that. No dice.

My only other guess is that you have this behind some other layer (CloudFront?) that is forwarding these headers for you. If that ends up being the case, I would suggest you look and see if you can make it forward these headers for the POST request as it is for the GET request.

My only other final thought if none of the above is true is that there is some magic going on in some of the express middleware. I doubt this is the case.

For reference, this was my full serverless.yml and handler.js I tested with as well as a full unaltered event object I got in the endpoint.

service: so-test

provider:
name: aws
runtime: nodejs8.10

functions:
myGetFunction:
    handler: handler.hello
    events:
    - http:
        path: /endpoint
        method: get
        cors: true
myPostFunction:
    handler: handler.hello
    events:
    - http:
        path: /endpoint
        method: post
        cors: true

And the nodejs code:

'use strict';

module.exports.hello = async (event, context) => {
return {
    statusCode: 200,
    body: JSON.stringify({
    message: 'Go Serverless v1.0! Your function executed successfully!',
    input: event,
    }),
};
};

Finally the response object

{
    "message": "Go Serverless v1.0! Your function executed successfully!",
    "input": {
        "resource": "/endpoint",
        "path": "/test/endpoint",
        "httpMethod": "GET",
        "headers": {
            "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
            "Accept-Encoding": "gzip, deflate, br",
            "Accept-Language": "en-US,en;q=0.9",
            "CloudFront-Forwarded-Proto": "https",
            "CloudFront-Is-Desktop-Viewer": "true",
            "CloudFront-Is-Mobile-Viewer": "false",
            "CloudFront-Is-SmartTV-Viewer": "false",
            "CloudFront-Is-Tablet-Viewer": "false",
            "CloudFront-Viewer-Country": "US",
            "Host": "so-test.serverless-examples.com",
            "upgrade-insecure-requests": "1",
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
            "Via": "2.0 f92491812e422470607f365e923929b5.cloudfront.net (CloudFront)",
            "X-Amz-Cf-Id": "6AwZPV3uCYxseJIAmsGzhApzRostCiLXwwM3XsbSJP4K8hQx11MSgw==",
            "X-Amzn-Trace-Id": "Root=1-5c086dd9-bce03ab0c216116fa6de9786",
            "X-Forwarded-For": "55.55.55.555, 70.132.32.155",
            "X-Forwarded-Port": "443",
            "X-Forwarded-Proto": "https"
        },
        "multiValueHeaders": {
            "Accept": [
                "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"
            ],
            "Accept-Encoding": [
                "gzip, deflate, br"
            ],
            "Accept-Language": [
                "en-US,en;q=0.9"
            ],
            "CloudFront-Forwarded-Proto": [
                "https"
            ],
            "CloudFront-Is-Desktop-Viewer": [
                "true"
            ],
            "CloudFront-Is-Mobile-Viewer": [
                "false"
            ],
            "CloudFront-Is-SmartTV-Viewer": [
                "false"
            ],
            "CloudFront-Is-Tablet-Viewer": [
                "false"
            ],
            "CloudFront-Viewer-Country": [
                "US"
            ],
            "Host": [
                "so-test.serverless-examples.com"
            ],
            "upgrade-insecure-requests": [
                "1"
            ],
            "User-Agent": [
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36"
            ],
            "Via": [
                "2.0 f92491812e422470607f365e923929b5.cloudfront.net (CloudFront)"
            ],
            "X-Amz-Cf-Id": [
                "6AwZPV3uCYxseJIAmsGzhApzRostCiLXwwM3XsbSJP4K8hQx11MSgw=="
            ],
            "X-Amzn-Trace-Id": [
                "Root=1-5c086dd9-bce03ab0c216116fa6de9786"
            ],
            "X-Forwarded-For": [
                "55.55.55.555, 70.132.32.155"
            ],
            "X-Forwarded-Port": [
                "443"
            ],
            "X-Forwarded-Proto": [
                "https"
            ]
        },
        "queryStringParameters": null,
        "multiValueQueryStringParameters": null,
        "pathParameters": null,
        "stageVariables": null,
        "requestContext": {
            "resourceId": "mftg6x",
            "resourcePath": "/endpoint",
            "httpMethod": "GET",
            "extendedRequestId": "RdYZ7HaxoAMFQYQ=",
            "requestTime": "06/Dec/2018:00:31:21 +0000",
            "path": "/test/endpoint",
            "accountId": "800708648372",
            "protocol": "HTTP/1.1",
            "stage": "dev",
            "domainPrefix": "so-test",
            "requestTimeEpoch": 1544056281163,
            "requestId": "410632a3-f8ee-11e8-a7e2-7d886f93a0e4",
            "identity": {
                "cognitoIdentityPoolId": null,
                "accountId": null,
                "cognitoIdentityId": null,
                "caller": null,
                "sourceIp": "55.55.55.555",
                "accessKey": null,
                "cognitoAuthenticationType": null,
                "cognitoAuthenticationProvider": null,
                "userArn": null,
                "userAgent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
                "user": null
            },
            "domainName": "so-test.serverless-examples.com",
            "apiId": "txctij0cnp"
        },
        "body": null,
        "isBase64Encoded": false
    }
}
like image 68
Jared Short Avatar answered Sep 27 '22 22:09

Jared Short