Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

POST API: preflight OPTIONS request fails with MissingAuthenticationTokenException #521

Closed
rgwood opened this issue Jul 1, 2018 · 6 comments

Comments

@rgwood
Copy link

commented Jul 1, 2018

I'm trying to set up a Lambda function that accepts POST requests using the API class in cloud-aws. Standalone POST requests work as expected, but when they are preflighted with an OPTIONS request for CORS the OPTIONS request fails. This feels like a bug (or a missing feature?) – is anyone able to confirm?

Details

I have created a repo with a minimal reproduction of the issue here. I am calling the POST endpoint in-browser from a web app (and have reproduced the issue in Postman as well).

Before making the POST request, my browser automatically makes a preflight OPTIONS request like so:

OPTIONS /stage/ HTTP/1.1
Host: gtkvcq0tbe.execute-api.us-west-2.amazonaws.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:60.0) Gecko/20100101 Firefox/60.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Origin: http://localhost:4200
Connection: keep-alive
DNT: 1

However, the server comes back with a 404 and an Amazon MissingAuthenticationTokenException:

HTTP/2.0 404 Not Found
content-type: application/json
content-length: 29
date: Sun, 01 Jul 2018 16:21:28 GMT
x-amzn-requestid: ce9b0d9c-7d4a-11e8-bcf6-bdb2ed7b8547
x-amzn-errortype: MissingAuthenticationTokenException
x-amz-apigw-id: JWzdSHWnPHcF6KQ=
x-cache: Error from cloudfront
via: 1.1 7cce0961450ef6caf68e8045176d0c0d.cloudfront.net (CloudFront)
x-amz-cf-id: H4sPhRNnVTSTdoY1dIYVOeDZL1Fb6PIsjNr7KzCGJRWujYJzJX4A3A==
X-Firefox-Spdy: h2

My first thought was to try explicitly handling OPTIONS requests (using API.options()), but then I get a 502 Bad Gateway error instead:

HTTP/2.0 502 Bad Gateway
content-type: application/json
content-length: 36
date: Sun, 01 Jul 2018 16:40:36 GMT
x-amzn-requestid: 7b1cd1cb-7d4d-11e8-bbb8-d18d8e472e6e
x-amz-apigw-id: JW2QuEDTvHcF_Gw=
x-cache: Error from cloudfront
via: 1.1 2a7e9ec6f25ccbf79b1adfa129de8f9c.cloudfront.net (CloudFront)
x-amz-cf-id: Mc3RhH-Mj7e_0uZ-twfwkhgHHMeg3mOrZ3KeomvzM4SOO8G26ckaMQ==
X-Firefox-Spdy: h2

I was unable to find any documentation pertaining to this, or examples that use API.post() successfully.

@lukehoban lukehoban self-assigned this Sep 19, 2018

@lukehoban lukehoban added this to the 0.18 milestone Sep 19, 2018

@lukehoban lukehoban assigned CyrusNajmabadi and unassigned lukehoban Oct 4, 2018

@CyrusNajmabadi

This comment has been minimized.

Copy link
Contributor

commented Oct 4, 2018

hey @rgwood Sorry for the long delay on getting back to you about this.

First off, let me admit that this is not an area of expertise for me :) It's definitely possible that we're not doing something properly in our cloud.API abstraction.

That said, one thing i could suggest you trying is to actually move off of cloud.API and attempt to swithc over to cloud.HttpServer. cloud.HttpServer attempts to actually cut out pulumi as much as possible from this, and is intended to give you a much-closer-to-"http" experience.

Simplified: the idea behind cloud.HttpServer is that it provides you with an API surface and implementation that should be far closer to the native node "http" module. Because of that, you are not limited into only being able to use what we we support. Instead, you should be able to use any existing http middleware (like 'express'), with the intent that those should be able to handle these scenario properly with far more battle tested code. The way you'd use this api is as follows:

import * as cloud from "@pulumi/cloud";

// here we use 'express', but you should be able to use any middleware package you prefer.
import * as express from "express";

const server = new cloud.HttpServer("myexpress", () => {
    const app = express();

    // Basic route example.  Feel free to do whatever you need for CORS.  Example resources here:
    // https://expressjs.com/en/resources/middleware/cors.html
    app.get("/", (req, res) => {
        res.json({ succeeded: true });
    });

    // Return the 'express' instance to Pulumi.  This will be what we install in the AWS lambda
    return app;
});

In this new model, pulumi tries to get out of the way as much as possible. All we try to do is get you from the lambda to your http middleware with minimal fuss.

I hope this can help out here! These are definitely more complex scenarios than what we've tested explicitly. So i can't give any guarantees. If you do run into problems here though i would like to know about them so we can try to figure out what's wrong, even when trying to go this newer route.

Thanks much!

@rgwood

This comment has been minimized.

Copy link
Author

commented Oct 4, 2018

Thanks Cyrus! That sounds good, I'll look into cloud.HttpServer.

@CyrusNajmabadi

This comment has been minimized.

Copy link
Contributor

commented Oct 4, 2018

@rgwood Great! Note: this is a very fresh API. It may not have been published yet in a non-dev package. But we should be cutting a new release very soon. API docs and impelmentation are here:

https://github.com/pulumi/pulumi-cloud/blob/master/api/httpServer.ts
https://github.com/pulumi/pulumi-cloud/blob/master/aws/httpServer.ts

@CyrusNajmabadi CyrusNajmabadi modified the milestones: 0.18, 0.19 Oct 5, 2018

@CyrusNajmabadi

This comment has been minimized.

Copy link
Contributor

commented Oct 5, 2018

Moving out for now. Currently waiting to hear back if this is a viable approach for Reilly. :)

@rgwood

This comment has been minimized.

Copy link
Author

commented Oct 5, 2018

I won't be able to look into cloud.HttpServer with a high priority (although I am curious and will give it a spin when I can), so don't wait on me.

After getting blocked by this issue, I moved on to a lower-level solution using lambda.Function from @pulumi/aws to upload a Lambda deployment package generated by Serverless Framework. Seems good so far.

@CyrusNajmabadi

This comment has been minimized.

Copy link
Contributor

commented Oct 30, 2018

I'm going to close this out. It sounds like there are three viable approaches that can be taken:

  1. using HttpServer, and ideally getting the full range of http options there.
  2. using aws.apigateway.x.Api and also getting full access to the information AWS passed along in apigateway.
  3. directly creating lambdas and managing them yourself (as @rgwood has done).

cloud.API is in that unfortunate middle ground where it was written early, tries to be a uniform service over many providers, but then lacks fine grained control in scenarios like this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants
You can’t perform that action at this time.