SpringCloud Microservices JSON Web Token (JWT) Security - spring-security

I have a multiple microservices architecture in which I intend to apply security.
My View of the Security Design:
The authentication will happen with an LDAP and when the user is authenticated a JSON Web Token (JWT) will get generated using a "secret key" and the token will have the roles, expiration time etc. With every call to a microservice this token will be passed in Header for authorization. In my view I just have one single auth server which authenticates the user and generates the JWT.
My Doubt:
Now, when a microservice will receive a call (containing the JWT in Header) will it always hit the auth server to get the token verified?
If yes, won't it lead to multiple calls to auth server and thus a bad practice?
If no, how will the client verify the token and what is the scope of the auth server?

JWTs are always signed, so that you can verify a given token without doing a call to some central auth instance. The auth server knows the secret to sign the token and all services that want to validate the token also need have a way to check this.
There are two different approaches to signing:
symmetric: A secret value is appended before hashing the payload. The consuming service also needs to know this secret and can verify by appending the secret to the payload received and checking the resulting hash with the transmitted hash.
asymmetric: By using some PKI signing/verification it is possible that only the auth server has the private key to sign the token. All consuming services then only need the public part to verify.
I prefer the second way, cause it reduces the chance of a key getting stolen. If one of the consuming services is hijacked, there is no secret lost such that the attacker can create valid tokens. Using such an algorithm could possibly take some more time / cpu cycles for validating than a simple hash used in the symmetric way.
Please see the official JWT page for an example of the different mechanisms: https://jwt.io/

Related

How do you guarantee safety when validating Keycloak (OIDC) tokens without making requests to the Keycloak API?

There is a lot of information on OAuth, OIDC and Keycloak, but the main thing every tutorial seems to gloss over is offline validation. The only information I found is in the Keycloak docs on RPT introspection:
No. Just like a regular access token issued by a Keycloak server, RPTs also use the JSON web token (JWT) specification as the default format. If you want to validate these tokens without a call to the remote introspection endpoint, you can decode the RPT and query for its validity locally. Once you decode the token, you can also use the permissions within the token to enforce authorization decisions.
If I wanted to verify a user's request with an authorization token, I would make a request to the Keycloak introspection (or userinfo?) API. I'm not completely sure, but I would guess that Keycloak then verifies the info encoded in the JWT with the Keycloak user database.
However, what if I don't want to make a Keycloak request on every API request? This could improve system performance by limiting the amount of HTTP requests. There are mentions of JWT signature validations and reading the scope and user information encoded in the JWT, but I don't see how this guarantees safety. Isn't it possible to just generate any old JWT, encode any information you want and basically spoof an authorization token? How would I check if the user mentioned in the JWT really exists in the Keycloak database?
I think I am missing some crucial part of this technology.
For example, in ASP.NET Core, an API that receives a JWT token will, at startup, download the public signing keys from the token provider, and by default, it will refresh the keys every 24 hours.
So, when the API receives a JWT token, it will do various checks to validate the token, including:
Validating the signature using the provider public signing key
Validate the audience claim (is the token intended for me?)
Validate the expiry date
The API should not need to query anything against the token provider (keycloak) to let the user in.
However, then we have authorization (What the user is allowed to do), which is a different thing, and that all depends on your requirements.
JWT is all about who the user is; if the token is valid, you can trust that information.
With JWT-tokens, your API can work almost offline from the token provider. It can even be 100% disconnected if you copy the public signing key manually into the API.

Why does machine-to-machine interaction in OAuth2 disallow the refresh_token grant without providing the client_secret?

