CORS, withCredentials and third party cookies - cookies

I'm trying to do a CORS GET that sends the cookie along with it. I've set all the headers (access-control-allow-origin, access-control-allow-credentials, access-control-allow-headers) in the server and am using withCredentials: true and crossDomain: true in the jquery ajax request. Everything works when I tell my browser to allow third-party cookies. Is there any way to do this without forcing visitors to allow third party cookies? I've even tried redirecting the user and redirecting back, but CORS will refuse to send the cookie along. :/
I've tried doing the CORS request via ajax, as well as via an iframe.

I don't think it is possible. See my (old but relevant) blog post on this.
The only bullet-proof way is to use 1st-party cookies (that is, open window in a top-level window like a separate tab, or redirect current window).
In some cases it is not necessary though. Browsers have slightly different notions of what third-party cookie is, and default behavior is also different. This post has a nice overview on these details. So in some cases you could do tricks to enable (or at least detect) use of cookies on the page.
Other workarounds include putting one server under a subdomain of the other (subdomains are usually not considered 3rd-party), or changing the flow so that the user is authenticated by other means than cookies.

if you set cookie (origin 2 set cookie) you should know third party cookie will be used, but if you only get cookie (only send cookie for origin 2 without setting in response) there is no reason third party cookie play a role.
so i think you set a cookie in origin 2 and because of that force you enable third party cookie.
Note that cookies set in CORS responses are subject to normal
third-party cookie policies. In the example above, the page is loaded
from foo.example but the cookie on line 19 is sent by bar.other, and
would thus not be saved if the user's browser is configured to reject
all third-party cookies.
Cross-Origin Resource Sharing mozilla.org

Related

How can I get all 1st and 3rd party cookies from CDP for a given page?

What I need:
I need to get all the currently applicable cookies for a page state. For example, I navigate to a site in the US, the browser has a lot of cookies populated by that page. I then decline all cookies on that site. Afterwards the browser reports much fewer cookies for that page. I need to be able to get that list of applicable cookies for the page as displayed in Chrome's View site information pop-out dialog left of the URL.
What I've tried:
I'm currently using Puppeteer, though I've also tried using Playwright. Both can utilize the Chrome Devtools Protocol (CDP) to gather information about a browser session and other related HTTP data.
I have a use case where I need to see the current state of cookies as it pertains to a web page. CDP provides two methods to accomplish this. Network.getAllCookies and Network.getCookies.
Network.getCookies returns cookies for a given URL, or else it provides all the cookies for the URL of the current page when no URL is provided. The problem with this is it's not a full picture. Network.getCookies does not include 3rd party cookies unless that domain is specifically requested. But there's no way for me to know all the 3rd party cookies for a given page.
If I switch it up and use Network.getAllCookies, that has too much information. It returns with all the cookies currently known to the browser session, regardless of applicability to the current page. For example, if I visit site A, then nav to site B, then I call Network.getAllCookies, I get all of the cookies from both pages since they are all in the same browser context. But I only want the 1st and 3rd party cookies for the current page I'm on.
In a headful browser it is possible to see all the applicable 1st and 3rd party cookies are for a site. If you click on the lock icon (secure site) to the left of the url, there is an option to view cookies. This is the most complete and accurate view of cookies I've come to know. Somehow the browser knows what 3rd party cookies originated from the current page and requests made by the current page and therefore displays them there. But how? And how can I get that list through CDP?
Note that document.cookie is useless as it does not include httpOnly cookies, and to my knowledge also doesn't return detailed cookie information (such as sameSite, secure, expiry, etc.)
I've tried using the CDP session directly attached to both of the above mentioned libraries. I've tried monitoring HTTP requests using Puppeteer and gathering set-cookie data from response headers, but CDP is unreliable when it comes to providing all the response header set-cookie information.
TLDR:
I'm expecting to programmatically retrieve only the relevant cookies for a page visit up to that point. If cookies become irrelevant in that page session, I don't want to receive them any more.
Network.getAllCookies returns too many cookies as it gives the whole browser context and not just the page relevant cookies.
Network.getCookies only returns cookies by a url.
document.cookie only returns application cookies.
How can I get all the 1st and 3rd party cookies that pertain to my current page?
I want this exact list:

OIDC js library reponse cookies are not stored and not attaching for subsequent requests

