Is it a good practice to store JWT Tokens in memory - asp.net-core

I wrote an asp.net core 3.0 web api where I am using JWT tokens to authenticate a user. Once the user gets token, he/she can use it until it expires.
What I have done is that I have also stored this token in-memory on authentication, to get other minimal details e.g. username, token generated at and "token".
My first question is that is it a good practice? since tokens are stateless and therefore saves server side from the hassle of maintaining it.
My second question is that if it is acceptable to do so, then how do I remove this token information from in-memory once a token expires.
If I am not storing this token in memory, how to extract information like "get a list of all logged-in users".

Yes, it is a good practice to cache the JWT in memory cache like Redis or simple in-memory cache. The newly created tokens are cached in memory with cache eviction time same as token expiration time.
When a request comes in to validate token, its first checked whether it exists in memory cache, if not will be looked in to persistent storage like db.
When the user invalidates token(ie logged out), it should be removed from cache and update the state to invalidated in db.
In a distributed application, its a challenge to maintain the state. For this reason, its better to have separate caching layer backed by redis. In this way, we can maintain the application stateless.
In addition to token expiration time, you may want to add additional check for validation, depends on the content of JWT like (aud claim, signature verification etc).
To retrospect the content of JWT token , you can use tools like below
https://devtoolzone.com/decoder/jwt
Cheers,
Lakshmanan

When you say "in memory", does that mean locally on the client machine or somewhere in the server? I'm going to assume you mean client-side for their use.
I'm currently using JWT myself, so here are my recommendations:
1) Save the tokens in session storage.
2) Just empty the session (or wherever you're storing it).
3) You'll definitely need to store it somewhere if you want to access it. But getting a list of all users sounds like you want the data on the back-end. You can keep track of that on a back-end server, but usually these tokens are handled and persisted into databases. But even on a back-end server, you can just have a array of Client objects to track which ones are logged in (i.e. which ones have unexpired tokens).
The typical practice involves generating two tokens (auth token and refresh token) and then checking them against a database when the user submits a token for authentication.

Related

Refresh tokens: security & implementation

