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

SameSite=Strict cookies break the oauth flow (Grant: missing session or misconfigured provider) #199

Open
vicb opened this issue Oct 9, 2020 · 12 comments

Comments

@vicb
Copy link

vicb commented Oct 9, 2020

TL;DR do no use strict SameSite cookies.

From MDN:

Strict SameSite Cookies will only be sent in a first-party context and not be sent along with requests initiated by third party websites.

This means that the session cookie will not be sent when the oauth provider redirects to your oauth callback (.../connect/<provider>/callback) at the end of the Authorization Request.

It means that at that point grant will not be able to get the configuration information as those are stored in the session. As a result grant will redirect you to the root of your site with an Grant: missing session or misconfigured provider error, i.e. https://example.com/?error=Grant%3A%20missing%20session%20or%20misconfigured%20provider.

Using SameSite=Lax which is the default value in modern browsers solve this issue.


I thought everything was finally working until I tried to login from an incognito window.

My app is at flyxc.app
Grant is mounted on oauth
You can see my config and the express server on github.

So the first time I tried to authenticate, I have:

Request URL: [10ms] https://flyxc.app/oauth/google?x=85&y=24

Request URL: [215ms] https://accounts.google.com/o/oauth2/auth?client_id=754556983658-qscerk4tpsu8mgb1kfcq5gvf8hmqsamn.apps.googleusercontent.com&response_type=code&redirect_uri=https%3A%2F%2Fflyxc.app%2Foauth%2Fgoogle%2Fcallback&scope=openid%20email%20profile&state=72773a896d3aa87c33fe82ba58f25b5988b92966&nonce=247053f8ca6cd2fe238cb64e1de0ff3340395cea&code_challenge_method=S256&code_challenge=blH_5sDhwsE9-ZRoGA2fD12HT1MY-WeNr4GnoP0DiZc

Then it takes some time to enter the email, do the 2 step verification.
There are a few more requests during this time:

Request URL: [28.56s] https://accounts.google.com/CheckCookie?hl=en&checkedDomains=youtube&[...]

Request URL: [28.66s] https://accounts.youtube.com/accounts/SetSID?ssdc=1&[...]

Request URL: [28.85s] https://accounts.google.com/signin/oauth/consent?authuser=0&[...]

Request URL: [29.22s] https://flyxc.app/oauth/google/callback?state=72773a896d3aa87c33fe82ba58f25b5988b92966&code=[...]&scope=email+profile+openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&authuser=0&prompt=none

At this point grant redirect to "/"

[29.41s] https://flyxc.app/?error=Grant%3A%20missing%20session%20or%20misconfigured%20provider

Question: Why would grant ever want to redirect me to / instead of my callback (/device.html) ?

If I initiate the login again:

Request URL: [5.2m] https://accounts.google.com/o/oauth2/auth?client_id=754556983658-qscerk4tpsu8mgb1kfcq5gvf8hmqsamn.apps.googleusercontent.com&response_type=code&redirect_uri=https%3A%2F%2Fflyxc.app%2Foauth%2Fgoogle%2Fcallback&scope=openid%20email%20profile&state=31c00ed60daa1488cc348763a895c285a0692ed1&nonce=0556040886b7f73a8a16546d83795deeacee1375&code_challenge_method=S256&code_challenge=V3xFedAexGB30MY3ZUFbjdS23ghNds9lXv9h_Rf8ooI

Request URL: [5.2m] https://flyxc.app/oauth/google/callback?state=31c00ed60daa1488cc348763a895c285a0692ed1&code=[...]&scope=email+profile+openid+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&authuser=0&prompt=none

And grant finally logged me in without any error:

Request URL: [5.2m] https://flyxc.app/devices.html, auth ok.

I do see the session cookie created the first time I navigate to the /oauth/google

Do you have any idea of what could wrong when grant receives the code ?
Is there a timeout that could cause the issue ?

Otherwise any idea on how I can debug this ? What should I log ?

Thanks !

@vicb
Copy link
Author

vicb commented Oct 9, 2020

A few thing I have tried:

Use the same express settings as in the example:
.use(session({secret: 'grant', saveUninitialized: true, resave: false}))
The outcome is the same.

Try to get debug traces by running DEBUG=req,res,json node app/server.js.

There is absolutely no traces on the first attempt.

Seconds attempt looks good:

req POST https://accounts.google.com/o/oauth2/token
    user-agent:     simov/grant/5.4.4
    ...    
form
    grant_type:    authorization_code
    code: ...

res 200 OK
    x-google-esf-cloud-client-params:           backend_service_name: "oauth2.googleapis.com" backend_fully_qualified_method: "google.identity.oauth2.OAuth2Service.GetToken"
     ...
json
    access_token: ...
    expires_in:   3599
    scope:        https://www.googleapis.com/auth/userinfo.email openid https://www.googleapis.com/auth/userinfo.profile
    token_type:   Bearer
    id_token: ...
req GET https://openidconnect.googleapis.com/v1/userinfo
    user-agent:    simov/grant/5.4.4
    Host:          openidconnect.googleapis.com
res 200 OK
    x-google-esf-cloud-client-params:           backend_service_name: "openidconnect.googleapis.com" backend_fully_qualified_method: "google.identity.oauth2.openidconnect.v1.OpenIdConnectService.GetUserInfo"
    ...
json
    name:           Victor Berchet
    ...

No traces on the first attempt looks weird. It means that grant does not even tried to get the token.