I am using authcodeflow with PKCE.
Using OIDC js library in the frontend, making calls to adfs getting an auth code and then calling my backend api. The backend api which calls adfs server get the access token and the backend api returns the token as a cookie to the frontend. I can see the cookie in response headers. but That cookie is not stored in browser and not getting added for subsequent requests. I have tried with samesite with all modes -> Lax, None,Strict and not setting.
Is this an issue with OIDC js library or is it blocking the cookies to store in browser?
Update:
Below are the observation with my analysis
Since the OIdc-client-js does not have an option to set flag "withCredentials" to true for the requests. There are no cookies send in the request and response cookies are ignored for the cross origin requests.This changes are marked as enhancement and still not completed in thier github repo.
https://github.com/IdentityModel/oidc-client-js/issues/1062
Is there any way to achieve with this library? or any other libraries for OIDC js
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials
So you are issuing a cookie from an API domain that is a sibling of the WEB domain:
web.mycompany.com
api.mycompany.com
Cookie domain = .mycompany.com
POSSIBLE CAUSES FOR COOKIE BEING DROPPED
Maybe it is the withCredentials flag or maybe due to a lack of user gesture, since the user has not done anything explicit to navigate to api.mycompany.com, such as a browser navigation or clicking a link?
FORCING WITHCREDENTIALS
You can override the prototype like this in order to add the withCredentials property. This is a little hacky but you could limit usage based on the URL and it should let you know whether setting withCredentials resolves your problem:
let open = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url) {
open.apply(this, arguments);
this.withCredentials = true;
}
PROXYING VIA WEB DOMAIN WILL HAVE FEWER COOKIE ISSUES
In my blog post I do something similar to proxy messages containing a refresh token. I use the web's exact domain though, rather than using an API subdomain. This will never be impacted by browser restrictions.

Safari not including cookies in request, but Safari incognito does?

So with my app I allow our users to set their own custom domiain which points to our hosted app on netlify. This works fine, but now the frontend is obviously talking to an api which lives on a different domain.
On the auth cookie I send back from the api, I have SameSite=None which works on all other browsers except for safari where the request does not include the cookie. However, if I go on Safari in incognito, it does include the cookie on the request? My question is:
Why does this work in safari incognito and not normal?
Is there a way to make this work in normal safari?
Here is a more thorough example:
front end:
customersdomain.com
api:
api.myapp.com
Cookie
x-refresh: <cookie_val>
SameSite: none
HttpOnly: true
Secure: true
expires: 1 month
domain: api.myapp.com
My cors has allow credentials set as well and in the request I have credentials set to include.
In Safari 13.1, in order for third party requests to have access to credentials/cookies, you must use the Storage Access API to request access, via an iframe.
This may affect the workings of your app considerably. Please read WebKit's recent blog post for more information about the latest changes to their Intelligent Tracking Prevention.
Before Safari 13.1, there were some temporary compatibility fixes as detailed here to allow for third party requests to have access to cookies. My guess is that the third party domain was flagged by Safari on your device as being a domain that has the potential to track users, and blocked from having access to cookies by default. The domain will remain blocked for as long as you don't clear the cache on Safari. By using an incognito window, the domain was no longer blocked for that session.
SameSite=None compatibility was added to Safari 13, so this shouldn't have contributed to any of your issues.

SameSite attribute in cookies

I have a website a.com that has third party app point to apps.b.com. When I login to a.com, I'm also authenticated to apps.b.com in the background using the same credentials. This is so the users do not have to login to access apps.b.com. I understand that browser sends all the cookies to apps.b.com when making the request to it. This is how it works now. Reading the article https://web.dev/samesite-cookies-explained/ in regards to SameSite attribute, it appears apps.b.com is third party site.
Now do I have to configure web server on a.com to set the cookie to SameSite=none;Secure OR do I have to set the SameSite=none;Secure on web server on apps.b.com?
Any time you are making a cross-site request that needs cookies, then those cookies need to be marked SameSite=None; Secure.
So, for example if the user is on a.com and you have an <iframe> or fetch() to apps.b.com that expects cookies, then the apps.b.com cookies need SameSite=None; Secure.
Vice versa, if the user is on apps.b.com and you are making requests to a.com to check their auth status by relying on the a.com cookies, then those cookies need SameSite=None; Secure.
Essentially the pattern you're looking for is when the site in the browser location bar is different to the site that needs the cookies, then those are the cookies that need marking. So, depending on your set up, it may be one or both.

How to align client and IdentityServer cookies

I'm moving an ASP.NET web application away from Forms authentication to OIDC authentication through IdentityServer, with implicit flow for getting an ID token. Forms authentication has options in the client web.config such as 'timeout' and 'slidingExpiration' and I'm looking for a way to make sure the client is just as configurable when using IdentityServer.
I understand there are two separate cookie management systems in this scenario - the client's and IdentityServer's. I would like to align them as much as possible and have a single place for configuring these options. This could be either at either end, one handing responsibility to the other.
One option I've explored is setting UseTokenLifetime = true on both ends and then using the IdentityServer Client property IdentityTokenLifetime as a way to configure timeout for the client. Both cookies should then expire at the same time specified by the IdentityTokenLifetime. When the client's cookie times out it'll redirect to IdentityServer for authentication, where the login prompt will be shown because its own cookie will have expired too. However, I don't think this allows a sliding expiration option?
Another option might be to set UseTokenLifetime back to false, configure cookie options in the client cookie middleware, and ensure the client sends prompt=login when authenticating. This means even if IdentityServer has cookie settings which don't match the client (e.g. the IdentityServer cookie is still valid after client's has expired), it'll still always show the login prompt. The downside to this seems to be that it would inhibit SSO should I add more clients, because they'll always have to login for each client.
I would appreciate any thoughts on this
Thanks