When a user is authenticated by the server, the server sends, according to the most common implementation I found(which is were my question stems from), sends BOTH access token and the refresh token to the client.
-- My first questions is:
What is the point of sending both tokens to the client if, to my understanding, we have the refresh token in the first place to help us mitigate the consequences of an access token being leaked?
If both tokens are sent to the client and are stored together (in the same place, localStorage, sessionStorage, one in former, one in latter - I don't think it matters to the questions how we decide to store them on the client), if an attacker manages to steal the access token, then it is safe to assume he would also find a way to steal the refresh token from the same client since they are most likely stored together. I don't understand why most implementations and answers I find online mention sending both tokens to the client since its basically like putting all eggs in the same basket.
(A big part of my confusion comes also from the fact that those answers and implementations don't mention anything about storing the tokens in HttpOnly cookies, which I'd think would be a common practice if we want to prevent tokens getting leaked, so I'm getting a feeling I'm missing something)
-- My second question would be:
Would it be a correct solution then to persist the access and refresh tokens upon issue in an "accessT <-> refreshT"(like a key=value pair) table on a server, so that only one token is ever sent to the client - the access token? And when that access token expires the process of "refreshing" would be the following:
ResServer = resource server
AuthServer = authorization server
The request with the expired token is sent to the ResServer.
ResServer checks and sees that the access token has expired.
ResServer then sends a request to the AuthServer to look up the refresh token by the access token in the table mention above.
If AuthServer finds a refresh token by using the expired access token as a key - good, AuthServer generates a new access token.
AuthServer then responds to the ResServer with that new access token.
Having received a positive response, ResServer proceeds on with it's usual flow for authorized users.
^^ This seems to me to be a more rational way of keeping the refresh token safe - making it serve its primary function, which is why I don't understand why most other implementations on the web always mention sending both tokens to the client.
-- And my third question is:
Not having much experience implementing microservices, I am confused about why we would ever prefer to implement this token back and forth approach, when, from what I understand, the entire point of tokens is that they are supposed to be a stateless solution(well, the refresh token is always kept on the server regardless of implementation, which confuses me even more about that "stateless" part). Doesn't it make more sense to just use cookies that basically serve the same function, but are easier to implement, secure by default("Secure", "HttpOnly" flags), and, as it appears to me, are much easier to revoke in can they are leaked?
Thanks you for taking your time to read this entire post, I appreciate your help.
Regarding your first question:
The advantage of having two tokens is not that you can store one of the tokens more securely. The advantage is that if the Resource Server gets compromised, it does not allow lateral escalation. For this to make sense, your access tokens must be bound to specific resource servers.
As an example, assume you have two resource servers ResA and ResB. Then your Authentication server would allow you to obtain one access token for each of these servers, and one refresh token (that allows refreshing both access tokens). If resource server A gets compromised (or the network path between the client and that server), then the access token to that server will expire at some point, and the attacker will not be able to access resource server B with the access token issued for resource server A. At the same time, only the legitimate user is able to refresh their tokens, since they only provide the refresh token to the AuthServer, such that a compromised or malicious resource server never sees at.
That leads directly to your second question:
Your proposed model prevents key rollover. If a resource server gets compromised, all its tokens are eternally compromised, unless the Authentication Server voids all refresh tokens. Voiding refresh tokens would lead to users being logged out of all resource servers (even those who are not compromised).
As an example, consider the following scenario: Tour authentication provider is a large public service, such as "Sign in with Google", with thousands of resource servers using this service. Now one of those resource servers gets compromised, and attackers steal the authentication tokens.
In the commonly employed auth-refresh token pattern, the auth tokens will expire, which means that the service will be inaccessible for attackers as soon as the used vulnerability is fixed + the time it takes for tokens to expire (since the attackers could not get hold of the resource tokens), without the need for the AuthServer to do anything. Additionally, the AuthServer does not need to keep track of the issued tokens, if it uses cryptography to sign the tokens with a private key only known to the auth server, as it (and all resource servers) can trivially verify token authenticity by validating against a public key (please also see the end of my answer).
In your proposed approach, the AuthServer (which is Google in this example) would have to void all refresh tokens OR they would have to selectively delete all auth-refresh token pairs for the affected resource server from the key-value store. That key-value store will be gigantic, since it has to contain EVERY auth token ever issued, for any service that uses "Sign in with Google", and apart from storage costs, this delete operation will take quite some time.
Regarding your last question:
You can store access tokens in Cookies. There is a bunch of advantages to that (including the Secure and HttpOnly flags that you mentioned). It has two disadvantages: If you want to implement something like a CLI client that runs outside of a browser, you would have to implement Cookie handling. The other disadvantage is the CSRF risk as Cookies are automatically sent on every request. Using local storage prevents this, as an external website cannot access the local storage of your website to extract the token.
In the end it comes down to the concrete scenario, if Cookies or Local Storage + Custom Header are the preferable solution.
However, I think you have a misconception regarding statefulness:
Access and Refresh tokens do not need to be stored on the server. Instead, the Auth Server signs the Token Contents with a cryptographic private key, before sending them to a client. In doing so, the AuthServer includes an expiration date in the token, which is included in the signed content.
To validate the token, the Resource Server (or the AuthServer) checks if the signature comes from the AuthServer's private key, and then checks if the expiration date has passed. In particular, the resource server does not need to communicate with the AuthServer, apart from obtaining its Public Key from time to time. This makes this solution scale really well for very large deployments. See the Microsoft Azure docs, which do a great job on explaining the difference between Auth and Refresh tokens.
What you are alluding to are traditional session ids, which are stored on the server until they expire. Thats obviously a much simpler solution, and works well for smaller, more monolithic applications. It just does not work for hyper scalers.

Is local storage the best way to store JWT token on client side? ( Assuming best practices are in place for preventing XSS )

Let us say you are taking the needed steps to prevent XSS such as input validation, and input Sanitizing, also you are very careful about XSS so you do daily code reviews that checks for malicious code;
Would storing a JWT token in browser local storage is the safest in this situation compared to storing it in a cookie or http only cookie ?
To describe this more lets say the JWT access token lives in a redux store in a REACT APP. The app auto-log out users after 1 hour of inactivity. You provide the token as a global state.
The access token for authenticated users only keeps them in the authorized part of the site, they can not use it to retrieve anything from the backend.
Note: Nothing on your application is safe when you are not preventing XSS by daily code reviews.
If you're asking whether storing JWT in local storage makes them more or less safe, the general answer is that it doesn't matter, as JWT are tamper proof, and any attempt to modify them will immediately be detected by the server which issued them. In terms of protecting any visible data contained in a JWT, storing them in local storage increases the chances that prying eyes might see this data. If this be a concern, then consider encrypting them.

Does Using Opaque Access Tokens Make My Server Stateful? [duplicate]

I am trying to understand statelessness in restful APIs in the context of authentication. Here's the scenario:
The user logs in.
The server verifies the username and the password, and generates an opaque access token. It caches some information related to this token - for example, the expiration time, the userId, whether this token was explicitly invalidated before it expired, etc.
The token is sent to the client, and the client sends it with every future request.
List item
Fielding's dissertation defines statelessness as:
"...such that each request from client to server must contain all of the information necessary to understand the request, and cannot take advantage of any stored context on the server. Session state is therefore kept entirely on the client."
In my example, the client is sending the token with every request, so the first condition is satisfied. However, my server has a context associated with this session that is stored in the sessions cache.
Does this make my application stateful?
If yes, then is it that true statelessness be achieved only if we are using JWTs? I am pondering upon this as JWTs are quite new, so how were architects building truly stateless services before they were invented?
That's right. If you you maintaining the session you are keeping the state in server which makes the application hard to scale. True stateless applications can be scaled out and any server should be able to handle the request.
JWT is popular way to avoid sessions and everything is encapsulated inside the token for any server to auth/Authorize the request and help us achieve stateless application, they come with their own challenges however OpenID connect is the new way for Auth/Authorization.
Before jwt to make application stateless we used to keep session in DB (or Shared Cache) , and any server would like to check the session would have to contact DB.
Hope that Helps!
Briefly: No, such usage of token does not make your application stateful.
Detailed: When we talk about stateless/stateful, we consider usually only the data that affect business logic. Business logic does not usually depend on authentication data. For example, a user sends a request that contains all data needed to place some order. Normally creating an order does not depend on when this user has logged in, on his user ID, etc.

Where to store authentication token in RESTful API

I have started to design a RESTful API and I'm thinking about how to handle authentication. I want to use some kind of authentication token but I can't use OAuth o similar infrastructures so I have to handle it myself.
One of the requirements for this API is that it must have good performance, enough to handle a high volume of requests before there is the need to scale; my concern is how to make on each request the time needed to verify the token (integrity, expiration, IP Address, etc...) as little as possibile.
I suppose the token should some kind of hash and not an encrypted string containing the user information because the decryption time would be to heavy.
I've read that I could store the tokens in an in-memory hashtable where the key is the token and the value is the user info needed to process the request, but how can I make this work in a clustered environment where there will be an hashtable on each "node"?
Should I put tokens on a DB table an hit the DB every time also Handling manually the retention of expired tickets?
Probably it's not that important for the question but I'm using Spring MVC for the RESTfull API.
Thanks in advance.
I solved my problem by using both an in-memory cache and a db cache. Here is a summary of my solution that may help anyone with the same task.
the user logs in and in that moment a unique key is generated and sent back to the user.
that login token (which is basically a GUID with some processing) is also store in a db table with additional info like exipiration and with the user's info and roles. the same pieces of information are also store in memory (google guava hashtable where the token is the key)
the token must be passed along with every api call in the authorization token as #ipa suggested
the server code checks if the token is in its memory cache the user info are already available otherwise (e.g. the api call is done on another node in the cluster) the token is search in the token db
once the token is found you can check expiration, roles, etc...
This grants a good level of performance and security, the token can be generated with any arbitrary algorithm even a relative slow one since you don't have to recalculate it on every api call. Also this works with a stateless service wich can be scaled up horizontally.
I assume you use https and therefore all the traffic is encrypted. I'd suggest one of the following principles.
Basic Authentication
You can add the credentials in the Authorization header of the request. This credentials are encoded with Base64 (see below). This credentials could be sent on every request and then checked with your DB. To get this faster and less IO intensive you can still use a cache. Once I implemented an API like this without a cache and was able to handle thousands of requests per second.
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==
Authorization Token
There are different ways to implement your idea with a token. A common one is that every API user has his own token usually called api key which never expires. Another one is that you first have to authorize (Basic Authentication) and then get a token back which expires. This one is then used as api key for a certain time.
Either way you have to decide whether to use a cache or not. I would keep it simple and go for basic authentication and check the db every time. Almost every framework has very good support for this approach because it's simple http. If this causes performance issues (I'd recommend performance tests anyway) try to add the table with your credentials to the JPA cache. If you want to implement something with expiring tokens have a look at Infinispan.
You can store token in Redis. If you are going to store it in DB, make sure you optimise server (if you are managing it) for read operations. I have couple of implementation where folks have used key value store as well. Hashtable is also good idea.

