How do client systems “trust” an OIDC identity token (or an oAuth2 authorisation access token) in a SSO scenario? - authentication

First of all let’s clarify we are aware that OIDC and oAuth2 are different protocols, albeit OIDC builds on the flows and mechanisms defined by oAuth2, and they also use different tokens, a JWT Identity Token used for OIDC, and a resource access token (possibly also JWT formatted, but not required to) for oAuth2; the first deals with the issue of federated authentication and the second deals with the issue of federated resource access authorisation).
Having said that, for this specific question it is more or less irrelevant what type of token we do have, as here we are interested in understanding the mechanism through which a client system trusts the legitimacy of a token (please understand client system as defined by the oAuth2 flow definition of client system plus any extra system capable of accepting those same digitally signed tokens).
For the sake of simplifying the argumentation, let’s assume that we are following an auth code grant flow. In this flow after the end-user has been redirected toward the Id/auth server, provided his credentials successfully, and being redirected back to the original "issuer client"; we can be sure that this “issuer client” can trust this token because it was obtained through a backchannel http request which provided the access code plus a client secret unknown to anybody else, so for this "issuer-client" it is trivial to trust this token. Let’s call this the “trivial case”.
Now let’s assume we have more client systems capable of potentially accepting this previously generated token -as long as that token is valid of course- (this would indeed be a form of SSO, because those systems are basically “bypassing” their end user login, by virtue of trusting this token previously generated by ANOTHER client). The question I have is how can those other clients (which didn’t issue the token initially as described previously on the trivial case) trust the legitimacy of this token?.
One way to solve the point in the above’s paragraph, would be for clients when presented with a token, to “ask” the id/auth provider if it indeed generated the token; but in different documentation & blogs I’ve seen it seems it is often the case that client systems usually accept the token without talking back to the Id/auth provider. How does this happen that the token is on itself enough for establishing trust? It is mentioned that the digital signature ensures nobody changed the token, but how can those systems know the token wasn’t generated by other -potentially malign- Identity/auth server?. Let’s say that we have a 2nd Identity/authorisation server that issues tokens identical in structure to the ones of the 1st one; under this situation, how do clients know that a token comes from auth server 1 and not auth server 2? For the clients to discern with 100% certainty that a token not only wasn’t changed, but also that was generated by the authority the clients know and trust, it seems as if the tokens need to have as part of their digital signature some piece of information which is specific to the Id/auth server that generated it and can’t be replicated by any impostor (and the clients knows how to decode).
So that is the gist of my question, how can “non issuer-clients” (when presented with a token), know without speaking to the Id/auth provider, that the received token not only wasn’t changed (for this the signature), but also know from which Id/auth provider they come from, and also how is it prevented that a “fake Id/auth provider” could generate almost identical otherwise perfect tokens.
Thanks in advance for any feedback, and sorry for my limited english, it is a complex topic and probably the question isn't formulated in the best way.

The API's that receives the tokens usually queries the token providers /.well-known/openid-configuration endpoint to download the public signing keys.
then when the API receives an access token, it can use the public key from the provider that the API trusts, and verify that the access token is genuine and has not been modified.
Inside the token there is typically also an audience claim, that specifies who the intended target is for the token and also a claim describing who issued it.
So, there are many ways for a resource that receives an access token to verify that it is trustworthy.

Related

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 API gateway validates access token via introspection

I found one interesting article that has this illustration:
It says that:
API Gateway verifies access token for all incoming requests via introspection
But what does this mean?
it says that gateway goes to authorization server and validates token (JWT).
why is that needed?
if gateway has authorization server's public key, it can check token validity using signature just like every backend service, why is introspection needed and how is it done?
Depending on your Identity provider it can be done either way but there are trade offs.
If you validate the token locally then yes it can use public keys to do that and that's very efficient way, however downside is that if the token or signing keys are revoked then your token is still valid. With Remote check you have to bear the http overhead but that is more reliable.
Normally tokens are kept short lived and validated locally. But if your access token are long lived, your application require strict access controls or library doesn't support local validation then it's a good idea to check them remotely
I believe you are looking at this document.
What I understood from this Secure API Gateway is that the gateway is responsible for introspection and the back-end services will only check the token signature, which is less secure than introspection, but still a layer of security.
Introspection is necessary to validate the token information against the Authorization Server.
This is more secure, because the system can ensure that the token received is not malicious, expired and it is from an known source.
The details on how it is done are explained in RFC 7662.
Yes, the gateway could validate the token signature if it has access to the certificate.
I can't really tell why they choose the back-end server to do it, probably a project decision.
API Gateway primarily meant for routing the incoming calls to the corresponding MicroService Clusters.
In addition to that,it can also play a role to validate the token, so that only valid traffic is routed to the downstream servers (filtering malicious traffic).
The level of validation could be up to the product owner/architect decision. It could be as simple as validating against the list of in memory cached token or in depth validation on set of claims, digital signature verification, expiry time, audience claim etc.
You can view the set of claims inside the token using JWT decoder like https://devtoolzone.com/decoder/jwt

