Bug 219150

Summary: Safari does not allow first-party JS cookie to be set after SSO flow
Product: WebKit Reporter: Lukas Röllin (Swisscom) <lukas.roellin>
Component: New BugsAssignee: Nobody <webkit-unassigned>
Status: NEW ---    
Severity: Normal CC: achristensen, beidson, ericlaw, me, webkit-bug-importer, wilander
Priority: P2 Keywords: InRadar
Version: Safari 14   
Hardware: iPhone / iPad   
OS: Unspecified   

Description Lukas Röllin (Swisscom) 2020-11-19 01:56:19 PST
Hi

We have a web app, https://tv.blue.ch/. Users can log in via SSO (OAuth), but there is also a developer login which does not go over any other page (it logs in directly).

We have a bug since iOS 14

The flow is the following:

1. Obtain session token,
  1. Normal SSO Flow: we get SSO token, send that to our backend, and receive a session token
  2. Dev Flow: the user enters the session token directly into our app
2. Save the session token via `document.cookie = 'session=...'

We have found the following behavior:

- When users go to our page, log in via SSO and then come back, our JS cookies (document.cookie = ...) are _not_ set
- When dev users go to our page, log in via directly entering a session token via a hidden form, the cookies are set

The SSO flow sends the users to another page, which has a callback URL back to our page (see 1.1 above).

Note that we are only interested in cookies set by our own app! We do not care about any cookies set during the SSO flow. We think we're triggering some tracking protection.
Comment 1 Lukas Röllin (Swisscom) 2020-11-19 01:57:28 PST
Note: if you want to try it out, tell me a way how I can privately send you credentials :)
Comment 2 Lukas Röllin (Swisscom) 2020-11-19 04:50:05 PST
I think it may be due to how we set the cookies without user interaction?

1. User goes to our site ("A")
2. User clicks on login button (*user interaction*)
3. User gets to SSO flow (multiple pages of site "B") 
4. User gets redirected back to site "A", and without further user interaction, the cookies are set
Comment 3 John Wilander 2020-11-19 19:04:55 PST
There is no need for user interaction to set cookies as first party website. Are you saying that JavaScript running in the webpage of the top frame cannot set cookies?
Comment 4 Lukas Röllin (Swisscom) 2020-11-19 23:44:35 PST
Hi John

Ok, yes I did indeed do an experiment to check the interactions, but it didn't work.

Yes you are correct. Regarding the top frame, you're talking about iframes etc? We do not employ any of those.

Two things to note:
- Our app is an SPA
- We can use Chrome on Mac, or Safari 13 on Mac (Mojave) fine, as some counterpoints. 

1. User goes to our page, clicks on login button
2. User is sent to SSO flow (via window.open(ssoSite, '_self')
3. SSO flow eventually calls us back with the credentials necessary for us to log him in (sends the user to a specified URL)
4. We use those against our backend, and get a session token (valid in our backend's realm) back
5. We store that session token via document.cookie, among other similar tokens

These are not stored.

If however, you swap steps 1-3 with a hidden form where the devs can enter a session token directly, and swap step 4 with a simplified step of simply checking the validity, it works (the cookies are stored). Note that in this case, the user never leaves our page.
Comment 5 Lukas Röllin (Swisscom) 2020-11-20 00:36:22 PST
I have made another finding.

- It seems like SameSite=Lax instead of SameSite=Strict seems to alleviate the problem

As flags go, we're using Secure, and until now SameSite=Strict.

Side note: we do not rely on cookies being sent to any backend server (they are on a completely different, non-user facing domain anyway). We authenticate our requests to our backend by manually setting an Authorization header (put together by reading the value in the cookie (and in-memory from then on)). So we rely only on having those cookies available via first-party JS.

Would you have any idea why SameSite=Lax cookies are allowed to be stored, while SameSite=Strict cookies do not, after an SSO flow?

As a definition, "allowed to be stored" means that I can
1. Set the cookies via document.cookie = '...'
2. Read the cookie via document.cookie = '...'

So far, 'not stored' meant that the (1) completed (without any error message in any console), while (2) was empty
Comment 6 Radar WebKit Bug Importer 2020-11-26 03:26:05 PST
<rdar://problem/71747820>
Comment 7 Ramiro Jr Franco 2021-04-28 10:55:44 PDT
I'm experiencing a similar issue, when a user is sent via a send grid redirect to our site, our SPA is unable to set a cookie as Strict via JS on the client. Switching to Lax does seem to alleviate the issue.
Comment 8 Eric Lawrence (MSFT) 2021-04-29 11:04:32 PDT
Is this the issue that Chrome fixed in 2019?

https://bugs.chromium.org/p/chromium/issues/detail?id=958331#c8