Best Practices - OAuth and Same Site Cookies
On this page
When using OAuth and OpenID Connect in a browser based application, the two main options are to develop a website or a single page application (SPA). Either of these can use HTTP-only cookies to convey user identities in HTTPS requests, to secure calls from the frontend to the backend.
Browser based apps send
first-party cookies to their own backends, which are in the
same site as the web origin. During more advanced navigation, web apps can contact external sites, and send
third-party cookies. One such use case is during OAuth flows, when the browser interacts with the authorization server.
Recent same-site cookie restrictions can lead to application problems in some OAuth flows. This article therefore explains how to avoid them, to ensure good security, reliability and usability. Some best practices are also provided, on both web cookie security and other cross-domain navigation use cases.
Current cookie behaviors are explained in the latest updates to the HTTP state management specification, also known as RFC6265. Servers now issue a
SameSite attribute when issuing cookies, to indicate its desired behavior. The newer cookie properties are also understood by all modern browsers (or user agents).
|SameSite Value||Intended Behavior|
|strict||User agents should send the cookie only for same-site requests|
|lax||User agents should send the cookie for same-site requests and cross-site top level navigations|
|none||User agents should send the cookie for both same-site and cross-site requests|
User Agent Restrictions
Modern user agents implement the client-side behavior from the specification, but often go beyond it, adding further restrictions. This protects users against unwelcome tracking by external sites. For example, the Safari browser prevents cross-site tracking by default, even for
The RFC6265 specification explains rules for classifying requests from user agents as same-site or cross-site. This includes actions to inspect the web origin, the target domain, and ancestor documents for nested browsing contexts. The end result is that cookies issued by external domains are considered third-party.
Exact behaviors may vary a little between the main browsers. The main use cases affected are iframes that load content from external domains, or Ajax requests sent from the browser to APIs in external domains.
When authenticating a user, your browser based app will run a code flow. The initial request sent in an HTTP redirect will contain parameters similar to these:
GET http://login.example.com/oauth/v2/oauth-authorize?client_id=web-client&redirect_uri=http://www.product.com/&response_type=code&scope=openid profile&code_challenge=WhmRaP18B9z2zkYcIlb4uVcZzjLqcZsaBQJf5akUxsA&code_challenge_method=S256&state=CfDJ8Nxa-YhPzjpBilDQz2C...&nonce=638088910888703720.YzY3...
The authorization server validates the initial request, then issues a temporary HTTP-only cookie to the browser, including the
SameSite=none property. This cookie must be re-sent by the browser for all subsequent requests in the authentication workflow, so that these requests are secured correctly.
The authorization server then presents multiple screens. Some of these are HTTP POST requests, such as those to submit a user's password. Finally, once the code flow completes, a single sign-on (SSO) session may be created. This is represented by another cookie, which also uses
OAuth cookies are usually third-party
Cookies issued by the authorization server will be considered third-party cookies by your web applications, unless the authorization server shares the same parent domain as the web origin.
In your own applications,
SameSite=none is not the most secure cookie option. It is the standard behavior for authorization servers, which also implement many other techniques for protecting requests.
Browser Window Types
Browser based apps can send code flow requests using any window that supports redirects. Usually the main window is used, but it is also possible to send the request from a popup window or an iframe. These windows have different privacy characteristics, which affects how the user agent sends cookies.
Main windows and popup windows show the user a navigation bar, to indicate the origin the user has been redirected to. For iframes however, the user is not informed which origin is being used, and the window can even be completely hidden. This increases the scope for iframes to be used for malicious purposes.
The trend in modern browsers such as Safari is therefore to only send OAuth
SameSite=none cookies for top level redirects, and to drop them for requests sent from iframes, or when issuing Ajax requests.
OAuth cookies may be dropped when sent from cross-domain iframes
If you send OAuth requests from iframes in a browser based app, the user agent may refuse to send OAuth cookies, unless the authorization server shares the same parent domain as the web origin.
Cookie Best Practices
Before discussing OAuth flows that are restricted by same-site cookies, this section summarizes how the backend of a browser based application should issue cookies for its frontend. The cookie issuing can be done by building a website. Alternatively, a backend for frontend (BFF) can perform this task on behalf of a single page application. HTTP-only cookies issued are then shared across all browser tabs.
Issue First-Party Cookies
Always issue cookies from a backend domain hosted on the same parent domain as the browser based app's origin. Avoid issuing cookies from an unrelated API domain, e.g.
https://api.company.com, to the web origin of the browser based app, e.g.
https://www.product.com. This will issue cookies that are considered third party, and user agents are likely to drop them during API requests.
Follow a Secure Web Development Lifecycle
Web development teams must ensure good browser security. A common option is to follow recommendations published by the Open Web Application Security Project (OWASP). Two of the main threats are cross site request forgery (CSRF) and cross site scripting (XSS). When issuing cookies to browser based apps, the
SameSite=strict cookie property provides the strongest built-in CSRF protection.
Consider API Driven Cookie Issuing
The OWASP recommendations includes defense in depth measures to protect against CSRF, in addition to using same-site cookies. When developing single page applications, a convenient place to manage these concerns is in an API gateway, in order to keep the security plumbing out of your application code. The token handler overview describes this approach, with the following end-to-end flow:
It is possible to issue cookies from an API domain, e.g.
https://api.product.com, in the same parent site as the web origin, e.g.
https://www.product.com. The cookies issued then remain same-site and are not impacted by recent browser restrictions. Doing so provides additional options when designing your web deployments, since cookies are only used in API requests. It is therefore possible to design API routes independently to your web domains.
Secure cookies returned to the browser must be HTTP-only, so that they cannot be directly accessed by scripts. They must also use the
Secure cookie property, and only be accepted by servers in HTTPS connections.
Avoid storing secure values in the browser, such as in local storage. Instead, use server-side capabilities to protect the confidentiality and integrity of cookies issued. This can include the use of a strong symmetric encryption algorithm, such as AES256-GCM, with a key known only to security components in the backend.
Also, ensure that cookies are time limited and no longer accepted after a defined period of time. This is automatically ensured when all expiry is based on underlying OAuth tokens. It is recommended to also use non-persistent cookies, so that cookies are removed when the user agent is closed.
Limit Cookie Sending
Cookies containing identity information ultimately act as credentials for accessing your data, so send them to as few endpoints as possible, and take care in server code, when setting domains and paths. Avoid setting cookies on entire top level domains such as
In the token handler pattern, cookies used to access data are only sent to the API endpoints that need them, and the cookie used for token refresh is only sent to a particular endpoint of the OAuth Agent.
set-cookie:example-rt: <AES-256-GCM encrypted data>Domain: api.example.comPath: /refreshSecureHttp OnlySameSite=strict
Avoid implementing your own single sign-on solution that sets cookies for a top level domain such as
example.com. Doing so sends SSO cookies to many endpoints that are not entitled to receive them. Always use an authorization server instead, which will set SSO cookies for a separate dedicated domain.
Limit Cookie Sizes
Cookies are needed to convey identity, but should not be used as a general mechanism for conveying data, due to size limitations. Current browsers have a limit of 4KB per cookie, and some servers, such as NGINX, have an overall 4KB default limit for the cookie header size. Therefore, use small opaque tokens when storing tokens in cookies. The RFC6265 document provides further information on cookie limits, though some user agents may go beyond this and restrict cookie sizes further.
Restricted OAuth Flows
A number of OAuth flows for web applications use iframes that load content from the authorization server domain, or redirect to it, or send Ajax requests. Some user agents, such as Safari, will refuse to send authorization server cookies in these scenarios, preventing these flows from working. Some affected OAuth flows are summarized in the following sections, along with alternative approaches.
Flows that require first-party OAuth cookies
The flows in this section will not work in all browsers with default settings, unless the authorization server is hosted on the same parent domain as the web application's origin.
Checking Login Status
When loading a browser based app, it is possible to spin up a hidden iframe and send a code flow request that includes the OpenID Connect prompt=none parameter. This sends the SSO cookie, and if the user is not already authenticated, a response with an
error=login_required parameter is received.
When the user agent refuses to send the SSO cookie, this flow no longer works. In most web scenarios, it remains easy to determine if the user is signed in though, by simply making an HTTP request to the app's backend, to check whether a valid HTTP-only cookie is present.
Silent Token Refresh
Single page applications that use access tokens in the browser can silently refresh tokens by running a complete code flow on a hidden iframe, using
prompt=none. This flow can be triggered when an access token expires, or as a background operation, that refreshes the access token before the time in its
Assisted Token Flow
Due to recent browser restrictions however, this flow may fail, if the user agent refuses to send temporary cookies required to secure the authentication workflow. The assisted token flow may still be useful as a simple solution for internal applications, especially if you can control which browsers are used.
Single Logout Flows
Logout flows may fail if they rely on third-party cookies sent from iframes. Instead, a simpler and more reliable option is to implement RP-initiated logout, using a top level redirect. Multi-tab logout within a web domain can be achieved by setting a
loggedOut property in the user agent's local storage, then listening for storage event changes on other browser windows. See the SPA using token handler for an example.
Web Cookies and Navigation
Once your web cookie security is implemented securely, and you are using reliable OAuth flows, you may also need to design solutions for multi-application scenarios. This section provides recommendations for securely managing various types of navigation.
Navigation Across Multiple Apps
It is possible to share cookies across multiple web applications. Doing so avoids OpenID Connect redirects when users navigate across applications, which can provide a seamless user experience. In many cases though, this is not a good security design.
For OAuth secured browser based apps, cookies map to OAuth tokens representing privileges. When navigating across business areas, ensure that users of each application run with least privilege. In the following example, a marketing user's cookie maps to a token that includes a
A more secure design is to implement navigation across business areas using single sign-on. Cookies sent to APIs will then map to tokens designed with least privilege, while also providing a good user experience. Use separate backends to achieve this, and ensure that each app sends cookies to APIs via a different domain or path:
Cookie sharing is a better choice in micro-UI architectures. A browser based app for a single business area could be split across teams, to keep code sizes manageable. Multiple micro-UIs could then be deployed, to run at paths such as
/marketing2. This is easy to enable when API driven cookie issuing is used, since the cookie issuing technology is external to each application, and conflicts are thus avoided.
Widgets and Mashups
It is possible to use
div HTML elements as widgets that consume external content, as part of a web mashup solution. With recent browser restrictions this will no longer work reliably in all browsers. If a third-party cookie is used, the user agent may not send it. Some alternative designs, such as using access tokens directly in the browser, result in suboptimal security.
The preferred option is to instead design such solutions to use a first-party
div HTML element, that sends first-party requests to your own backend, so that only same-site cookies are used. Consider using a reverse proxy in your own backend, to route such requests to the third party domain. The reverse proxy can also attach a secure B2B credential, such as an access token or client certificate.
Mobile Web Navigation
It is common for organizations to want users to navigate seamlessly from their mobile app to a browser based app. In some cases, single sign-on may not work due to web and mobile SSO cookies being stored in different cookie jars, leading to a double login. Other interoperability solutions are not obvious, when mobile apps use tokens, while web applications use secure cookies.
In all cases though, browser based apps should continue to use the security recommendations from this article, and use the most secure cookies in mobile browsers. For further techniques on mobile web interoperability, see the nonce authenticator pattern article, and the Mobile Web SSO code example.
Browsers and servers must protect against many security threats when using cookies, and you must implement up to date cookie best practices in your applications. Recent cookie restrictions also need to be managed, which help to protect privacy, but may also prevent some web design patterns from working. To overcome these barriers, use the following main techniques, to ensure predictable results:
- Use only the latest and most secure cookies in your browser based apps
- Issue server-side cookies using tested web cookie solutions, provided by security experts
- Use a top level window for OAuth redirects, to ensure that third-party cookies are handled reliably
- For other secure communication from the browser to third-party domains, route requests via your backend