website logo

Last Updated:

Gotchas With Same Site Strict Cookie and OAuth

feature.webp

Often, servers want to save some client specific information in the browser. This helps the server to serve more personalized experiences.

Have you ever noticed the items you add in your shopping cart stays the same after you reopen your browser? Or YouTube remembers how much you have watched a particular video?

These type of customization can only be possible, if the server save some information about the user in the browser. The browser send this information with every request to the server.

A cookie is a small block of information stored in the browser.

A server can generate a cookie to store some client specific information in the browser. The server sends the cookie with an HTTP response with a Set-Cookie header.

Once a cookie is set, The browser sends the cookie with each request to the server.

There are many types of cookie present. Let’s get a brief overview about some important ones.

When you create a new tab in the browser, a new session starts. The session ends when you close the tab.

A session cookie persists only during the session duration. This type of cookie doesn’t have any expiration date. After each session, browser delete these cookies.

As the name suggests, persistent cookies are persistent in nature. The browser doesn’t delete the persistent cookie after each session.

Persistent cookie comes with an expiration date or max-age attribute. When the time pass, browser automatically delete these cookies.

This is an example of Set-Cookie header in an HTTP response.

Set-Cookie: key=value; Expires=Thu, 2 May 2024 07:28:00 GMT; Secure; HttpOnly; SameSite=Strict

Focus on the Expires and SameSite word. These are called cookie attributes.

In this blog, we are discussing the SameSite attribute in a cookie.

Same site attribute in a cookie restrict browser to send the cookie in cross-site requests. The SameSite attribute accepts one of the 3 values, Strict, lax and none. Let’s understand them briefly.

Same site strict

Cookie with SameSite=strict attribute, restrict browser to send with every cross site requests. Even if a user follows a URL from an other website, the same site strict cookie is not sent by the browser.

Same site lax

Cookie with SameSite=Lax attribute take a balance approach. When a cookie is set to SameSite=Lax, the browser sends the cookie if someone follow a URL from other website. But the cookie is not sent in other 3rd party requests like fetching an image or scripts from other websites.

This is the default value for SameSite attribute.

Same site None

Cookie with SameSite=None attribute doesn’t give any security. This cookie is sent with every requests by the browser.

Understand the OAuth flow

Let’s take an example to understand the situation. You have 3 HTTP endpoint defined in your server.

  1. /auth/login: User send a GET request to this endpoint. Server generate an OAuth URL and redirect to the OAuth provider website to complete the authentication.
  2. /auth/callback: After user completes the authentication, OAuth provider redirect the user to this endpoint with the authentication code in the query parameter. Server exchange this code for an access token and refresh token.
  3. /user/dashboard: Personalized dashboard for each user. This endpoint is only accessible if the user is authenticated with the OAuth provider.

To identify if a user is authenticated or not, server send a Cookie to the browser after getting the access token in auth/callback endpoint. Then server redirect the successfully authenticated user to the /user/dashboard page.

When a user visits the /user/dashboard page, the server reads the cookie associated with the request. If the cookie is present, only then the server gives access to the /user/dashboard page to the visitor.

Gotchas with strict same site cookies.

This authentication flow works well when you set the SameSite attribute of your cookie to Lax or None. In this case, browser send the authentication cookie to the /user/dashboard page when redirected from the /auth/callback page.

Gotchas start appearing when you set the SameSite attribute to Strict. Earlier in this blog, you have read that cookie with SameSite=Strict is only sent by the browser in first party context.

But remember that once the user completes the authentication process in OAuth provider’s website, they are redirected to the /auth/callback then finally /user/dashboard page. The OAuth provider website is in 3rd party context and server endpoints are 1st party context.

GET /user/login -(redirect)-> Oauth provider website

GET OAuth provider -(redirect)-> /auth/callback -(redirect)-> /auth/dashboard

As you can see above that, the second GET request originate from the 3rd party context. Therefore, the browser doesn’t send the authentication cookie with SameSite=Strict attribute. Although that cookie is set by the /auth/callback response.

As a result, instead of the user is authenticated and the authentication cookie is set, the browser doesn’t send the cookie with the redirect request to /user/dashboard page and the user get a 401 Unauthorized response.

To solve this problem, we should break the 2nd redirect chain and add an intermediate page.

GET /user/login -(redirect)-> Oauth provider website

GET OAuth provider -(redirect)-> /auth/callback -(redirect)-> /intermediate

GET /intermediate -(JS redirect)-> /user/dashboard

Instead of directly redirecting the user to the /user/dashboard page in the 2nd request, load the /intermediate page as a redirect from /auth/callback.

Now add a Javascript snippet in the /intermediate page to make a client side redirect to the /user/dashboard page. As this 3rd request originates from a first party context, browser send the authentication cookie with the request and the user can successfully access the /user/dashboard page.

setTimeout(() => {
  window.location.href = "/user/dashboard";
}, 3000);

This script redirect the site to /user/dashboard in 3 seconds.

Other solution

On the contrary, you can set the SameSite=Lax attribute to the authentication cookie. This change make browser to send the authentication cookie in redirect requests originates from 3rd party contexts.

This solution doesn’t need you to create a separate /intermediate page, but is less secure than SameSite=Strict cookie.

We have previously discussed the nature of SameSite=Lax attribute. Browser send this cookie when a user visits the website but blocks the cookie in other 3rd party request.

Conclusion

Same site attribute is one of the security measure you can use to secure your website. In addition to this, there are other important cookie attributes like HTTPOnly and Secure which further improve the security of your website. Learn to use these attributes and make a balance between security and usability for your application.

See Also