Using OAuth to control access for untrusted 3rd party services to our API

I need to secure access to an API that will be consumed by untrusted 3rd party service. My current investigations have lead me to using grant_type=“client_credentials” passing in the clientId and client secret I've setup for the 3rd party within my idenity server. However this flow seems to be only for Machine to Machine (MTM) connections where the client is trusted.
I can understand why: If I use this flow, with HS256, then I can see an obvious security flaw: the JWT is signed using a shared symmetric key. This means there is nothing stopping the 3rd party generating and signing their own JWT tokens using this key and circumventing the authentication server entirely. If I use RS256 however, this flaw doesn’t exist as the untrusted party only has access to the public key, so they can’t create their own signed JWTs.
[EDIT]: I now know that you shouldn't validate tokens at the client as there is no need, and this means they don't need the key, so this 'flaw' is moot.
My main question is: Is this the correct way to go for my use case, or is there a different OAuth flow I should be using here? Everything I've read suggests that client_credentials grant type should only be used when the client is the resource owner and is trusted, and this is not my scenario - however they then state you must use Implicit or Authorisation code - which both require user involvement and are also not valid for my use case.
So I assume that you do not want the client to manually put in any password or secret when connecting/authenticating with your service. If that's the case, then keep reading, otherwise I have misunderstood your question completely.
One thing is that your client secret, will always be at risk of being compromised. There is nothing you can do about that - it's like your user's password being compromised. It's their fault.
There are things you can do to make it more secure (though this would add some level of inconvenience to the usage of your API - but you can always add an SDK for the 3rd party to use). But first, when you say untrusted, it can mean two things:
non-malicious and untrusted (NMU): the third party will knowingly not do anything "bad" with their access to your service. Most consumers would be here.
malicious and untrusted (MU): the third party may do something "bad". You do not know. And if this happens, it is entirely their fault and they are to blame. Not you.
Either way, you can simply make it so that they keep using your provided secret for each API request. This is the simplest approach - but of course, increases the chances of this secret being stolen.
If you want to take it one level further, then you can use this secret to issue a long lived access token to this client. If using JWT, then the signing key can be symmetric and kept to you - since they do not need to verify the token on their side. They simply use it in each request. This has problems such has how would you or they know if this access token is stolen? Plus using long lived JWT is a bad idea in general, so I would use non-jwt tokens for this if I were you.
If you want to take it a level higher (most secure): The service authenticates itself with the secret you provided to them. Then you could issue a short lived access token and a long lived refresh token to them. They would use this access token for all normal API calls to authenticate, and when it expires, they hit a special API endpoint with the refresh token to get a new access token. Furthermore, you could change the refresh token each time they hit the refresh API - this will also allow you and them to detect token theft! (See this). If you decide this approach, then you also have to take care of a few race conditions and network failure issues as mentioned in this blog. Plus, you could also go about changing the JWT signing key, since you have a refresh token to fallback on! But this would give you the most secure solution for your problem.
Note that is the third party service is likely to be of type MU, then there is nothing you can do to secure your service for them - depending on what your service does, their data and "account" would be affected..
I hope this answer helps you! Feel free to message me on Discord to chat more about this. I can be found on this server with the username rp#5569.

What is the difference between OAuth based and Token based authentication?

I thought that OAuth is basically a token based authentication specification but most of the time frameworks act as if there is a difference between them. For example, as shown in the picture below Jhipster asks whether to use an OAuth based or a token based authentication.
Aren't these the same thing ? What exactly is the difference since both includes tokens in their implementations ?
This is a good question -- there is a lot of confusion around tokens and OAuth.
First up, when you mention OAuth, you are likely referring to the OAuth2 standard. This is the latest version of the OAuth protocol, and is what most people are specifically talking about when they say 'OAuth'.
The OAuth protocol supports several different types of authentication and authorization (4 to be precise).
Secondly, the OAuth protocol works by authenticating users via tokens. The idea here is this:
Instead of having your user send their actual credentials to your server on every single request (like they would with Basic Auth, where a user sends their username/password to the server for each request), with OAuth you first exchange your user credentials for a 'token', and then authenticate users based on this 'token'.
The idea of OAuth is that by requiring users to pass their confidential credentials over the network less frequently, less bad things can happen. (This is the idea, anyhow.)
Now, here's where tokens come into play: the OAuth spec is built around the concept of tokens, but DOES NOT SPECIFY WHAT A TOKEN IS.
In the most 'general' sense, a token is just a string that uniquely identifies a user. That's it.
People realized this, and developed a new standard for creating tokens, called the JSON Web Token standard. This standard basically provides a set of rules for creating tokens in a very specific way, which makes tokens more useful for you in general.
JWTs let you do things like:
Cryptographically sign a token so you know that a token wasn't tampered with by a user.
Encrypt tokens so the contents cannot be read in plain text.
Embed JSON data INSIDE of a token string in a standard way.
Now, for the most part: pretty much everyone in the development community has agreed that if you're using any sort of OAuth, then the tokens you're using should be JSON Web Tokens.
OK! Now that we've covered the backstory, let me answer your question.
The choice you're making above is whether or not you want to enable the full OAuth2 specification for authentication / authorization (which is quite complex), or whether you simply want some basic 'token authentication'.
Because the OAuth protocol provides multiple different ways to authenticate in a STANDARDS COMPLIANT way, it adds a lot of complexity to most authentication systems.
Because of this, a lot of frameworks offer a 'dumbed down' version of the OAuth2 Password Grant flow, which essentially is a simple method where:
A user sends their username/password to your server at some URL like /login.
Your server generates a JWT token for the user.
Your server returns that token to the user.
The user stores this token in their cookies, mobile device, or possible API server, where they use it to make requests.
Again: the flow above is NOT OAuth compliant, but is a slightly simpler version that STILL uses tokens.
The main point here is that tokens (JWTs) are generally useful, and don't NEED to be paired with the OAuth flow.
I realize this is a wall of text, but hopefully it answers your question in more depth =)
OAuth is a specification for authorization not authentication
OAuth 2.0 is a specification for authorization, but NOT for authentication. RFC 6749, 3.1. Authorization Endpoint explicitly says as follows:
The authorization endpoint is used to interact with the resource owner
and obtain an authorization grant. The authorization server MUST first
verify the identity of the resource owner. The way in which the
authorization server authenticates the resource owner (e.g., username
and password login, session cookies) is beyond the scope of this
specification.
Only use OAuth if you want to give access to a third party service to your apis. Even when you are using OAuth you would need some kind of authentication (token based or session based etc) to authenticate the uses. OAuth is not designed for authentication.
see this question.
When you are requesting resource from a secured web service, you can provide an authentication token on the call. The token acts as "secret code" for accessing the resource.
OAuth is just specific type of token based authentication method.

What if JWT is stolen?

