Allowing multiple authentication flows in parallel (e.g., in different tabs)
See original GitHub issueIs your feature request related to a problem? Please describe.
We currently use authlib.integrations.flask_client
to authenticate users against Auth0, where they can log in via different connection types (e.g., GitHub, Google, etc.). But users sometimes initiate multiple authentication flows in parallel, as by command- or control-clicking multiple links, each of which opens in a new tab. Even if the user logs in successfully to each of those tabs, each tab (except for the most recently opened one) ultimately errs with:
authlib.integrations.base_client.errors.MismatchingStateError:
mismatching_state: CSRF Warning! State not equal in request and response
That seems to be the result of Authlib using a single session key (e.g., _name_authlib_state_
) to implement CSRF protection, per https://github.com/lepture/authlib/blob/master/authlib/integrations/flask_client/integration.py#L15-L21.
Because each tab has a new value for state
, previously opened tabs’ state values are clobbered in Flask’s session.
Describe the solution you’d like
Might it make sense to use unique session keys instead so that tabs don’t share (and clobber each other’s) state? Similarly for _name_authlib_redirect_uri_
and _name_authlib_nonce_
? E.g., instead of, in pseudocode,
session["_name_authlib_state_"] = "ABC"
session["_name_authlib_redirect_uri_"] = "https://example.com/callback"
session["_name_authlib_nonce_"] = "XYZ"
perhaps an approach along these lines, whereby the key includes the unique state
value?
session["_name_authlib_ABC_"] = {
"redirect_uri": "https://example.com/callback",
"nonce": "XYZ"
}
Describe alternatives you’ve considered
Instead of authlib.integrations.flask_client
, should we perhaps use requests_client.OAuth2Session
instead to achieve this behavior? Would we need to validate state
, redirect_uri
, and nonce
ourselves, though, and also validate the ID token returned from Auth0?
Is a simpler approach already possible perhaps?
Additional context
If a user opens multiple tabs because they’ve command- or control-clicked multiple links (each of which requires authentication), it’s indeed intentional that we want them to authenticate in each of those tabs (especially since their choice of connection type on Auth0’s end might differ per tab). We wouldn’t want one tab, upon encountering a MismatchingStateError
, simply to check whether the user has logged in via another tab and allow the user to proceed.
Thank you!
Issue Analytics
- State:
- Created 3 years ago
- Comments:18 (9 by maintainers)
Top GitHub Comments
This has been fixed in master branch. It will be released in v1.0.
Definitely possible, though probably not a common case? And sounds like a job for garbage collection, no? Old keys (prefixed with, e.g.,
_cs50_authlib_
) insession
could simply be deleted after N minutes, triggered by subsequent calls into the library?This might indeed decrease the probability of state being clobbered, since a user would now have to click a button in multiple tabs. But the risk would still remain, and that definitely feels like a net negative UX-wise? And cookie size could be mitigated with server-side sessions, a la https://flask-session.readthedocs.io/en/latest/?
Thank you for considering!