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

Entrypoint for webpack-dev-middleware Options - adding custom headers #5544

Closed
bfsmithATL opened this issue Oct 23, 2018 · 5 comments
Closed

Comments

@bfsmithATL
Copy link

Hello, I have a question for the community, and possible feature request. First qualifier- I have a good understanding and working knowledge of CORS. I realize there are a lot of issues opened here related to CORS and most end up being a configuration issue or lack of understanding. I assure you this isn't one of them. Bear with me on the verbose explanation, I honestly don't know of a better way to give you readers all the needed information:

We have a particular scenario where we have a React app (webpackdev server on localhost:3000) being driven by UI Automation testing (TestCafe) and are using a Node Express instance (localhost:3002) to function as a synthetic backend REST API (fake API). This assures clean separation of the React app under test and allows Automation testing to run entirely stand-alone, separated from network connectivity.

In addition to this, we have another Node Express instance (on localhost:8080) which serves Environment data. Some readers maybe saying "meh? but why?" right about now. This is required in our prod env, since it connects to vcaps and retrieves env data from the Cloud Foundry host(s). Yes you guessed it, in our package.json we have proxy: localhost:8080 already specified so we are able to get calls for Env over to this Node Express 8080 service. There appears to be an issue already logged to get documentation put together on specifying multiple proxies here: #3348 but I don’t think this would solve this issue anyway.

We have a method in the React App which will probe a URL for an SSO system (simple Axios GET) and we asses the return code. If we don't get a 200/302, we park the user on an "oops" page. If we get a 200/302, we navigate the user to that URL for authentication. During Automation, this URL is handled by a method on the fake API which redirects the React app back to the default route with a fake query string param and value. This is done to emulate leaving our React app to visit a SSO page, and return with a token.

Normal order of operations should be:

  1. We fire up our fake API on localhost:3002
  2. Automation testing fires up our React app on localhost:3000, which also fires up the Env on localhost:8080
  3. Axios probes fake SSO URL, it's happy, then navigate.
  4. Fake API redirects user back to React app on the root route with a fake query param and value which emulates real SSO interaction.
  5. We go along further into the app, everyone is happy.

The Problem: Actual behavior deviates on step 3, the Catch statement for Axios traps an exception and it happens to be with CORS.

The offending code:
Axios.get('http://localhost:3002/fakeSSO').then((response)=>{ if(response.status === 200){ this.props.actions.toBeAuthenticated() } else{ console.log('Auth Validation failure) this.props.history.push('/SSOFailure') } }).catch(function (e) { console.log('Auth Validation failure. Error is: ' + JSON.stringify(e)) self.props.history.push('/SSOFailure') })

So the probe call actually reaches the fake API (localhost:3002/fakeSSO) and it redirects the browser back to localhost:3000/?code=blah. Since WebPackDev server is responsible for responding to the new inbound (redirected) request, it doesn't specify an Access-Control-Allow-Origin header and value, Chrome sees this as a CORS violation, which generates an exception that is subsequently handed back to Axios and dumps us in that catch.

In the Catch statement following the Axios probe call, we get “Access to XMLHttpRequest at 'http://localhost:3000/?code=imafakessoauthcode' (redirected from 'http://localhost:3002/oauth/authorize') from origin 'null' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.”

The key here is from origin 'null’ in the exception. Localhost:3000 is the HTTP server processing this request, as redirected by localhost:3002. So the culprit is WebPackDev server, oddly in this scenario, for the CORS violation, even though we’re dealing with only the local “domain.” The Headers for this request are:

GET /?code=imafakessoauthcode HTTP/1.1
Host: localhost:3000
Connection: keep-alive
Accept: application/json, text/plain, /
Origin: null
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36
Referer: http://localhost:3000/SSOFailure
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
If-None-Match: W/"924-+pfIc+6fpsivV35xSfuZUmUTh5o"

To remedy the WebPackDev server driving our React app, I had to introduce an option object in the webpack-dev-middleware, forcing the local server to produce the 'Access-Control-Allow-Origin' header and '*' value as prescribed by this team's docs over here: https://github.com/webpack/webpack-dev-middleware Editing node_modules\webpack-dev-server\lib\Server.js and in function Server(compiler, options) right where options is being assessed, I add options = {...options, headers: {'Access-Control-Allow-Origin': '*'}} and we're good to go. The proper header and * value is on the request, Chrome and its CORS layer is happy, subsequently our React Axios promise is happy, so on and so forth... NOTE: I simply cannot install a Chrome extension to mitigate this issue, that is not a holistic solution.

Many of you readers are cringing right now. I am as well. This "fix" feels tremendously hacky and of course will break the next time we upgrade Create-React-App. Does this scenario justify adding a feature to Create-React-App to easily accommodate dropping in custom headers via some other entrypoint, such as in package.json? OR is there already some other entrypoint that I don't know about?

Let me know what you all think. I'd be happy to resubmit a less verbose issue to function as a feature request :-)

Thank you for patience, if you're reading this, then you were patient enough to read this giant dissertation, lol

@bfsmithATL
Copy link
Author

Just curious if this question has been reviewed or not

@stale
Copy link

stale bot commented Dec 14, 2018

This issue has been automatically marked as stale because it has not had any recent activity. It will be closed in 5 days if no further activity occurs.

@stale stale bot added the stale label Dec 14, 2018
@bfsmithATL
Copy link
Author

Bummer, the StaleBot has tagged this thread. I’d still really like to hear from anyone out there in the ether that might have a solution or info about this question. Thanks!!

@stale stale bot removed the stale label Dec 14, 2018
@stale
Copy link

stale bot commented Jan 13, 2019

This issue has been automatically marked as stale because it has not had any recent activity. It will be closed in 5 days if no further activity occurs.

@stale stale bot added the stale label Jan 13, 2019
@stale
Copy link

stale bot commented Jan 18, 2019

This issue has been automatically closed because it has not had any recent activity. If you have a question or comment, please open a new issue.

@stale stale bot closed this as completed Jan 18, 2019
@lock lock bot locked and limited conversation to collaborators Jan 23, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

2 participants