what's the point of refresh token?

i have to confess i've had this question for a very long time, never really understand.
say auth token is like a key to a safe, when it expires it's not usable anymore. now we're given a magic refresh token, which can be used to get another usable key, and another... until the magic key expires. so why not just set the expiration of the auth token as the same as refresh token? why bother at all?
what's the valid reason for it, maybe a historical one? really want to know. thanks
I was reading an article the other day by Taiseer Joudeh and I find it very useful he said:
In my own opinion there are three main benefits to use refresh tokens which they are:
Updating access token content: as you know the access tokens are self contained tokens, they contain all the claims (Information) about the authenticated user once they are generated, now if we issue a long lived token (1 month for example) for a user named “Alex” and enrolled him in role “Users” then this information get contained on the token which the Authorization server generated. If you decided later on (2 days after he obtained the token) to add him to the “Admin” role then there is no way to update this information contained in the token generated, you need to ask him to re-authenticate him self again so the Authorization server add this information to this newly generated access token, and this not feasible on most of the cases. You might not be able to reach users who obtained long lived access tokens. So to overcome this issue we need to issue short lived access tokens (30 minutes for example) and use the refresh token to obtain new access token, once you obtain the new access token, the Authorization Server will be able to add new claim for user “Alex” which assigns him to “Admin” role once the new access token being generated
Revoking access from authenticated users: Once the user obtains long lived access token he’ll be able to access the server resources as long as his access token is not expired, there is no standard way to revoke access tokens unless the Authorization Server implements custom logic which forces you to store generated access token in database and do database checks with each request. But with refresh tokens, a system admin can revoke access by simply deleting the refresh token identifier from the database so once the system requests new access token using the deleted refresh token, the Authorization Server will reject this request because the refresh token is no longer available (we’ll come into this with more details).
No need to store or ask for username and password: Using refresh tokens allows you to ask the user for his username and password only one time once he authenticates for the first time, then Authorization Server can issue very long lived refresh token (1 year for example) and the user will stay logged in all this period unless system admin tries to revoke the refresh token. You can think of this as a way to do offline access to server resources, this can be useful if you are building an API which will be consumed by front end application where it is not feasible to keep asking for username/password frequently.
I would like to add to this another perspective.
Stateless authentication without hitting the DB on each request
Let's suppose you want to create a stateless (no session) security mechanism that can do authentication of millions of users, without having to make a database call to do the authentication. With all the traffic your app is getting, saving a DB call on each request is worth a lot! And it needs to be stateless so it can be easily clustered and scaled up to hundreds or even thousands of servers.
With old-fashioned sessions, the user logs in, at which point we read their user info from the database. To avoid having to read it again and again we store it in a session (usually in memory or some clustered cache). We send the session ID to the client in a cookie, which is attached to all subsequent requests. On subsequent requests, we use the session ID to lookup the session, that in turn contains the user info.
Put the user info directly in the access token
But we don't want sessions. So instead of storing the user info in the session, let's just put it in an access token. We sign the token so no one can tamper with it and presto. We can authenticate requests without a session and without having to look up the user info from the DB for each request.
No session ... no way to ban users?
But not having a session has a big downside. What if this user is banned for example? In the old scenario we just remove his session. He then has to log in again, which he won't be able to do. Ban completed. But in the new scenario there is no session. So how can we ban him? We would have to ask him (very politely) to remove his access token. Check each incoming request against a ban list? Yes, would work, but now we again have to make that DB call we don't want.
Compromise with short-lived tokens
If we think it's acceptable that a user might still be able to use his account for, say, 10 minutes after being banned, we can create a situation that is a compromise between checking the DB every request and only on login. And that's where refresh tokens come in. They allow us to use a stateless mechanism with short-lived access tokens. We can't revoke these tokens as no database check is done for them. We only check their expiry date against the current time. But once they expire, the user will need to provide the refresh token to get a new access token. At this point we do check the DB and see that the user has been banned. So we deny the request for an access token and the ban takes effect.
The referenced answer (via #Anders) is helpful, It states:
In case of compromise, the time window it's valid for is limited, but
the tokens are used over SSL, so unlikely to be compromised.
I think the important part is that access tokens will often get logged (especially when used as a query parameter, which is helpful for JSONP), so it's best for them to be short-lived.
There are a few additional reasons, with large-scale implementations of OAuth 2.0 by service providers:
API servers can securely validate access tokens without DB lookups or RPC calls if it's okay to not worry about revocation. This can have strong performance benefits and lessen complexity for the API servers. Best if you're okay with a token revocation taking 30m-60m (or whatever the length of the access token is). Of course, the API servers could also keep an in-memory list of tokens revoked in the last hour too.
Since tokens can have multiple scopes with access to multiple different API services, having short-lived access tokens prevents a developer of API service for getting a lifelong access to a user's data on API service B. Compartmentalization is good for security.
Shortes possible answer:
Refresh tokens allow for scoped / different decay times of tokens. Actual resource tokens are short lived, while the refresh token can remain valid for years (mobile apps). This comes with better security (resource tokens don't have to be protected) and performance (only the refresh token API has to check validity against DB).
The following is an addition to the benefits of refresh tokens that are already mentioned.
Safety First!
Access tokens are short-lived. If someone steals an access token, he will have access to resources only until access token expires.
"...But what if a refresh token is stolen?"
If an attacker steals the refresh token, he can obtain an access token. For this reason, it it recommended that a new refresh token is issued each time a new access token is obtained. If the same refresh token is used twice, it probably means that the refresh token has been stolen.
When the refresh token changes after each use, if the authorization
server ever detects a refresh token was used twice, it means it has
likely been copied and is being used by an attacker, and the
authorization server can revoke all access tokens and refresh tokens
associated with it immediately.
https://www.oauth.com/oauth2-servers/making-authenticated-requests/refreshing-an-access-token/
Of course, this is just another layer of security. The attacker can still have time to obtain access tokens, until the refresh token is used a second time (either by the attacker or the real user).
Always keep in mind that the refresh token must be stored as securely as possible.