@vicb
Copy link
Author

vicb commented Oct 9, 2020

The playground seems to works ok.

It could be either a different config or a different framework... or more likely some error on my side !

@simov
Copy link
Owner

simov commented Oct 9, 2020

A few things to note here:

  1. Grant redirects to / by default when it cannot load a provider, see here
  2. DEBUG can log only requests happening on the server, the authorization step is done in the browser

My only assumption right now is that for some reason the session is not being loaded when you get back to the redirect URL /oauth/google/callback.

@vicb
Copy link
Author

vicb commented Oct 9, 2020

My only assumption right now is that for some reason the session is not being loaded when you get back to the redirect URL /oauth/google/callback.

Could you please point me to what point in the code I should check that ?
I will also try to add DEBUG trace for redis to see if I'm trying to read something.

@simov
Copy link
Owner

simov commented Oct 9, 2020

You can put a simple handler before grant:

.use('/oauth/:provider/:callback?', (req, res, next) => {
  console.log(req.session.grant)
  next()
})

This will tell you what's loaded inside the session before entering the Grant handler. If that key is missing or empty, or otherwise the data inside it does not match the :provider from the path, then Grant will redirect you to / with a generic error message:

Grant: missing session or misconfigured provider

@vicb
Copy link
Author

vicb commented Oct 9, 2020

Yep there is definitely something fishy with the session:

$ DEBUG=req,express-session,ioredis:* node app/server.js

Before connection:

  express-session no SID sent, generating session +809ms
  express-session no SID sent, generating session +36ms
  express-session no SID sent, generating session +169ms
  express-session no SID sent, generating session +3s

On trying to login

  express-session saving .... +1ms
  ioredis:redis write command[35.224.153.24:18918]: 0 -> set('sess:mDolhG5ItZcx8_...,{"cookie":{"originalMaxAge":null,"expires":null,"secure":false,"httpOnly":true,"path":"/","sameSite":true},"grant":{"provider":"google","dynamic":{"x":"129","y":" ... <REDACTED full-length="855">') +10s

  express-session saving mDolhG5ItZcx8_... +55ms
  ioredis:redis write command[35.224.153.24:18918]: 0 -> set('sess:mDolhG5ItZcx8_...,{"cookie":{"originalMaxAge":null,"expires":null,"secure":false,"httpOnly":true,"path":"/","sameSite":true},"grant":{"provider":"google","dynamic":{"x":"129","y":" ... <REDACTED full-length="855">') +55ms
  express-session split response +1ms
  express-session set-cookie session=s%3AmDolhG5ItZcx8_SBKKyiKPPDxdVILEJ4.mOu045Ju6cB0ncmidmQKs9kWRgCS59jcYy1kt4sAY%2FQ; Path=/; HttpOnly; SameSite=Strict +0ms

When back to google/callback:

  express-session no SID sent, generating session +2m
  express-session saving w_egXuW8_... +1ms
  ioredis:redis write command[35.224.153.24:18918]: 0 -> set([ 'sess:w_egXuW8_...', '{"cookie":{"originalMaxAge":null,"expires":null,"secure":false,"httpOnly":true,"path":"/","sameSite":true},"grant":{}}', 'EX', '86400' ]) +2m

For some reason the session is retrieved (no SID sent) and a new one is generated. I'll debug that more tomorrow.

@simov
Copy link
Owner

simov commented Oct 9, 2020

You can try setting up saveUninitialized to true. Another option to play around is the resave one, although that should stay as false in most cases.

@vicb
Copy link
Author

vicb commented Oct 9, 2020

I think I found the culprit:

cookie: {
        maxAge: 3600,
        httpOnly: true,
        path: '/',
        sameSite: true,
        secure: USE_SECURE_COOKIES,
      },

It looks like sameSite: true, causes the session cookie not to be attached when google redirect to the callback.

I did a quick test and it seems to be the root cause. I'll confirm later today when I have time to test extensively.

Thanks for your help !

@vicb
Copy link
Author

vicb commented Oct 9, 2020

I confirm that this solves the problem.

Would you like me to send a PR to add a warning in the examples and the doc ?

vicb added a commit to vicb/flyXC that referenced this issue Oct 9, 2020
@simov
Copy link
Owner

simov commented Oct 10, 2020

Thanks for the feedback @vicb, that was really helpful.

I don't think we need to update the examples, as they strive to be short and simple, not necessarily with the best setup for production.

As for the docs, probably additional Cookies section under Misc? We definitely need some info about this somewhere, I'm just not sure yet.

Otherwise we can keep this issue open for now as a reference too, probably with updated title?

@vicb vicb changed the title Error with the Google Oauth provider, need help to debug. SameSite=strict cookies break the oauth flow Oct 10, 2020
@vicb vicb changed the title SameSite=strict cookies break the oauth flow SameSite=Strict cookies break the oauth flow (Grant: missing session or misconfigured provider) Oct 10, 2020
@vicb
Copy link
Author

vicb commented Oct 10, 2020

I have updated the title and description of the issue.

I think a "FAQ" or "Troubleshooting" section in the docs might be helpful to explain the most common errors people encounters. Explaining why/when "Grant: missing session or misconfigured provider" error is generated would be great. One the the thing this entry should tell to check is the SameSite setting.

@Twiggeh
Copy link

Twiggeh commented Jan 3, 2021

Same thing happens with sameSite set to none :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants