JWT - per user signing key - redis

In my project there's a requirement to invalidate all jwt tokens of a user when the user changes his password. I was thinking of giving each user a different signing key, and simply reset the key when password is changed. Then I googled around and found Redis is a good place to store those per-user keys. Everything seems to work just fine.
But there one thing I cannot get my head around. Since it has to hit Redis once per request, is it any different than issuing the user an opaque token instead of JWT, and store the token -> JWT payload mapping in Redis?Isn't that defeats the purpose of using JWT?

To invalidate tokens you need to revoke them. OAuth spec also does not require getting secret key from remote server every time you need to validate JWT (as you said it kind of defeats the purpose). The key can be stored locally at resource site.
You have two options here:
1) Introspect the JWT token from resource side against OAuth server every time it validates it. Seems like overkill to me. The best approach is to give short expiration time to JWT token and let the already issued tokens to just expire.
2) Have the resource store the secret key locally and when it fails to validate go and get the key and re-validate it again.

From the point of view of invalidating the token, there's no particular need to store the JWT in Redis - anything that you can check and later invalidate should do the trick.
That said, presumably you're using a JWT for other reasons. For example, it's what the AuthN/Identity service provides. Or perhaps you use it to store claims or other metadata that you validate as part of the AuthN/AuthZ logic. In that case, since it's handy, storing the JWT seems very reasonable.

Related

Why do we need refresh tokens in JWT

I'm just learning JWT in nodejs, and I found out about refresh tokens.
As far as I understand, a user gets an access token and a refresh token. After the access token expires, a request containing the refresh token is made to get a new access token. To get a new access token, the server checks if the received refresh token is contained in a database. If the refresh token is stolen, it can easily be deleted from the DB and prevent further refreshes.
My question is: Why don't we just make the access tokens behave like refresh tokens? i.e. We store them in a database and check if they are there when making a request, and when compromised we just delete them?
The key element to answering your question is: You need to add an expiration date on access tokens you deliver to clients. This is the main purpose with refresh token.
Imagine someone steels your access_token, and you didn't make it expirable: It means that as long as you didn't discover that your access_token has been stolen, you're giving literaly a lifetime free pass to whoever has it.
With refresh tokens and expirable access_tokens, you know that the window of vulnerability is really small.
Now your second question: Why don't we make access_tokens behave like refresh_tokens ?
The key idea here is to keep your refresh_token in a safe spot, and only expose access_tokens.
And by the way, refresh_tokens have one job: Carry information to generate new access_tokens, access_tokens on the other hand have their own job: Carry information necessary to give you direct access to resources.
If you pay attention to most serious websites, they have a centralized auth server that serves access_tokens.
Answering comments:
Key difference between them is: refresh token key is like a master key, it stays on the authorization server and is never ever shared with any other server, unlike access token key, it can be passed to another server to authenticate users
in other words:
auth.yourapp.com: stores access_token_key and refresh_token_key
api.yourapp.com: stores access_token_key ONLY, to make sure that users did actualy authenticate on your auth.yourapp.com domain, and api.yourapp.com can easily confirm that. if access_token_key has been compromised, vulnerability has a shorter lifetime, and you can easily isolate the attacked server.
if one of your servers is compromised, the rest is safer.

Generating an API Secret

I have created an API that I only want certain clients having access to. After a bit of research, I found that API Keys and API Secrets are pretty good way of controlling that.
I want to basically generate my own secrets using information I control. For example, if I create the secret 1500315177265-8005550000-System, the secret itself has information I can reference and validate. From what I understand, it doesn't matter what the secret is, as long as its not shared, and that's what makes it a secret. I can append some long salt values to make it much harder to guess. Can I use secrets securely this way?
Along the same lines, I am thinking what the need for the API Key is needed if the secret itself has identifying information. More than likely, I'm missing something here or more APIs would do it this way.
You don't need to suffer creating this mechanism by your own, you could just use OAuth for this. Actually by reading how OAuth works, I'm pretty sure that you'll get an overall idea of what the "API Key" is doing.
Long story short. OAuth allows you to create access tokens that will be requested by your users, once the user has asked for an access token, he'll be able to use it to get authenticated on the API.
You can also configure the duration for these access tokens, for example, let's say that you only want them to be valid for one hour. Then the user will use a new access token every hour, helping you to minimize risks against compromised access tokens.
If you want to take a look at the pipeline used by OAuth, it will be something like this:
The user sends an identifier and a shared secret (see them as username and password). If the identifier and the secret are correct, he'll receive a "refresh token", this token will be used to send requests to the token server to receive new "access tokens". The client sends a request to the tokens server to receive an access token, and now he'll be able to send requests to your API, where he'll use his access token as an identifier, and only if the token is valid, he'll get access to your application.
Maybe you could be curious about expired tokens, for example, What happens when the token has expired? Now our user needs to repeat all process again? No, because if the token has expired, he can just send a new request to the tokens server, sending his refresh token, and he'll get a new token to be used with your API.
I'm pretty sure that you already noticed that your API key is the "access token" equivalent, and your shared secret is the equivalent to the credentials used at the beginning of the OAuth process.
You can create your own mechanism, but you will need to take a lot of considerations that are already covered by OAuth. For example, Will you expire your API keys? After all, you should not trust a single key to be sent over every request for an undetermined amount of time. How will you handle the process to request new keys? Do you really want your users to send their secret every time they want a new key? Refresh tokens are useful for this.

Update/change roles claim (or any other claim) in JWT

I'm storing user roles inside a JWT (to restrict API endpoints). The roles can be changed by an administrator.
If a role is changed. How am I supposed to reflect this inside all tokens? I've thought about a couple of solutions:
If I'd use refresh tokens, the user would have to wait until the expiration date of the access token is expired.
I could keep a record of changed user IDs and check every request, and then return a new token if the user has been changed.
Is there a standard way to do this?
Refresh tokens don't seem to be the solution if you care about the changes you make being instant, you probably don't want an user to access moderation tools for some time if you revoke his permissions.
What you could do is keep a version number in the jwt token relative to the user, much like how mongoose does it with it's versionKey. By doing this, you would be able to check this version against the one in the database for a given user. Each time you change the roles of this user, you would increment this version, if the version of the jwt doesn't match, just recreate a new one with the correct roles and version and send it back to the user.
I don't believe there is a proper standard for this, as jwt is immutable by design, you'll have to change it entirely if you need to "update" it.
The JWT tokens are immutable so you can't change/update claims on an existing token - thus you have to issue a new JWT token.
That leads to the biggest problem with JWT - token revocation. There are no good solutions. What you can do is
Keep JWT expiration date short (and optionally use refresh tokens)
Use a blacklist to keep a list of revoked tokens (of course losing the 'stateless' part this way)
change the secret key (keep in mind that this revokes ALL valid tokens of all users)
The best solution depends on the concrete case.
To address that scenario, you can keep the token lifetime short, once the token expires you can renew the token silently in case of Implicit grant or use refresh token mechanism to issue a new token from the authorization server. Once the role has changed, it might not reflect in the token instantly, but it will be available once the token is renewed.
#Janar said three solutions to handle different scenarios, but they still exist corresponding drawbacks.
I also have a idea to revoke your token:
set iat to JWT payload. (You should know what is the iat)
revoke tokens of a user:
find the user id
let auth server rejects tokens which are before current time(judged by iat) and belong to this user(judged by userId)
A solution to this would be to keep authentication and authorization separate when using JWT tokens. Use the token for authentication(claiming an ID) and use that ID to check the authorization in the database. This can increase the latency of each request considering that you now have to check the authorization for each request. However, this can be mitigated by using an in-memory data structure store(such as Redis) as a cache. On every permission change, delete the cache and make another call for the permissions.

Encoding and Decoding API Access token with keys

