HTTP Basic auth with Lambda/API Gateway?

I want to use HTTP Basic auth on one particular function. The username and password can be hardcoded in the source for all I care, or be in env vars.

However, when I pass back the WWW-Authenticate header in my handler’s response it is remapped when it goes through API Gateway to x-amzn-Remapped-WWW-Authenticate, which obviously then doesn’t work. I found some Amazon documentation which confirms this is what is happening, though it doesn’t explain why or if I can get around it.

I can’t find anything about this in the Serverless docs.

Is there any way to do this? I have a feeling it might involve switching from a lambda-proxy function to the other type, but I don’t know where to start.


Edit:

I’ve worked through some of the docs for lambda integration (as opposed to lambda-proxy) and got far enough that I’m attempting once again to set the WWW-Authenticate header, but it’s still being transformed to x-amzn-Remapped-WWW-Authenticate. I find this particular documentation very difficult to follow and I haven’t managed to actually set the response header to 401. I’m not sure whether that would make a difference.

What I currently have is this:

functions:
  report:
    handler: handler.report
    events:
      - http:
          path: report
          method: get
          integration: lambda
          request:
            passThrough: WHEN_NO_TEMPLATES
          response:
            headers:
              Content-Type: integration.response.body.headers.Content-Type
              WWW-Authenticate: integration.response.body.headers.WWW-Authenticate
            template: $input.path('$.body')
            statusCodes:
              401:
                pattern: '.*statusCode.*401.*'

And my implementation looks like this:

callback(null, {
  statusCode: 401,
  headers: {
    'WWW-Authenticate': 'Basic realm="My realm", encoding="UTF-8"',
    'Content-Type': 'application/json',
  },
  body: "no auth",
});

One other possible issue here is that no matter what I try with the quoting in my Basic realm… it comes out in the response header with unwanted extra escaping, for example like this: x-amzn-Remapped-WWW-Authenticate: Basic realm=\"My realm\", encoding=\"UTF-8\", which doesn’t look valid.

1 Like

I would still like to know for future if this is possible.

But my deadline is up and I have given up.

Instead, I moved my endpoint from GET to POST. I replaced the GET endpoint with a response which gives an HTML form challenging for authentication. This posts to the POST endpoint with username and password fields. The POST endpoint now checks these before allowing the protected response. In this way I give a similar user experience to HTTP basic, which will have to do.

I actually made the POST endpoint also accept HTTP basic authentication (because why not, and I’d already written the code), though it will not challenge for this, since I can’t get that WWW-Authenticate header through.

If you are looking for a way to accomplish basic auth from a set of lambda functions … 1) write out the header as something that won’t get remapped like X-WWW-Authenticate. 2) Write a lambda@edge function for OriginResponse that replaces X-WWW-Authenticate with WWW-Authenticate. The Authorization header on the return will be remapped but you can look for that in the lambda and process it just like you would the normal Authorization header. This assumes an architecture of CloudFront to API Gateway to Lambda. This is how I got it to work.

You just need to modify the 401 Unauthorized response template so that it contains the WWW-Authenticate header set to 'Basic'. Apart from that, you’ll need to create a custom authorizer that verifies that the provided credentials are correct. You can find more info here