How to make use of cookies while still using oauth?

Viewed 1146

Currently we have a SPA and API and SPA sends email/password to API and API returns response with two secure / HttpOnly / Lax cookies. First cookie is access token with short TTL (custom JWT is stored inside cookie) and second one is a refresh token with long TTL. SPA makes requests to API with those cookies, and API verifies if access token is expired and refreshes it when needed by reading refresh token from cookie and setting new access token cookie.

Because we will have more API clients soon (mobile app and machine-to-machine clients) we wanted to make use of OAUTH to standarize authorization. After making some research it seems that OAUTH is good for everything except SPAs because storing refresh tokens in browser is not secure and should be avoided. For mobile it seems to be secure-enough because refresh token can be stored in OS keychain or something like that.

So it would be reasonable to still use secure cookies for SPA and access tokens for mobile and machine-to-machine. To make it consistent we would like to just have regular oauth access / refresh tokens stored inside cookies and on API side treated in a same way that bearer tokens passed in authorization header. Our SPA and API are in same domain (different subdomains) and this is more about one API and many clients case.

We are considering following options for SPA:

  1. Just use Resource Owner Password Flow - while it's not recommended, it can be used from highly trusted "client" - in our case that would be SPA sending credentials to API and API calling oauth server (with client id, secret and user credentials) to get access token and refresh token and then return those tokens in secure cookies back to SPA.

  2. I am not sure if this is possible but I was thinking of splitting Authorization Code Flow between SPA and API. SPA redirects to oauth authorization page, user logins on hosted login page and is redirected back to SPA with authorization code. Then SPA instead of calling /oauth/token on oauth server it sends authorization code to API and API makes final call to /oauth/token on oauth server to get access token and refresh token and store it in cookies. Does it reduce security in any way?

Are there any other options?`

2 Answers

1. Using resource owner password credentials (ropc)

Avoid ROPC grant. This grant was intended for legacy solutions and security best practice RFCs for OAuth discourage the usage (ex:- rfc6819 :section-4.4.3, draft-ietf-oauth-security-topics-19 :section-2.4 ) . Further, this will get deprecated with OAuth 2.1

2. Split solution - SPA with Backend

You already have cookies and I assume they get initiated with some validations (ex:- valid access token to establish a cookie) from a backend. Hence, if your application architecture supports or can be modified to support backend based token obtaining (instead of front end only authorization code flow), go for that solution.

Advantage - You do not store any token in the browser and tokens can be stored in a secure backend. Cookie expiry can be mapped to token lifetime.

3. Pure SPA : Session storage or local storage

If you cannot have the backend for SPA and if you do not want to preserve long lived refresh token (ex:- remember me sort of feature), you can use session storage or local storage (depending on the UX & security requirement).

Things to consider here is proper management of tokens stored in browser storage (ex:- clear local storage when SPA exit) & refresh of access token when API returns the 401. Further, use short lived refresh tokens.

I would go for both of your option 2s, though there are some subtleties in getting an SPA and API solution working. These should be the end results:

  • In the browser you use HTTP Only SameSite=strict cookies
  • You can develop in technologies such as React
  • Web and mobile clients can call the same API routes
  • SPA can be deployed to a CDN if you prefer

At Curity we have sone detailed resources on this approach, which we call the Token Handler Pattern. It is basically just website security via an API. I provided an architectural overview a while back in this blog post.

It is a tricky flow in deployment terms though, so maybe have a look at the React SPA Example. Note also that this will work with any OAuth provider and is a design pattern, not a vendor solution.

Related