I am planning to secure my rest API in django with a ACCESS_TOKEN.
When ever user is logged in using their username and password, once they are authenticated, I generate a ACCESS_TOKEN and passed to frontend be it Website or Native application. and then later used that ACCESS_TOKEN for further communication.
I am generating this token based on some user data and then encrypting this with public key. Later when application send this for in any request, I decrypt the ACCESS_TOKEN with private key and extract user data data and process the request. This is something similar to session where session data is in encrypted form in ACCESS_TOKEN and only private key and decrypt the ACCESS_TOKEN. This is what I am planning to do.
Please suggest me for following questions:-
1. Is is the best way to secure my REST API? I want to use my API in same way from Web-application(AJAX calling) and NATIVE application(Android/IOS etc) ?
2. What is the best way to expire the token? Do I need to keep track of access token at my end in order to expire them?
Also I do want to use the Oauth in my API.
Most people I see use JWT's that are signed but not encrypted so they store non-PI data like user_id or session_id. I guess you could encrypt it if needing to store personal information but I don't see any other reason. Assuming you are using HTTPS, then only the end client would have access to the information. Sounds like asking for trouble if the secret gets leaked so you would want a really good key rotation scheme since you may not even know its leaked until too late.
Many people using JWTs do so because they don't want a centralized auth server, thus the token is short lived like a few hours or days. If you need really tight control on expiring tokens, you can take a blacklist approach where a blacklist of JTI's (JWT Ids) are stored in a K/V to be checked against. https://www.moesif.com/blog/technical/restful-apis/Authorization-on-RESTful-APIs/

Security and reliability concerns about JSON Web Tokens (JWT)

I'm creating an API along with a SPA for a personal project and I'm hesitating between the following solutions to authenticate users (note: over HTTPS):
HTTP Basic Authentication (send username/password wich each request)
Token based authentication (store SHA1-ed user tokens in the database)
JSON Web Token (JWT) authentication
I don't even consider OAuth cause it seems like a real pain plus I don't need to authenticate with other apps, I'm only concerned about authenticating users.
From what I've read, JWT seems to be a growing standard. It basically holds the caller's data so everytime he makes an API request you encrypt(base64(header) + "." + base64(payload)) with your secret and you compare it with the signature provided in the last part of the token itself. It avoids having to perform DB transactions.
The problem is that if I use JWT 1) I have no possibility to manually revoke specific tokens, and most of all 2) if I change a user's permissions, the previously granted JWT will still have the old data with his old permissions which could grant/restrict him continuous access to some data as long as he doesn't get a new token with his new permissions, which is really problematic and I'm surprised I haven't seen anyone mentionning this problem yet. Moreover, 3) JWT claims to allow the server to validate access without having access to DB but I can't imagine any API request that doesn't involve the database somehow, if only to return data the user asked for. So this argument doesn't make any sense to me.
To me, my best option right now is option 2. Website will have restricted and small traffic so storing tokens in the Database seems like a small and worthwhile trade-off and allow me to do anything I want with these tokens, including managing their lifecycle and permissions. It also avoids exposing the users' credentials like in option 1, in case they use the same ones for other online services.
I just want to know if my concerns about JWT are right or if I misunderstood its functioning? Also, even if I've already read a lot about these different options, feel free to link anything that could enlight me and help me make a better choice. Thanks.
You are right and invalidating tokens before expiration time is a common JWT problem. There are several reason to consider: account deleted/blocked/suspended, password changed, permissions changed, user logged out by admin.
With JWT, you can also set a token blacklist to store tokens that were between logout & expiry time, mark expired and check it in every request. You can include only the ID (jti claim of JWT) or use the last login date and the iat claim (issued at)
Other technique to invalidate tokens when user changes their password/permissions is signing the token with a hash of those fields. If the field value changes, any previous tokens automatically fail to verify.
See https://stackoverflow.com/a/37520125/6371459
Finally, be aware that the token is signed with server private key (not encrypted)
sign(base64(header) + "." + base64(payload))