rkusa/koa-passport

CORS issue when serving from different port or domain.

Panoplos opened this issue · 6 comments

I have a React app that is being served from a different port (and potentially different domain) than my API server. I am using koa-passport to authenticate the user of the API, and I have been able to get a local "strategy" working without issue via dev server proxy setting; however, when I attempt to authenticate the user via the Google OAuth2 strategy, I am running into CORS issues, as follows:

XMLHttpRequest cannot load https://accounts.google.com/o/oauth2/auth?response_type=code&redirect_uri=h…d=<>.apps.googleusercontent.com. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 405.
(Note that <<SECRET>> is used here to mask sensitive info.)

The API server is currently running on port 7000.

I have tried modifying both the koa and node headers without any success.

One question I have is, does koa-passport (and perhaps passport.js for that matter) use the client req headers for an internal/server side web action that should be considered decoupled from the client?

Anyway, would greatly appreciate any insights here. 😄

rkusa commented

You have to update your application to respond to preflight request properly. While you could do this manually, there are also middleware for this, like https://github.com/koajs/cors

One question I have is, does koa-passport (and perhaps passport.js for that matter) use the client req headers for an internal/server side web action that should be considered decoupled from the client?

I don't quite understand this question, could you maybe rephrase it? Thanks

Yes, I have tried cors, but it still gives the error.

At this point, I have tried everything from using a proxy (8000 -> 3000 [app server] & 7000 [api server]) to manipulating headers directly. I have also set up API Credentials in Google Developer Console as follows:
screen shot 2017-04-13 at 8 06 58 pm

Here are the ngnix proxy provided headers before making the call to passport.authenticate('google', ...):

  <-- GET /api/google/signin
/api/google/singin called with
ctx -> {"request":{"method":"GET","url":"/api/google/signin","header":{"host":"localhost:8000","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36","accept":"*/*","accept-encoding":"gzip, deflate, sdch, br","accept-language":"en-US,en;q=0.8,ja;q=0.6","cookie":"koa.sid=KDUHfnnL6ubr5OXet-JKC-QayXNhNIPz; koa.sid.sig=1eviWO_8GcapCZY9mA0jTN57a6U","dnt":"1","referer":"http://localhost:8000/signin?redirect=%2Ftodo-pubsub","x-forwarded-for":"::1","x-forwarded-proto":"http","x-real-ip":"::1","x-requested-with":"XMLHttpRequest"}},"response":{"status":404,"message":"Not Found","header":{}},"app":{"subdomainOffset":2,"proxy":false,"env":"development"},"originalUrl":"/api/google/signin","req":"<original node req>","res":"<original node res>","socket":"<original node socket>"} && next -> function next() {
          return dispatch(i + 1)
        }
ctx.req.headers -> {"host":"localhost:8000","user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36","accept":"*/*","accept-encoding":"gzip, deflate, sdch, br","accept-language":"en-US,en;q=0.8,ja;q=0.6","cookie":"koa.sid=KDUHfnnL6ubr5OXet-JKC-QayXNhNIPz; koa.sid.sig=1eviWO_8GcapCZY9mA0jTN57a6U","dnt":"1","referer":"http://localhost:8000/signin?redirect=%2Ftodo-pubsub","x-forwarded-for":"::1","x-forwarded-proto":"http","x-real-ip":"::1","x-requested-with":"XMLHttpRequest"}
ctx.req.rawHeaders -> Host,localhost:8000,User-Agent,Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36,Accept,*/*,Accept-Encoding,gzip, deflate, sdch, br,Accept-Language,en-US,en;q=0.8,ja;q=0.6,Cookie,koa.sid=KDUHfnnL6ubr5OXet-JKC-QayXNhNIPz; koa.sid.sig=1eviWO_8GcapCZY9mA0jTN57a6U,Dnt,1,Referer,http://localhost:8000/signin?redirect=%2Ftodo-pubsub,X-Forwarded-For,::1,X-Forwarded-Proto,http,X-Real-Ip,::1,X-Requested-With,XMLHttpRequest
  --> GET /api/google/signin 302 4ms 0b

This still results in:

XMLHttpRequest cannot load https://accounts.google.com/o/oauth2/auth?response_type=code&redirect_uri=h…d=<<SECRET>>.apps.googleusercontent.com. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. The response had HTTP status code 405.

Actually, you can ignore that question above, as I understood it is necessary due to browser redirect to the actual authentication page of the OAuth2 provider.

The main problem still remains unsolved, though.

Note that I have been able to get this to work when the Web App and the API are served from the same port, but this is impractical for my deployment requirements.

rkusa commented

Have you added the CORS middleware before the passport middleware?

Yes, it is the first app.use I call.

OK, a little progress, it looks like this is an issue of trying to call the backend through an ajax call. When using the browser location, it takes care of the CORS issue, but I have run into another issue that I will post.

Working through the issue I was having, I just want to highlight that the order of middleware matters.

I had to put my @koa/cors middleware before my routing middleware for it to work.