I am trying to implement stateless authentication with JWT for my RESTful APIs.
AFAIK, JWT is basically an encrypted string passed as HTTP headers during a REST call.
But what if there's an eavesdropper who see the request and steals the token? Then he will be able to fake request with my identity?
Actually, this concern applies to all token-based authentication.
How to prevent that? A secure channel like HTTPS?
I'm the author of a node library that handles authentication in quite some depth, express-stormpath, so I'll chime in with some information here.
First off, JWTs are typically NOT encrypted. While there is a way to encrypt JWTs (see: JWEs), this is not very common in practice for many reasons.
Next up, any form of authentication (using JWTs or not), is subject to MitM attacks (man-in-the-middle) attacks. These attacks happen when an attacker can VIEW YOUR NETWORK traffic as you make requests over the internet. This is what your ISP can see, the NSA, etc.
This is what SSL helps prevent against: by encrypting your NETWORK traffic from your computer -> some server when authenticating, a third party who is monitoring your network traffic can NOT see your tokens, passwords, or anything like that unless they're somehow able to get a copy of the server's private SSL key (unlikely). This is the reason SSL is MANDATORY for all forms of authentication.
Let's say, however, that someone is able to exploit your SSL and is able to view your token: the answer to your question is that YES, the attacker will be able to use that token to impersonate you and make requests to your server.
Now, this is where protocols come in.
JWTs are just one standard for an authentication token. They can be used for pretty much anything. The reason JWTs are sort of cool is that you can embed extra information in them, and you can validate that nobody has messed with it (signing).
HOWEVER, JWTs themselves have nothing to do with 'security'. For all intents and purposes, JWTs are more or less the same thing as API keys: just random strings that you use to authenticate against some server somewhere.
What makes your question more interesting is the protocol being used (most likely OAuth2).
The way OAuth2 works is that it was designed to give clients TEMPORARY tokens (like JWTs!) for authentication for a SHORT PERIOD OF TIME ONLY!
The idea is that if your token gets stolen, the attacker can only use it for a short period of time.
With OAuth2, you have to re-authenticate yourself with the server every so often by supplying your username/password OR API credentials and then getting a token back in exchange.
Because this process happens every now and then, your tokens will frequently change, making it harder for attackers to constantly impersonate you without going through great trouble.
Hopefully this helps ^^
I know this is an old question but I think I can drop my $0.50 here, probably someone can improve or provide an argument to totally decline my approach.
I'm using JWTs in a RESTful API over HTTPS (ofc).
For this to work, you should always issue short-lived tokens (depends on most cases, in my app I'm actually setting the exp claim to 30 minutes, and ttl to 3 days, so you can refresh this token as long as its ttl is still valid and the token has not been blacklisted)
For the authentication service, in order to invalidate tokens, I like to use an in-memory cache layer (redis in my case) as a JWT blacklist/ban-list in front, depending on some criterias:
(I know it breaks the RESTful philosophy, but the stored documents are really short-lived, as I blacklist for their remaining time-to-live -ttl claim-)
Note: blacklisted tokens can't be automatically refreshed
If user.password or user.email has been updated (requires password confirmation), auth service returns a refreshed token and invalidates (blacklist) previous one(s), so if your client detects that user's identity has been compromised somehow, you can ask that user to change its password.
If you don't want to use the blacklist for it, you can (but I don't encourage you to) validate the iat (issued at) claim against user.updated_at field (if jwt.iat < user.updated_at then JWT is not valid).
User deliberately logged out.
Finally you validate the token normally as everybody does.
Note 2: instead of using the token itself (which is really long) as the cache's key, I suggest generating and using a UUID token for the jti claim. Which is good and I think (not sure since it just came up in my mind) you can use this same UUID as the CSRF token as well, by returning a secure / non-http-only cookie with it and properly implementing the X-XSRF-TOKEN header using js. This way you avoid the computing work of creating yet another token for CSRF checks.
Sorry being a little late on this, but had the similar concerns and now want to contribute something on the same.
1) rdegges added an excellent point, that JWT has nothing to do with the "security" and simply validates, if anyone has messed up with the payload or not(signing); ssl helps to prevent against breaches.
2) Now, if ssl is also somehow compromised, any eavesdropper can steal our bearer token (JWT) and impersonate the genuine user, a next level step what can be done is, to seek the "proof of possession" of JWT from the client.
3) Now, with this approach, presenter of the JWT possess a particular Proof-Of-Possession(POP) key, which the recipient can cryptographically confirm whether the request is from the same authentic user or not.
I referred Proof of Possesion article for this and am convinced with the apporach.
I will be delighted, if able to contribute anything.
Cheers (y)
To deal with the problem that tokens are getting stolen, you map each JWT with the list of valid IPs.
For eg, when the user logs in with a particular IP when you can add that IP as valid IP for that JWT, and when you get the request pf this JWT from another IP (either the user changed the internet or JWT is stolen, or any reason) you can do the following depending on you use case:
Map CSRF token with user token and incase it gets stolen then it's CSRF token will not match in that you can invalidate that user token.
You can provide a captcha to the user to validate if he is a valid user or not. If he enters the captcha then add that IP to the valid list of that JWT.
You can log out the user and make a new request to log in again.
You can alert the user that your IP has changed or requested from a different location.
You can also use cache with a small expiry of 5 mins in above use-cases instead of checking each and every time.
Suggest if it can be improved.
Can't we just add the ip of the initial host which has requested to generate this JWT token as part of the claim ? Now when the JWT is stolen and used from a different machine, when the server validates this token, we could verify if the requested machine ip matches with the one set as part of the claim. This would not match and hence the token can be rejected. Also if the user tries manipulate the token by setting his own ip to the token, the token would be rejected as the token is altered.
Once the token gets stolen - it is game over.
However there is a way to make it harder to make use of a stolen token.
Check https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html#token-sidejacking for reference.
Basically, you create a x-Byte long fingerprint in hexadezimal, store its raw value in the token - hash the fingerprint using for example SHA-512 and put the hashed fingerprint inside a httponly secure cookie.
Now instead of validating just the signature and expired date of the token you need to also validate the existence of the cookie and be sure that the raw fingerprint values match.
Client should use part of the hash of user password to encrypt the time that the http msg was sent by client to the server. This part of the hash should also be encrypted with some server secret key into the token when it is created.
The server than can decrypt the http request time and verify for short time delay.
The token is going to change every request.