-
-
Notifications
You must be signed in to change notification settings - Fork 753
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
OAuth redirect lost sometimes due to session store race #2514
Comments
mterrel
added a commit
to mterrel/feathers
that referenced
this issue
Dec 23, 2021
mterrel
added a commit
to mterrel/feathers
that referenced
this issue
Dec 23, 2021
This has been published via #2515. Thank you again for digging into this! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Steps to reproduce
redirect
query parameter set, for example tohttps://example.com/oauth/github?redirect=dashboard
https://example.com/dashboard#access_token=xyz123
. This happens correctly most of the time. But occasionally, the browser is redirected tohttps://example.com#access_token=xyz123
instead.Note that this behavior is difficult to reproduce and appears to require specific timing of external resources (the session store needs to be slow) to trigger the failure.
Expected behavior
At the end of the OAuth flow, the browser should get redirected to the path requested by the initial
redirect
query parameter 100% of the time.Actual behavior
At the end of the OAuth flow, the browser gets redirected to the root of the site about 5% of the time (about 1 of every 20 requests redirects incorrectly).
System configuration
Tell us about the applicable parts of your setup.
Module versions (especially the part that's not working):
Feathers 4.5.x:
NodeJS version:
14.18
Operating System:
Linux
Browser Version:
Chrome 96.0.4664.110 / Win10
React Native Version:
N/A
Module Loader:
None
Analysis
I've looked carefully at this issue by turning on all the Feathers-related debugs and looking closely at the network requests in the browser. I think the issue is due to a race condition with Express sessions in the Feathers OAuth code. Note that we happen to be using
connect-session-sequelize
and a Postgres DB for our Express session store, but I believe this can happen with any session store if the store is sufficiently slow.Here's what I found. Please correct me if I've gotten anything wrong.
Feathers and Grant both use the same Express session to store information about the OAuth transaction. Feathers uses it to store the
redirect
query parameter and the remaining other query parameters as well.Successful case
In the successful OAuth case, Feathers creates the Express session during the request to
/oauth/github
, setting the session cookie ID to some ID we'll call "A". Feathers code owns this Express handler (see/packages/authentication-oauth/src/express.ts:49
). Feathers then generates a redirect response to/oauth/connect/github
and Express session stores the session (in our case, into Postgres withconnect-session-sequelize
) as part of standard Express flow at the end of a request. The browser now contacts/oauth/connect/github
, which is handled by Grant. Express looks for an existing Express session using ID "A", finds the session in Postgres and uses it, passing the session to the Grant handler. A few steps later, when the client requests/oauth/github/authenticate
, Feathers again looks up session ID "A", finds it, and successfully retrieves theredirect
property from the session, which eventually gets passed back to the browser in the final redirect of the flow.The browser dev tools network panel in this case shows a single consistent cookie
connect.sid
value across all of the requests and responses.Failing case
In the failing case, Feathers creates the Express session during the request
/oauth/github
, setting the session ID to "A". And Express session begins saving the session to Postgres, BUT this does not complete prior to Feathers sending the redirect to and the client accessing/oauth/connect/github
. When the browser does access/oauth/connect/github
, the session cookie with session ID "A" is set, so Express looks for an existing Express session using ID "A" in Postgres, does not find it in the database (yet) and creates a new Express session with ID "B", overwriting the session cookie ID in its response. Session "A", which has the originalredirect
parameter stored is orphaned and never used again. Later, when the client requests/oauth/github/authenticate
, Express looks up session ID "B" and finds it, but theredirect
property in session "B" was never set and is undefined, so cannot be passed back in the final redirect to the browser.The browser dev tools network panel in the failing case shows two different
connect.sid
values. Theconnect.sid
response to/oauth/github
and the request to/oauth/connect/github
use one ID and all the subsequent responses and requests use a differentconnect.sid
. This is consistent with the explanation above.Suggested fix
Because Feathers issues a redirect and expects the Express session to be saved before the browser initiates the next request, Feathers should explicitly save the Express session and wait for completion prior to issuing the initial redirect.
This is consistent with guidance from Express session's docs:
Also see issues like https://github.com/expressjs/session/issues/660
So I think the fix is to modify
/packages/authentication-oauth/src/express.ts:60
roughly like this:I've made a PR (#2515) to address this issue.
The text was updated successfully, but these errors were encountered: