Is storing JWT access token in app memory or both in httpOnly cookies? - authentication

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.

Related

What are the benefits of implementing OAuth (JWT access tokens with refresh tokens)

Current Setup
I'm currently building an application, and have just finished implementing an OAuth authentication server. This is my first "real" attempt at a project that has a legitimate user authentication and management component, so much of this is new to me.
I've implemented the OAuth specification. This means the following:
The authentication is deployed on a separate webserver with a separate DB than the application server.
The auth server logs in a user, and issues them two tokens. One is a JWT access token that contains information about their user identity. This has a short-lived 15 minutes expiry. The second token is a refresh-token. This is a single-use token with a 7 day expiry. It is used to fetch another access token with the application server returns a 401 (the access token has expired).
The application server shares a secret key with the auth server, and has middleware that verifies the JWT access token.
Concerns
My concern is that I've over-engineered a project that didn't need this much complexity. Since the auth/app are distinct, this means that my client code needs to be aware of, and handle refresh token rotation. It needs to interpret 401s, and fetch another access token.
As far as I can tell from my reading, this wouldn't be necessary with simple session cookies that persist. The cookie is just included in requests to my domain. If I killed this approach, and just had my server do a DB lookup on a signed session cookie - I would avoid a lot of this client complexity.
One consideration is that I’m using a React SPA frontend client. This is also new territory for me, so I’m not sure whether or not this changes the situation.
As I said above, I'm new to a lot of this so could use some advice from people who have worked in this space for longer and have the experience. Is OAuth worth the hassle?
Options
OAuth with access tokens (JWTs) and refresh tokens:
Pros: Provides a secure and scalable way to handle user sessions.
Cons: Client needs to be aware of refresh token rotation procedure and handle 401 responses by using the refresh token to request a new access token, which can add complexity to the client-side code. Also adds complexity (and cost) to the AWS infra stuff. I need to know how to get the auth server and app server on the same base URI. Also makes my local dev environment a little more involved.
Server-side sessions using signed cookies:
Pros: Simpler for the client, as it does not need to handle refresh tokens or 401 responses.
Cons: Server needs to manage session state, which can be more resource-intensive. This means a DB call on every request.

Why not store JWT access token in memory and refresh token in cookie?

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.

Vue protecting paths from edited localstorage [duplicate]

When building SPA style applications using frameworks like Angular, Ember, React, etc. what do people believe to be some best practices for authentication and session management? I can think of a couple of ways of considering approaching the problem.
Treat it no differently than authentication with a regular web application assuming the API and and UI have the same origin domain.
This would likely involve having a session cookie, server side session storage and probably some session API endpoint that the authenticated web UI can hit to get current user information to help with personalization or possibly even determining roles/abilities on the client side. The server would still enforce rules protecting access to data of course, the UI would just use this information to customize the experience.
Treat it like any third-party client using a public API and authenticate with some sort of token system similar to OAuth. This token mechanism would used by the client UI to authenticate each and every request made to the server API.
I'm not really much of an expert here but #1 seems to be completely sufficient for the vast majority of cases, but I'd really like to hear some more experienced opinions.
This question has been addressed, in a slightly different form, at length, here:
RESTful Authentication
But this addresses it from the server-side. Let's look at this from the client-side. Before we do that, though, there's an important prelude:
Javascript Crypto is Hopeless
Matasano's article on this is famous, but the lessons contained therein are pretty important:
https://www.nccgroup.trust/us/about-us/newsroom-and-events/blog/2011/august/javascript-cryptography-considered-harmful/
To summarize:
A man-in-the-middle attack can trivially replace your crypto code with <script> function hash_algorithm(password){ lol_nope_send_it_to_me_instead(password); }</script>
A man-in-the-middle attack is trivial against a page that serves any resource over a non-SSL connection.
Once you have SSL, you're using real crypto anyways.
And to add a corollary of my own:
A successful XSS attack can result in an attacker executing code on your client's browser, even if you're using SSL - so even if you've got every hatch battened down, your browser crypto can still fail if your attacker finds a way to execute any javascript code on someone else's browser.
This renders a lot of RESTful authentication schemes impossible or silly if you're intending to use a JavaScript client. Let's look!
HTTP Basic Auth
First and foremost, HTTP Basic Auth. The simplest of schemes: simply pass a name and password with every request.
This, of course, absolutely requires SSL, because you're passing a Base64 (reversibly) encoded name and password with every request. Anybody listening on the line could extract username and password trivially. Most of the "Basic Auth is insecure" arguments come from a place of "Basic Auth over HTTP" which is an awful idea.
The browser provides baked-in HTTP Basic Auth support, but it is ugly as sin and you probably shouldn't use it for your app. The alternative, though, is to stash username and password in JavaScript.
This is the most RESTful solution. The server requires no knowledge of state whatsoever and authenticates every individual interaction with the user. Some REST enthusiasts (mostly strawmen) insist that maintaining any sort of state is heresy and will froth at the mouth if you think of any other authentication method. There are theoretical benefits to this sort of standards-compliance - it's supported by Apache out of the box - you could store your objects as files in folders protected by .htaccess files if your heart desired!
The problem? You are caching on the client-side a username and password. This gives evil.ru a better crack at it - even the most basic of XSS vulnerabilities could result in the client beaming his username and password to an evil server. You could try to alleviate this risk by hashing and salting the password, but remember: JavaScript Crypto is Hopeless. You could alleviate this risk by leaving it up to the Browser's Basic Auth support, but.. ugly as sin, as mentioned earlier.
HTTP Digest Auth
Is Digest authentication possible with jQuery?
A more "secure" auth, this is a request/response hash challenge. Except JavaScript Crypto is Hopeless, so it only works over SSL and you still have to cache the username and password on the client side, making it more complicated than HTTP Basic Auth but no more secure.
Query Authentication with Additional Signature Parameters.
Another more "secure" auth, where you encrypt your parameters with nonce and timing data (to protect against repeat and timing attacks) and send the. One of the best examples of this is the OAuth 1.0 protocol, which is, as far as I know, a pretty stonking way to implement authentication on a REST server.
https://www.rfc-editor.org/rfc/rfc5849
Oh, but there aren't any OAuth 1.0 clients for JavaScript. Why?
JavaScript Crypto is Hopeless, remember. JavaScript can't participate in OAuth 1.0 without SSL, and you still have to store the client's username and password locally - which puts this in the same category as Digest Auth - it's more complicated than HTTP Basic Auth but it's no more secure.
Token
The user sends a username and password, and in exchange gets a token that can be used to authenticate requests.
This is marginally more secure than HTTP Basic Auth, because as soon as the username/password transaction is complete you can discard the sensitive data. It's also less RESTful, as tokens constitute "state" and make the server implementation more complicated.
SSL Still
The rub though, is that you still have to send that initial username and password to get a token. Sensitive information still touches your compromisable JavaScript.
To protect your user's credentials, you still need to keep attackers out of your JavaScript, and you still need to send a username and password over the wire. SSL Required.
Token Expiry
It's common to enforce token policies like "hey, when this token has been around too long, discard it and make the user authenticate again." or "I'm pretty sure that the only IP address allowed to use this token is XXX.XXX.XXX.XXX". Many of these policies are pretty good ideas.
Firesheeping
However, using a token Without SSL is still vulnerable to an attack called 'sidejacking': http://codebutler.github.io/firesheep/
The attacker doesn't get your user's credentials, but they can still pretend to be your user, which can be pretty bad.
tl;dr: Sending unencrypted tokens over the wire means that attackers can easily nab those tokens and pretend to be your user. FireSheep is a program that makes this very easy.
A Separate, More Secure Zone
The larger the application that you're running, the harder it is to absolutely ensure that they won't be able to inject some code that changes how you process sensitive data. Do you absolutely trust your CDN? Your advertisers? Your own code base?
Common for credit card details and less common for username and password - some implementers keep 'sensitive data entry' on a separate page from the rest of their application, a page that can be tightly controlled and locked down as best as possible, preferably one that is difficult to phish users with.
Cookie (just means Token)
It is possible (and common) to put the authentication token in a cookie. This doesn't change any of the properties of auth with the token, it's more of a convenience thing. All of the previous arguments still apply.
Session (still just means Token)
Session Auth is just Token authentication, but with a few differences that make it seem like a slightly different thing:
Users start with an unauthenticated token.
The backend maintains a 'state' object that is tied to a user's token.
The token is provided in a cookie.
The application environment abstracts the details away from you.
Aside from that, though, it's no different from Token Auth, really.
This wanders even further from a RESTful implementation - with state objects you're going further and further down the path of plain ol' RPC on a stateful server.
OAuth 2.0
OAuth 2.0 looks at the problem of "How does Software A give Software B access to User X's data without Software B having access to User X's login credentials."
The implementation is very much just a standard way for a user to get a token, and then for a third party service to go "yep, this user and this token match, and you can get some of their data from us now."
Fundamentally, though, OAuth 2.0 is just a token protocol. It exhibits the same properties as other token protocols - you still need SSL to protect those tokens - it just changes up how those tokens are generated.
There are two ways that OAuth 2.0 can help you:
Providing Authentication/Information to Others
Getting Authentication/Information from Others
But when it comes down to it, you're just... using tokens.
Back to your question
So, the question that you're asking is "should I store my token in a cookie and have my environment's automatic session management take care of the details, or should I store my token in Javascript and handle those details myself?"
And the answer is: do whatever makes you happy.
The thing about automatic session management, though, is that there's a lot of magic happening behind the scenes for you. Often it's nicer to be in control of those details yourself.
I am 21 so SSL is yes
The other answer is: Use https for everything or brigands will steal your users' passwords and tokens.
You can increase security in authentication process by using JWT (JSON Web Tokens) and SSL/HTTPS.
The Basic Auth / Session ID can be stolen via:
MITM attack (Man-In-The-Middle) - without SSL/HTTPS
An intruder gaining access to a user's computer
XSS
By using JWT you're encrypting the user's authentication details and storing in the client, and sending it along with every request to the API, where the server/API validates the token. It can't be decrypted/read without the private key (which the server/API stores secretly) Read update.
The new (more secure) flow would be:
Login
User logs in and sends login credentials to API (over SSL/HTTPS)
API receives login credentials
If valid:
Register a new session in the database Read update
Encrypt User ID, Session ID, IP address, timestamp, etc. in a JWT with a private key.
API sends the JWT token back to the client (over SSL/HTTPS)
Client receives the JWT token and stores in localStorage/cookie
Every request to API
User sends a HTTP request to API (over SSL/HTTPS) with the stored JWT token in the HTTP header
API reads HTTP header and decrypts JWT token with its private key
API validates the JWT token, matches the IP address from the HTTP request with the one in the JWT token and checks if session has expired
If valid:
Return response with requested content
If invalid:
Throw exception (403 / 401)
Flag intrusion in the system
Send a warning email to the user.
Updated 30.07.15:
JWT payload/claims can actually be read without the private key (secret) and it's not secure to store it in localStorage. I'm sorry about these false statements. However they seem to be working on a JWE standard (JSON Web Encryption).
I implemented this by storing claims (userID, exp) in a JWT, signed it with a private key (secret) the API/backend only knows about and stored it as a secure HttpOnly cookie on the client. That way it cannot be read via XSS and cannot be manipulated, otherwise the JWT fails signature verification. Also by using a secure HttpOnly cookie, you're making sure that the cookie is sent only via HTTP requests (not accessible to script) and only sent via secure connection (HTTPS).
Updated 17.07.16:
JWTs are by nature stateless. That means they invalidate/expire themselves. By adding the SessionID in the token's claims you're making it stateful, because its validity doesn't now only depend on signature verification and expiry date, it also depends on the session state on the server. However the upside is you can invalidate tokens/sessions easily, which you couldn't before with stateless JWTs.
I would go for the second, the token system.
Did you know about ember-auth or ember-simple-auth? They both use the token based system, like ember-simple-auth states:
A lightweight and unobtrusive library for implementing token based
authentication in Ember.js applications.
http://ember-simple-auth.simplabs.com
They have session management, and are easy to plug into existing projects too.
There is also an Ember App Kit example version of ember-simple-auth: Working example of ember-app-kit using ember-simple-auth for OAuth2 authentication.

How to log out using PKCE authorization flow?

If I have an app and an api. If the app logs in through authorization server and sends the authorization: Bearer xxx header with each request, the api can verify the token locally.
When the user logs out (through the auth server), but the token has not yet expired if someone retrieves this token they will be able to make requests (if the authentication of the token is done locally on the server), is that correct? If thats the case, why is such a logout flow considered secure?
Edit: Clarifying the main question: why PKCE flow is considered secure if when a user logs out their access token is still valid (given we do local token verification)
BEHAVIOUR OVERVIEW
With OAuth there is a greater separation of concerns than in older standalone web apps:
You log into UIs
This is externalised to an Authorization Server
An access token is issued with a fixed / short lifetime
Access tokens are used as API message credentials
The access token can potentially be sent to other components and used from there
When you logout:
You remove tokens from your app
You redirect to tell the Authorization Server the user is no longer logged into any UI
This doesn't invalidate access tokens
TOKEN STORAGE
Tokens should be stored in private memory or protected storage so that attackers cannot access them easily. Your app then removes tokens as part of the logout process so that they are no longer available for attackers to try to access.
THREATS
The OAuth Threat Model has a section on stolen tokens, where it recommends the above storage and to keep tokens short lived. The most common industry default for an access token is 60 minutes.
The main risk of a malicious party stealing a token is via cross site scripting. XSS risks are not related to logout. Security testing should be performed regularly to ensure that XSS risks are mitigated.
BALANCE BETWEEN SECURITY AND PERFORMANCE
It may be possible for the UI to tell the Authorization Server that a token is revoked. However, the API would then need to call the Authorization Server on every API request to check for token revocation. This would lead to poor performance.
API ARCHITECTURE
I always aim to use Claims Caching and introspection in OAuth secured APIs, since it gives the actual API best control, along with good extensibility and performance.
With this in place, if you really wanted to make access tokens non usable after logout, without ruining performance, your UI could perform these actions as part of the logout process:
Revoke the access token at the Authorization Server (if supported)
Call APIs to ask them to remove cached claims for the access token
Okta /introspect can tell you if active is true or false, you could check that on every request if you are not slamming the API https://developer.okta.com/docs/reference/api/oidc/#introspect
It's hard to get access to the token, that's probably a good reason why it's not per definition insecure.
However, providing a logout option is a good idea. OAuth2 has a 'revoke' feature to make sure that tokens are revoked:
https://www.rfc-editor.org/rfc/rfc7009
Not every server supports this.

How are cookies different from JWT and why are they considered worse than JWT?

I have been reading around using tokens for authentication. I, however, fail to understand how tokens (JWT) are different from cookies. Both will store the user info (as claims in tokens), have persistence defined and will be sent with each client request to the server.
Few questions that come to mind, in addition to the above -
Are JWT tokens not prone to Man in the Middle attack? If someone steals a token (on an unencrypted channel), can't they pose as the original user? (unless we add the user's IP etc in the claims)
I've read a few rants that cookies are not good for new-age mobile apps and tokens are the answer. Why?
Why are tokens considered more secure than cookies? What makes them more invulnerable to attacks?
Does a token needs to be issued by the server only, or one can receive a token from another OAuth provider and customize (add/remove claims) and reuse it?
Performance wise, cookies are 'bad' as they have a size limitation, that is why they just store the session ID (typically) with session data in server. This reduces cookie size. But JWT, the whole token needs to be sent, so if the token contains the session data as claims, then we'll be essentially sending this ever increasing token every time. If am getting that correct, isn't that bad performance of JWT as compared to Cookies?
Thanks
Are JWT tokens not prone to Man in the Middle attack?
Yes, you should use HTTPS to ensure that no one can see the JWT in the HTTP request headers. If someone gets the token, they can pose as the original user. The same thing is possible with cookies.
I've read a few rants that cookies are not good for new-age mobile apps and tokens are the answer. Why?
Most mobile apps don't use browsers to make HTTP requests. Browsers make dealing w/cookies seamless for web developers. For mobile developers, using JWT's can be less cumbersome than dealing w/cookies.
Why are tokens considered more secure than cookies? What makes them more invulnerable to attacks?
Tokens aren't necessarily more secure than cookies (a cookie could be signed, just like a JWT). The security benefits come from not being exposed to exploits which trick the browser into inadvertently using the cookies (CSRF attacks).
Does a token needs to be issued by the server only, or one can receive a token from another OAuth provider and customize (add/remove claims) and reuse it?
A JWT is signed with a secret that only the server/organization that generated it should know. So only servers that know the secret can verify the token is valid. While the server that generates the token doesn't have to be the same one that validates it, it doesn't make sense for you to customize and re-use someone else's token.
Reference