For API authentication based on a token: What is the advised practice:
Save the token in the dabase encrypted or unencrypted?
For authentication: find the user based on the token (only possible if the token is stored in the database unencrypted) or based on for example the user's email address?
I found several sources that seem to store an unencrypted token and then in authentication find the user on basis of the token received with the API request. That seems somewhat insecure to me, since then the back end searches the entire User table on basis of the token included in the request, irrespective which user has that token (so someone could just try out many tokens). At the same time I don't know if it it necessary to encrypt the token.
I'd treat it as a password - encrypt it.
Then when user connects, you look up the user specified, you encrypt the provided token and compare the results for that user.
The main reason, is when you get hacked, you don't have to reset everyone's compromised tokens immediately when you restore, you should have a little more time.. as the hacker won't have access to their tokens.. and if your token is salted, may never.
Not that I'd advocate not resetting the token! Just, it's one less immediate issue in the heat of the moment.
Related
It appears to me that JWT based authentication is currently the state-of-the-art way of authenticating a user.
Spring security allows for an easy configuration of the security mechanism by overriding the configure(HttpSecurity http) method of the WebSecurityConfigurerAdapter. Inside this method, I can e.g. set the login method to formLogin. From what I understand, using the formLogin authentication, the user needs to specify a username and a password for every request sent to the server. An alternative is to use JWT based authentication, in which case an access-token needs to be send to the server for every request. I don't see any benefit of the later over the former, so I was hoping someone could explain it to me?
im not going to explain ALL the difference, there are simply too many, but lets look at some:
Session based login (FormLogin)
You present your username and password to the server. The server then creates a session token. This token is in general just a random string. But before we give this string to the client, we also store the string on the server and we also store a boolean flag next to it telling us that the session is "logged in" or we usually call it authenticated.
The client takes this session token and sends it to us everytime it needs to make a request. Everytime someone then sends this token to us we check in our little storage are that we have a record of that token, and that the flag is set to true so.
So we check:
we created the session token
that the token is still logged in
When the client wants to log out, they just send us a logout request, and we just remove that record from our little storage.
Everything works fine so far. Lets introduce another server.
So first server authenticates the user with username and password, and we create a session cookie and return this to the browser, we also store it and everything is the same as before.
But this time we present the cookie (our session token) to server number two.
Server two has no idea what this token is. It has no store to check since it wasnt the one that created the token in the first place. So the server must then call the server that created the token, or the server that created the token must send over the session information to server 2 before.
And with that it becomes hard scale, because then servers need to constantly talk to each other asking things like "what is this token?", "is it valid?" if you have 100s of servers and millions of users, this is a problem.
Token based (oauth2 with JWTs)
In a token based world you have someone that authenticates a user (perhaps using username and password) and that someone issues a token. This service is usually called an issuer.
A JWT is cryptographically signed, which means that if we have a key, we can check that the token hasn't been changed or tampered with.
If we make sure all servers have the key, all servers can independently check that each token they receive is authentic. They dont need to ask the issuer if its authentic, because they can check themselves.
This way the server doesnt need to constantly ask the server that created the token "What is this token?, is it valid?" etc.
And thus we can now scale as long as we can make sure that all servers that need to verify tokens has the proper key to do the validation.
In this scenario no own has a complete record of all the tokens, which means its harder to log someone out. So instead you have to have tokens that are short lived.
Each token contains a timestamap for how long it is valid, and when its not the client needs to refresh this token.
And this is where things usually gets complicated.
So no they are not alike at all. Session based and token based are very different, and i cant explain to you all the differences but here where a few. If you want more information i suggest you read more about it on the internet.
I'm looking to create an application that never uses passwords and want to understand the risks.
Magic Link guides often suggest giving the JWT token a short TTL and to implement one-time use.
A Compromised email account seems to be a mute point because a password can be retrieved using a password reminder. We already depend on email accounts. Furthermore the security around email is far superior (device recognition for example) than most self-built applications.
Passing the JWT token as a query string parameter is not a risk if you use HTTPS, which I would.
Imposing one-time use means maintaining server side token database - one of the reasons for using JWT is not having to do this.
Adopting passwordless means that every time people want to log in they have to go through the email roundtrip which isn't that great UX but is it acceptable?
Once they have gained access all future auth is managed through JWT as usual.
Am I missing something?
You can implement a refresh token which last longer and an access token for a short period so that the user has to log in few times
I am using Spring Security OAuth2 and JWT tokens. My question is: How can I revoke a JWT token?
As mentioned here
http://projects.spring.io/spring-security-oauth/docs/oauth2.html, revocation is done by refresh token. But it does not seem to work.
In general the easiest answer would be to say that you cannot revoke a JWT token, but that's simply not true. The honest answer is that the cost of supporting JWT revocation is sufficiently big for not being worth most of the times or plainly reconsider an alternative to JWT.
Having said that, in some scenarios you might need both JWT and immediate token revocation so lets go through what it would take, but first we'll cover some concepts.
JWT (Learn JSON Web Tokens) just specifies a token format, this revocation problem would also apply to any format used in what's usually known as a self-contained or by-value token. I like the latter terminology, because it makes a good contrast with by-reference tokens.
by-value token - associated information, including token lifetime, is contained in the token itself and the information can be verified as originating from a trusted source (digital signatures to the rescue)
by-reference token - associated information is kept on server-side storage that is then obtained using the token value as the key; being server-side storage the associated information is implicitly trusted
Before the JWT Big Bang we already dealt with tokens in our authentication systems; it was common for an application to create a session identifier upon user login that would then be used so that the user did not had to repeat the login process each time. These session identifiers were used as key indexes for server-side storage and if this sounds similar to something you recently read, you're right, this indeed classifies as a by-reference token.
Using the same analogy, understanding revocation for by-reference tokens is trivial; we just delete the server-side storage mapped to that key and the next time the key is provided it will be invalid.
For by-value tokens we just need to implement the opposite. When you request the revocation of the token you store something that allows you to uniquely identify that token so that next time you receive it you can additionally check if it was revoked. If you're already thinking that something like this will not scale, have in mind that you only need to store the data until the time the token would expire and in most cases you could probably just store an hash of the token so it would always be something of a known size.
As a last note and to center this on OAuth 2.0, the revocation of by-value access tokens is currently not standardized. Nonetheless, the OAuth 2.0 Token revocation specifically states that it can still be achieved as long as both the authorization server and resource server agree to a custom way of handling this:
In the former case (self-contained tokens), some (currently non-standardized) backend interaction between the authorization server and the resource server may be used when immediate access token revocation is desired.
If you control both the authorization server and resource server this is very easy to achieve. On the other hand if you delegate the authorization server role to a cloud provider like Auth0 or a third-party component like Spring OAuth 2.0 you most likely need to approach things differently as you'll probably only get what's already standardized.
An interesting reference
This article explain a another way to do that: Blacklist JWT
It contains some interesting pratices and pattern followed by RFC7523
The JWT cann't be revoked.
But here is the a alternative solution called as JWT old for new exchange schema.
Because we can’t invalidate the issued token before expire time, we always use short-time token, such as 30 minute.
When the token expired, we use the old token exchange a new token. The critical point is one old token can exchange one new token only.
In center auth server, we maintain a table like this:
table auth_tokens(
user_id,
jwt_hash,
expire
)
user_id contained in JWT string.
jwt_hash is a hash value of whole JWT string,Such as SHA256.
expire field is optional.
The following is work flow:
User request the login API with username and password, the auth server issue one token, and register the token ( add one row in the table. )
When the token expired, user request the exchange API with the old token. Firstly the auth server validate the old token as normal except expire checking, then create the token hash value, then lookup above table by user id:
If found record and user_id and jwt_hash is match, then issue new token and update the table.
If found record, but user_id and jwt_hash is not match , it means someone has use the token exchanged new token before. The token be hacked, delete records by user_id and response with alert information.
if not found record, user need login again or only input password.
when use changed the password or login out, delete record by user id.
To use token continuously ,both legal user and hacker need exchange new token continuously, but only one can succeed, when one fails, both need to login again at next exchange time.
So if hacker got the token, it can be used for a short time, but can't exchange for a new one if a legal user exchanged new one next time, because the token validity period is short. It is more secure this way.
If there is no hacker, normal user also need exchange new token periodically ,such as every 30 minutes, this is just like login automatically. The extra load is not high and we can adjust expire time for our application.
source: http://www.jianshu.com/p/b11accc40ba7
This doesn't exactly answer you question in regards to the Spring framework, but here's an article that talks about why if you need the ability to revoke JWT's, you might not want to go with JWT's in the first place, and instead use regular, opaque Bearer tokens.
https://www.dinochiesa.net/?p=1388
One way to revoke a JWT is by leveraging a distributed event system that notifies services when refresh tokens have been revoked. The identity provider broadcasts an event when a refresh token is revoked and other backends/services listen for the event. When an event is received the backends/services update a local cache that maintains a set of users whose refresh tokens have been revoked.
This cache is then checked whenever a JWT is verified to determine if the JWT should be revoked or not. This is all based on the duration of JWTs and expiration instant of individual JWTs.
This article, Revoking JWTs, illustrates this concept and has a sample app on Github.
For Googlers:
If you implement pure stateless authentication there is no way to revoke the token as the token itself is the sole source of truth
If you save a list of revoked token IDs on the server and check every request against the list, then it is essentially a variant of stateful authentication
OAuth2 providers like Cognito provides a way to "sign out" a user, however, it only really revokes refresh token, which is usually long-lived and could be used multiple times to generate new access tokens thus has to be revoked; the existing access tokens are still valid until they expire
What about storing the JWT token and referencing it to the user in the database? By extending the Guards/Security Systems in your backend application with an additional DB join after performing the JWT comparison, you would be able to practically 'revoke' it by removing or soft-deleting it from the DB.
In general, the answer about tokens by reference vs. tokens by value has nailed it. For those that stumble upon this space in future.
How to implement revocation on RS side:
TL;DR:
Take a cache or db that is visible to all your backend service instances that are verifying tokens. When a new token arrives for revocation, if it's a valid one, (i.e. verifies against your jwt verification algo), take the exp and jti claims, and save jti to cache until exp is reached. Then expire jti in cache once unixNow becomes > exp.
Then on authorization on other endpoints, you check everytime if a given jti is matching something in this cache, and if yes, you error with 403 saying token revoked. Once it expires, regular Token Expired error kicks in from your verification algo.
P.S. By saving only jti in cache, you make this data useless to anyone since it's just a unique token identifier.
The best solution for JWT revocation, is short exp window, refresh and keeping issued JWT tokens in a shared nearline cache. With Redis for example, this is particularly easy as you can set the cache key as the token itself (or a hash of the token), and specify expiry so that the tokens get automatically evicted.
I found one way of resolving the issue, How to expire already generated existing JWT token using Java?
In this case, we need to use any DB or in-memory where,
Step 1: As soon as the token is generated for the first time for a user, store it in a db with the token and it's "issuedAt()" time.
I stored it in DB in this JSON format,
Ex: {"username" : "username",
"token" : "token",
"issuedAt" : "issuedAt" }
Step 2: Once you get a web service request for the same user with a token to validate, fetch "issuedAt()" timestamp from the token and compare it with stored(DB/in-memory) issued timestamp.
Step 3: If stored issued timestamp is new (using after()/before() method) then return that the token is invalid (in this case we are not actually expiring the token but we are stop giving access on that token).
This is how I resolved the issue.
I'm trying to add authentication feature to my application.
The authentication server implements oauth 2.0
I'm not sure how to save the refresh_token. I want to save it to a file, so next time when the application starts and there is a refresh_token available, it can ask for a new access_token. The user won't need to re-login again.
But this doesn't sound secure to me, because if someone copies my file that has the refresh_token to another computer, he can hack into my account.
You are correct with the attack that you describe. Refresh tokens have to be stored securely in order to be used as intended. As I understand, you are building a standalone application. Therefore, you can rely on file system security to prevent a refresh token being copied by an unauthorized user. You may want to use encryption for the refresh token, too, but the key would need to be bound to a user's session at your local machine (otherwise, the user would need to provide it during "sign in" process in order for the application to decrypt the refresh token).
Consider reading the thread from the OAuth WG, that discusses similar problems to the one described and provides some guidance:
https://www.ietf.org/mail-archive/web/oauth/current/msg02292.html
Refresh tokens are used to obtain access (this process requires HTTP Basic Auth). So, unless user has your (id,secret) combination he can't do much about it. However, storage of refresh token must be considered very seriously.
Here's my two cents:
Store your tokens in a DB
Whenever you use refresh token to obtain access token reset the refresh token as well. (Oauth2.0 has this feature, you can let the refresh token unchanged too, but it's wise in terms of security perspective to keep it changing and updating the DB)
Hope this gives some insights!!
You are right about your concern - you should not save the refresh token. By doing so, you jeopardize your client's data (and you know the reason; you wrote it in the question).
oAuth is not supposed to work this way.
You should keep the refresh token in-memory.
I am just getting started working with Google API and OAuth2. When the client authorizes my app I am given a "refresh token" and a short lived "access token". Now every time the access token expires, I can POST my refresh token to Google and they will give me a new access token.
My question is what is the purpose of the access token expiring? Why can't there just be a long lasting access token instead of the refresh token?
Also, does the refresh token expire?
See Using OAuth 2.0 to Access Google APIs for more info on Google OAuth2 workflow.
This is very much implementation specific, but the general idea is to allow providers to issue short term access tokens with long term refresh tokens. Why?
Many providers support bearer tokens which are very weak security-wise. By making them short-lived and requiring refresh, they limit the time an attacker can abuse a stolen token.
Large scale deployment don't want to perform a database lookup every API call, so instead they issue self-encoded access token which can be verified by decryption. However, this also means there is no way to revoke these tokens so they are issued for a short time and must be refreshed.
The refresh token requires client authentication which makes it stronger. Unlike the above access tokens, it is usually implemented with a database lookup.
A couple of scenarios might help illustrate the purpose of access and refresh tokens and the engineering trade-offs in designing an oauth2 (or any other auth) system:
Web app scenario
In the web app scenario you have a couple of options:
if you have your own session management, store both the access_token and refresh_token against your session id in session state on your session state service. When a page is requested by the user that requires you to access the resource use the access_token and if the access_token has expired use the refresh_token to get the new one.
Let's imagine that someone manages to hijack your session. The only thing that is possible is to request your pages.
if you don't have session management, put the access_token in a cookie and use that as a session. Then, whenever the user requests pages from your web server send up the access_token. Your app server could refresh the access_token if need be.
Comparing 1 and 2:
In 1, access_token and refresh_token only travel over the wire on the way between the authorzation server (google in your case) and your app server. This would be done on a secure channel. A hacker could hijack the session but they would only be able to interact with your web app. In 2, the hacker could take the access_token away and form their own requests to the resources that the user has granted access to. Even if the hacker gets a hold of the access_token they will only have a short window in which they can access the resources.
Either way the refresh_token and clientid/secret are only known to the server making it impossible from the web browser to obtain long term access.
Let's imagine you are implementing oauth2 and set a long timeout on the access token:
In 1) There's not much difference here between a short and long access token since it's hidden in the app server. In 2) someone could get the access_token in the browser and then use it to directly access the user's resources for a long time.
Mobile scenario
On the mobile, there are a couple of scenarios that I know of:
Store clientid/secret on the device and have the device orchestrate obtaining access to the user's resources.
Use a backend app server to hold the clientid/secret and have it do the orchestration. Use the access_token as a kind of session key and pass it between the client and the app server.
Comparing 1 and 2
In 1) Once you have clientid/secret on the device they aren't secret any more. Anyone can decompile and then start acting as though they are you, with the permission of the user of course. The access_token and refresh_token are also in memory and could be accessed on a compromised device which means someone could act as your app without the user giving their credentials. In this scenario the length of the access_token makes no difference to the hackability since refresh_token is in the same place as access_token. In 2) the clientid/secret nor the refresh token are compromised. Here the length of the access_token expiry determines how long a hacker could access the users resources, should they get hold of it.
Expiry lengths
Here it depends upon what you're securing with your auth system as to how long your access_token expiry should be. If it's something particularly valuable to the user it should be short. Something less valuable, it can be longer.
Some people like google don't expire the refresh_token. Some like stackflow do. The decision on the expiry is a trade-off between user ease and security. The length of the refresh token is related to the user return length, i.e. set the refresh to how often the user returns to your app. If the refresh token doesn't expire the only way they are revoked is with an explicit revoke. Normally, a log on wouldn't revoke.
Hope that rather length post is useful.
In addition to the other responses:
Once obtained, Access Tokens are typically sent along with every request from Clients to protected Resource Servers. This induce a risk for access token stealing and replay (assuming of course that access tokens are of type "Bearer" (as defined in the initial RFC6750).
Examples of those risks, in real life:
Resource Servers generally are distributed application servers and typically have lower security levels compared to Authorization Servers (lower SSL/TLS config, less hardening, etc.). Authorization Servers on the other hand are usually considered as critical Security infrastructure and are subject to more severe hardening.
Access Tokens may show up in HTTP traces, logs, etc. that are collected legitimately for diagnostic purposes on the Resource Servers or clients. Those traces can be exchanged over public or semi-public places (bug tracers, service-desk, etc.).
Backend RS applications can be outsourced to more or less trustworthy third-parties.
The Refresh Token, on the other hand, is typically transmitted only twice over the wires, and always between the client and the Authorization Server: once when obtained by client, and once when used by client during refresh (effectively "expiring" the previous refresh token). This is a drastically limited opportunity for interception and replay.
Last thought, Refresh Tokens offer very little protection, if any, against compromised clients.
It is essentially a security measure. If your app is compromised, the attacker will only have access to the short-lived access token and no way to generate a new one.
Refresh tokens also expire but they are supposed to live much longer than the access token.
I've written a little about this because I was pondering the reasoning myself today.
https://blog.mukunda.com/cat/2023/refreshing-access-tokens.txt
Essentially, I think the main security boost is only there if the refresh token does not remain the same over its lifetime.
Let's say someone steals your tokens from your browser cookies because they had access to your device temporarily.
If they use the refresh token, and the refresh token changes, then you have feedback – you are logged out. That can seem rightfully suspicious to careful users who can then take action and revoke all tokens.
If the refresh token doesn't update upon each use, then it is harder to notice that someone has access in tandem. (Chances are, if does update, then it might update from your device automatically before the attacker can even get to use it.)
If the refresh token does not get updated each time you use it, then I don't see any boost in security from the strategy, since it will be right next to the access token and client secrets.
So, why access tokens? It is so you can check that your credentials are valid regularly.
Do refresh tokens expire? Yes, but usually after a few months if you have "remember me" ticked. There's no expiration time in the spec, so you just go until it fails. Services that require longer unmonitored sessions might have secret credentials so they can refresh their refresh token.
Update:
I also glossed through the OAuth 2.0 specification and see the same reasoning, though it emphasizes that the invalid authentication feedback can be caught on the server side. That is a great point – the server can automate revoking the token if it is compromised.
If a refresh token is compromised and subsequently used by both the attacker and the legitimate client, one of them will present an invalidated refresh token, which will inform the authorization server of the breach.