We are implementing JWT-based authentication for our APIs, using Keycloak as an identity provider and token endpoint.
We found the idea of OAuth2 attractive, as it reduces the need for long-lived credentials to travel over the network. Instead of issuing our end-users an API key which they would put into a header for every request they send our way, they can use a client ID and secret to request an access token with a relatively short lifespan.
I mistakenly assumed that the clients would also receive a refresh token and be able to get new access/refresh token pairs using that (and not using the client secret). This would further lessen the need for the client secret to go back and forth over the network.
Here's some background for my initial reasoning:
Client gets access/refresh tokens with client credentials
Client uses access token until expiry
Client uses refresh token to obtain a new access/refresh pair.
The old refresh token is invalidated (this is possible to do with Keycloak by tweaking max sessions).
Retrieving an access/refresh pair with static credentials similarly invalidates a refresh token.
In this case an attacker sniffing network traffic would be very lucky to ever see static credentials passed and the compromise of credentials (whether static or refresh) is very visible, since the legitimate client would notice that its refresh token no longer works.
However, from what I gathered in the standards, the generally accepted way for machine-to-machine interaction to happen under OAuth2 is with the client credential grant type, which does not return refresh tokens and the client must request a new access token with its credentials every 10-15 minutes or so.
This leaves me confused: is this not, basically, another convoluted type of basic auth then, where we repeatedly send static credentials over a potentially insecure network? Sure, most requests are done with an access token, but an attacker will know for sure that every 10-15 minutes the static credentials will be sent to the authorization server.
Is there another way to do machine-to-machine interaction which is better secured against an attacker, who has managed to sniff our traffic? To be more specific, something which avoids, or mostly avoids sending static credentials.
Regarding your question about another way to do machine-to-machine interaction which is better secured against an attacker, who has managed to sniff our traffic, there are alternative authentication methods that a client can use.
The default client auth method is based on a shared key, called client secret in OAuth 2.0 spec. Client id and secret must be sent to the auth server to obtain an access token. This has to happen every time previously issued access token expires. This increases the risk of client secret exposure. This method does not require a refresh token as the client is obtaining a token for itself. This method is performed over SSL which reduces the risk of exposure. In addition, active IP monitoring further reduces the risk of compromised client secret. Client secret can be invalidated if a request is issued from an IP that has not been seen.
However, a more secure alternative to a shared client key is a private key and a signed JWT authentication. A client uses a private key and signs a set of assertions in a JWT token. This JWT is sent with the token request. The JWT is extremely short lived with expiry set to a few seconds from the issue. The auth server is configured with a corresponding public key and is able to validate JWT signature this authenticating the client's request. This JWT is a single use token and should include a unique token id. Auth server can persist unique JWT id until expiry to prevent token replay.
In addition to a short lived JWT, client IP monitoring can be implemented so that the client is only allowed to use this key from an established set of IP addresses or from previously observed set of IP addresses.
OAuth 2.0 also provides for a client to authenticate via a X.509 certificate submitted to the auth server during TLS handshake.
https://datatracker.ietf.org/doc/html/rfc8705

OAuth redirect flow server to server token generation for client

I have a rest API service that enables API calls for some resources.
The API calls can be done from an API server using a secret, or from a web client using a bearer token.
In order to get to the web client flow, a URL must be generated by the API server call:
https://www.someapi.com/somelink
The response will be a link with a token I call "action token". This token is passed with the link, for example:
https://www.somepage.com/?action_token=somejwttoken
By entering the link, the action token will be exchanged with an access token, that enables a client to access some pre-defined resources.
I wonder if there is a best practice for such flow.
ONE TIME TOKENS
If using tokens in URLs you should also ensure that:
The token has a one time use
The token is short lived
The token is not guessable - eg make it a UUID
The final access token returned has limited privileges and also a short lifetime
The one time action token may then be available in the browser history or server logs, so be aware of that. Make the actual swap for the proper token a JSON to JSON POST operation, after the page has loaded.
Typically each action token issued would also be stored by the API in a database along with its expiry time, then used to verify links later.
This type of URL solution is sometimes used in operations such as verify email or to enable magic links, where users can quickly access limited data.
OAUTH FLOWS
One time tokens should not be overused and they are of course no substitute for signing the user in properly via OpenID Connect standards, then running an authenticated user session.
SCOPES AND API TO API FLOWS
A more secure option may be to forward JWTs from the original client to downstream APIs, as described in Scopes Best Practices. This enables user context to flow securely and also simplifies code. This may eliminate or reduce the need for any token exchange operations.

Do OpenID Connect id_token and access_token need to be validated if they are obtained by web server?

I am wondering that in the OpenID Connect Auth Code Flow, whether there is still a need to validate the access_token and id_token given they are obtained by my web server rather than by browser (i.e. using back channel rather than front channel)?
By "auth code flow" I am referring to the flow where browser only receives an "authorization code" from the authorization server (i.e. no access_token, no id_token), and sends the auth code to my web server. My web server can therefore directly talk to the authorization server, presenting the auth code, and exchange it for the access_token and id_token. It looks like I can simply decode the access_token and id_token to get the information I want (mainly just user id etc.)
My understanding of the need for validating the access_token is that because access_token is not encrypted, and if it is transmitted through an insecure channel, there is a chance that my web server can get a forged token. Validating the token is basically to verify that the token has not been modified.
But what if the access_token is not transmitted on any insecure channel? In the auth code flow, web server directly retrieves the access_token from the auth server, and the token will never be sent to a browser. Do I still need to validate the token? What are the potential risks if I skip the validation in such flows?
You should always validate the tokens and apply the well known validation patterns for tokens. Because otherwise you open up your architecture for various vulnerabilities. For example you have the man-in-the-middle issue, if the hacker is intercepting your "private" communication with the token service.
Also most libraries will do the validation automatically for you, so the validation is not a problem.
When you develop identity systems you should follow best practices and the various best current practices, because that is what the users of the system expects from you.
As a client, you use HTTPS to get the public key from the IdentityServer, so you know what you got it from the right server. To add additional security layers, you could also use client side HTTPS certificates, so that the IdentityServer only issues tokens to clients that authenticates using a certificate.
In this way, man-in-the-middle is pretty impossible. However, in data-centers in the backend, you sometimes don't use HTTPS everywhere internally. Often TLS is terminated in a proxy, you can read more about that here
When you receive an ID-token, you typically create the user session from that. And yes, as the token is sent over the more secure back channel, you could be pretty secure with that. But still many attacks today occurs on the inside, and just to do a good job according to all best practices, you should validate them, both the signature and also the claims inside the token (expire, issuer, audience...).
For the access token, it is important that the API that receives it do validate it according to all best practices, because anyone can send requests with tokens to it.
Also, its fun to learn :-)
ps, this video is a good starting point

Why do you need authorization grant when you can just give the token out directly?

Watching this video, it details in OAuth2 that the client application first has to get the authorization grant from the Authorization server and then use that grant to get a token before being able to access the resource server. What purpose does the grant serve? Why not give the client the token right away after the user signs on with his/her username and password?
Because it is more secure, for some application types.
What you describe is so called authorization-code-flow. It is normally used for "classical" web applications, where only the backend needs to access resource server. The exchange of authorization code to access token happens on the backend and access token never leaves it. Exchange can be done only once and in addition client id and secret (stored on the backend) are necessary.
Single-Page-Applications often use implicit-flow where access token is delivered to the frontend directly in the URL.
See more here:
IdentityServer Flows
EDIT: Q: "I still don't see how it is more secure given that you have to have the grant in order to get the token. Why need 2 things instead of just 1 thing to access the resource? If someone steals the token, they can access the resource anyway – stackjlei"
"Stealing" access token will work independent on how your application acquires it. However, stealing access token on the backend is much more difficult than on the frontend.
Authorization code is delivered to the backend also over the frontend but the risk that someone intercepts and uses it is tiny:
It can be exchanged only once.
You need client-id and client-secret in order to exchange it. Client-secret is only available on the backend.
Normally, authorization code will be exchanged by your backend to access-token immediately. So the lifetime of it is just several seconds. It does not matter if someone gets hold of used authorization code afterwards.
In your scenario there could be two servers, an Authorization and a Resource one.
It could be only one as well, but let's imagine this scenario.
The purpose of the Authorization Server is to issue short lived access tokens to known clients. The clients identify themselves via their CLientID and CLientSecret.
The Authorization Server ( AS ) holds the list of clients and their secrets and first checks to make sure the passed values match its list. If they do, it issues a short lived token.
Then the client can talk to the Resource Server ( RS ), while the token is valid. Once the token expires, a new one can be requested or the expired one can be refreshed if that is allowed by the Authorization Server.
The whole point here is security, Normally, the access tokens are passed in the Authorization header of the request and that request needs to be over https to make sure that the data can't be stolen. If, somehow, someone gets hold of an access token, they can only use it until it expires, hence why the short life of the tokens is actually very important. That's why you don't issue one token which never expires.
You have different type of OAuth. On type doesn't require to use the 'grant' authorization. It depend who are the user/application, the ressource owner and the server API.
This way, you - as a user - don't send the password to the application. The application will only use the grant token to gain access to your ressources.
I think this tuto is a pretty good thing if you want more details
https://www.digitalocean.com/community/tutorials/an-introduction-to-oauth-2

Resources