I watched a guide where an author stored access token in localStorage and then he put the access token as Authorization header with value "Bearer accessToken" in every request through axios interceptor. But I am wondering why not to store access token in httpOnly cookie as we do it with refresh token. What would be the problem if any?
It's safer to store access tokens in HTTP-only, secure, same-site cookies (it doesn't matter if it's a JWT access token). It's safer because the value of the access token can't be stolen through a cross-site scripting (XSS) attack. However, when you keep the access token in a cookie, you won't be able to send it to an API in an Authorization header. The browser doesn't have a way of setting the authorization header, it only attaches the cookies. That means that you might need a piece of software that will sit between your front end and API, and extract the access token from the cookie (this can be done e.g., by an API gateway).
Remember also that storing access tokens in cookies leaves you open to cross-site request forgery attacks (CSRF), but there are well-established techniques to protect yourself from CSRF. It is also simpler to protect against CSRF than against XSS.
Related
I've always been under the impression that storing both of these tokens in an httpOnly cookie is secure enough, but been lately reading some people only store the refresh token in the cookie, and since the accessToken is short lived, they store it somewhere in app memory (context, redux, whatever). Since the entire goal of the refresh token is to fetch a new access token, the access token doesn't have to be stored in a cookie, but has it's disadvantages if you don't?
I think the issue for me is that with SSR, you can't access the access token on the server (NextJS for example), so you can't do prefetch/other operations on the server when you need to access token values right?
I assume that even context is an attack vector, so storing both of those tokens within the cookies is the safest?
It seems its more of a debate than being frowned upon in terms of storing both tokens in a cookie at the same time.
Storing both tokens in HTTP-only cookies is the safest way and is currently recommended as a security best practice for SPAs. However, this has some limitations and sometimes it's more convenient to store the access token in memory. When you have the access token in a cookie then you need your own backend that will handle those cookies. E.g., if you're calling APIs that require access tokens in the Authorization header, and you're not in control of those APIs, then you somehow have to translate the cookie to the header. Some people find it easier to just keep the access token in memory and call the APIs directly, without any intermediary backend components. Not all systems require the toughest security standards. Sometimes it's about finding the balance between robust security and good developer or user experience.
A lot of questions have already been asked on the topic of storing JWT tokens securely when dealing with a browser-based application. The consensus seems to be that http-only, secure cookies should be used. However, many variations seem to exist on storing JWT tokens when both short-lived access tokens and longer-lived refresh tokens are involved.
I have identified the following variations:
1. Store both JWT access token and refresh token in http-only, secure cookies
Pros:
Access token and refresh token cannot be accessed from Javascript
Cons:
Introduces CSRF vulnerabilities so CSRF token must be added as well
The top answer here advises to add CSRF tokens: https://stackoverflow.com/a/37396572/6735966
2. Store a JWT access token in memory and refresh token in http-only, secure cookie
Pros:
Refresh token cannot be accessed from Javascript
Access token sent through Javascript so access token is not vulnerable to CSRF
Refresh cookie can only be used to obtain new access token. With the correct CORS setup, reading the access token from the response is not possible through a cross-site request by a malicious party. Therefore, this approach seems safe from CSRF.
Cons:
Access token can be accessed through Javascript (but access token expires quickly)
Recommended here but received a lot less votes than the top post: https://stackoverflow.com/a/63593954/6735966
3. Store a refresh token in memory and JWT access token in http-only, secure cookie
Pros:
Access token cannot be accessed from Javascript
Refresh token sent through Javascript so refresh token is not vulnerable to CSRF
Cons:
Longer-lived refresh token can be accessed from Javascript
Access token is vulnerable to CSRF
A similar approach is described in the top answer here: https://stackoverflow.com/a/54378384/6735966
Considering the pros and cons storing a JWT access token in memory and refresh token in http-only, secure cookie definitely seems like a good idea to me. However, even though there are many questions on this topic, none of the top voted answers even consider this approach. Therefore my question is: Why not store JWT access token in memory and refresh token in cookie and instead use one of the other approaches?
Storing the cookie in memory would work, but one issue is if you have multiple instances of the same client.
An alternative is to do it like they do in ASP.NET core, where by default the cookies are stored encrypted in the session cookie. However, this cookie can't be used to access any API's, as it is inaccessible from JavaScript. Also, to avoid the CSRF issues, you typically add the common antiforgery token/cookie to prevent CSRF attacks.
So, the most way is to store the tokens in ASP.NET Core is in the session cookie. But at the sametime, this make the cookie to grow quite a bit, so when you feel the cookie size grows to big, then you start looking at storing them in memory or in database/Redis storage.
In .NET for example, the support for this is already built in by using a SessionStore. The picture below tries to show how this works where the SessionKey is stored in the cookie and then tokens are stored in memory/backend.
Yes, this is how it works in ASP.NET Core and I am sure you can find the similar approaches in other platforms as well.
An alternative is to look at using the BFF pattern that seems to get more and more popular.
We have some options such as localStorage, cookies, in-browser memory to store our JWT, I am also aware that localStorage is vulnerable to XSS, and httpOnly cookies are vulnerable to CSRF and it will be lost on reload/refresh when JWT is placed in the browser.
I studied about the latter issue and come to the solution that putting Refresh Token in httpOnly cookie and access token in browser memory can save me to some degree.
But according to my use case, I have an Admin dashboard from which only authenticated person(basically admin) can make authorised API call. Also, in my WebApp we don't have user input field(text field), So I guess XSS and CSRF hard to attack. So, Can I put JWT Token in httpOnly cookie with expiry of long duration?
Is this a good solution for my use case?
I'd like to secure my SPA private routes with JWT authentication. To make everything as much secure as it's possible, I wanted to use httpOnly cookie to store my access_token on the client-side.
Using httpOnly cookies protect me a lot from XSS attacks, but unfortunately this approach does not allow me to check if the cookie actually exists in the browser.
In this case - how can I implement some logic to prevent unlogged users to visit private, secure routes of my SPA?
Am I forced to use non-httpOnly cookies or localStorage for this?
Am I forced to use non-httpOnly cookies or localStorage for this?
No. Keep your access_token in a cookie with the httpOnly flag, and (if possible) with the secure flag.
Let's call this cookie session_cookie.
When a user does a successful login you could return 2 cookies: the session_cookie and another one which informs to JS the user has been authenticated (let's call as SPA cookie).
Your session_cookie is not accessible by JS so it's not vulnerable to XSS. This cookie is sent on each request to the server, which checks is a valid token, otherwise an unauthorized error is returned.
Your SPA cookie hasn't httpOnly flag so it's accessible by JS but the server doesn't use it to authenticate the user, so fake this cookie is useless.
Whenever you receive an unauthorized error on your SPA you can remove the SPA cookie.
On the surface, it seems like "token auth" is basically the same thing as traditional "cookie auth".
Token auth:
User submits username/password to API
API responds with access token
Client stores access token for identifying user in future requests
Cookie auth:
User submits username/password to API
API responds with cookie
Client stores cookie for identifying user in future requests
It seems that token auth is basically the same as cookie auth, except that most HTTP clients already know how to deal with managing cookies automatically, whereas you have to manually manage API tokens.
What am I missing? What are the benefits of using token auth? Is it really worth the extra effort?
Whether the extra effort is worth it, depends on what you are protecting and who is consuming the API.
Token based authentication is much easier when your clients are non-browser based. So if you're targetting mobile applications, token based authentication is worth considering.
But also in a browser scenario it has some advantages. As the browser does not automatically send the Authorization header, security token are not vulnerable to CSRF attacks.
If your web application lives on another domain than you API, cookies will not be sent because of the same-origin policy. Security tokens are not affected by this.