I’m using below java library to validate the JWT token. Creating the Bean to cache the Public key. but I realized (based on Time taken to validate JWT token) that the public key will be cached only when we call the decode function from the AccessTokenVerifier class. this is expensive since we are running the springboot application in multiple pods and this decode method can be called only once we have the token.
which means if we have our application running in ‘n’ pods, for n number of business api calls OKTA internally call the public key endpoint to cache the public key.
Is there any way while the application starting time itself we can cache the public key ?
If you know your authZ server, you can manually request the key from it (please see the okta guide, as it's published in authZ server metadata. Then you can use that key however you want. Not sure if your JWT verification library allows to provide the key manually during its initialization
Related
please take this doubt away.
I have a Spring Boot application with spring security using JWT.
One question I always had is: How does Spring store the generated tokens?
Looking at the manager of my tomcat, I saw that this application has some open sessions, but it works exclusively with JWT. There is no point in it where I request to open a session.
So can I assume that Spring creates sessions to store the generated tokens?
you authenticate and then get issued a token from an issuer.
When this token is presented to a spring server, the resource server needs to do multiple validations before it will let you use the api.
A JWT is not encrypted, it is encoded, which means, everyone can see and read its contents. But it is also signed, so that you can not tamper with its contents without breaking the signage.
So the first thing a server does is to verify the signature to be sure it hasn't been temepered with. This can be done in multiple ways, one is to take the token and send it to the issuer and basically ask "hello is this token valid?" and the issuer says "YAY" or "NEY".
This generates a lot of extra network traffic if it needs to send jwts back and fourth for validation.
Since the signage of tokens are done with asymmetric encryption, the resource server can periodically (for instance each 30 mins) ask the issuer for the public key so it can verify the tokens itself without constantly needing to ask if they are valid or not.
This key is usually sent in a format called JWK (Json web key) and this key is then used to validate the integrity. If this validation passes it can trust the jwts content, and start checking the validation date, the scopes, and any extra claims in it etc.
And then if the token is valid has not expired, you can for instance choose to construct a UserDetails object from the data in the jwt.
As mentioned in the comments. If using JWTs you have no need for a session.
you should disable session creation.
You can read a lot more about sessions in this article here Spring Security Session
And here you can read about spring security Session Managment
Im looking to create an angular application which login against a new authentication server created in springboot and return a jwt.
The idea is to create the application to be able to generate and sign the jwt token with a private key based on the user/password provided in the screen, the authentication server will validate the login information in database and generate the jwt token.
After that, a request will be sent to another microservice and in here I need to be able to validate the token, but this microservice wont be connected to the authentication service or database in any way, it will just validate the integrity of the token using a public key.
Im looking everywhere and I dont find the clue to be able to validate the token, I found this piece of code but for some reason when I execute the rest API exposed this code is not executed:
#Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
Resource resource = new ClassPathResource("public.txt");
String publicKey = null;
try {
publicKey = IOUtils.toString(resource.getInputStream(), Charset.defaultCharset());
} catch (final IOException e) {
throw new RuntimeException(e);
}
converter.setVerifierKey(publicKey);
return converter;
}
Does what im trying to do makes any sense?
Thanks
Regards
Your auth server will will need to be the single issuer of JWTs to your microservices. So, when a user logs in and successfully authenticates, your auth server will issue a JWT signed with a private key (signing MUST be asymmetric - RS256 is one example) you keep on the auth server only; do not give this private key to other microservices that you wish to validate JWTs inside of. What you can do is derive a public key based on the private key you sign your tokens with and publish that to an endpoint on your auth server that requires no authentication - the public key will be represented in the form of a JWK (see link to spec). Google does something similar here. Then, in each of your microservices, you will need to devise a way to make a GET request to the public key endpoint on your auth server every X minutes and cache the public key in each microservice.
Then whenever a request comes into one of your microservices, you grab the JWT, check its validity, and grant access/authorization if the token is valid. The beauty of using a private/public key pair and asymmetric key signing is that you can validate a token based on the public key alone, but not sign it. So as long as each service has the public key from your /cert endpoint, they can validate a token without ever needing to talk to the auth server or knowing the private key.
This will require a little more work up front, but will yield you massive amount of ease, flexibility, and peace of mind in the future knowing only one source knows your private key.
I suggest using this library to do JWT validation.
The overall architecture will end up looking something like this:
I have an Authentication service built on Identity Server 3. I recently switched it from JWTs to reference tokens and implemented SignOutAsync in my UserService to revoke the tokens when the user signs out. The code looks like this:
public override Task SignOutAsync(SignOutContext context)
{
string subjectId = GetSubjectId(context);
_tokenHandleStore.RevokeAsync(subjectId, context.ClientId);
return Task.FromResult(0);
}
And that code appears to work. (The ITokenHandleStore interface and RevokeAsync method were recommended in this post.)
If I copy the reference token, I can use it to access my services up until the user signs out. Then the reference token no longer works. Just as I'd expect.
Then I introduced persistent storage of the reference tokens using Identity Server's built-in Entity Framework implementation for operational data. The tokens are written to and purged from the data store as I expect, but they no longer appear to be revoked when the user signs out. I can copy the reference token and use it to access the services, even after the user has signed out.
I've stepped through the code so I know my SignOutAsync method is being called and _tokenHandleStore.RevokeAsync is being called.
Is ITokenHandleStore.RevokeAsync the right method to call? What should I see in the database Tokens table when a token is revoked? Will it be deleted or modified? I am seeing no change to the token data in the data store. The persistent storage and revocation are both built-in features of Identity Server, but do they know about each other? Does the built-in implementation of ITokenHandleStore detect the use of persistent storage and revoke those tokens? Or do I need to extend that method in some way or call a custom method?
I am trying to get a custom web application to work with Azure B2C OAuth and the Spring OAuth2.0 framework.
The authentication leg comes back fine and I receive a JWT token. When the request for a token occurs afterwards I get the following error:
java.lang.IllegalStateException: Access token provider returned a null access token, which is illegal according to the contract.
at org.springframework.security.oauth2.client.OAuth2RestTemplate.acquireAccessToken(OAuth2RestTemplate.java:223) ~[spring-security-oauth2-2.0.8.RELEASE.jar:na]
at org.springframework.security.oauth2.client.OAuth2RestTemplate.getAccessToken(OAuth2RestTemplate.java:173) ~[spring-security-oauth2-2.0.8.RELEASE.jar:na]
...
From some debugging of the spring code I can see the token is expected to be called access_token as seen in the OAuth2AccessToken class. From looking at the B2C tutorials their token is called token_id. Furthermore the applications.yml config I have for my spring application has a field called tokenName. Surely this should be used to pick up the token name field instead of the hardcoded static variable as above.
Am I missing something and is there a solution to my problem. Can I override the token name field used by the spring OAuth framework?
I'm going to go ahead and post this as the answer.
I started with the Spring tutorial, and made some modifications to it. For a working example, see the public github repo: https://github.com/Pytry/azure-b2c-oauth2.git
To properly parse the token received you will need:
A custom implementation of an AccessToken that will parse the JWT, pulling and setting variables as required by spring security. I extended DefaultOAuth2AccessToken and added this parsing to a private method called by the constructor.
If you are going to verify the RSA signature using the public keys, you will need a custom JWT object so you can access the header information. I chose to extend springs JWT, and add some parsing on creation to access the header. It may also be useful to have some custom Pojos for parsing the returned meta data and rsakey information into.
An extension of the JwtAccessTokenConverter, with an overridden "decode" method. Azure does not give a "user_name" nor a "client_id" in the returned id_token, so you need to add those. I also included some logic in the super class that I found suefull (such as converting strings to int/long when appropriate).
A custom UserDetailsManger to override the default in memory one. This can either retrioeve user information from the GraphAPI, or it can load it from your user repository. I actually did not create either of these, and instead used the default in memory service, but injected it into the token converter; then whenever a user was properly authenticated, I would add them to the managers store, or update them if they already existed.
There are a few things I have not done yet.
RSA verification is not being done. Any help on this is appreciated.
According to this and this there are two ways to validate the JWT token:
Using RemoteTokenServices which basically calls /check_token endpoint of oauth server, retrieves the whole token and compares it
Expose public key at oauth server and verify the JWT's signature at resource server
At the beginning I tried the first way but since I use custom token converter which hits the database every time token being generated, I decided to switch to signature verification at resource side - didn't want to get an additional database call per every client request.
After some investigation I realized that ResourceServerTokenServices (interface describes token retrieval, conversion and generation a valid OAuth2Authentication object) has only two default implementations: DefaultTokenServices which is primary used in case of oauth and resource servers are parts of the same application and RemoteTokenServices which was described in first approach.
So the main question is whether spring-oauth2 really hasn't default implementation of JWT signature verification or I just couldn't find one?
You do not need a JWT specific ResourceServerTokenServices, so the DefaultTokenServices should do fine. Most of the implementation specific details are sent to the store, so as long as you have a JwtTokenStore configured correctly there should be no issue.
Here :
The Resource Server also needs to be able to decode the tokens so the JwtTokenStore has a dependency on a JwtAccessTokenConverter, and the same implementation is needed by both the Authorization Server and the Resource Server. The tokens are signed by default, and the Resource Server also has to be able to verify the signature, so it either needs the same symmetric (signing) key as the Authorization Server (shared secret, or symmetric key), or it needs the public key (verifier key) that matches the private key (signing key) in the Authorization Server (public-private or asymmetric key). The public key (if available) is exposed by the Authorization Server on the /oauth/token_key endpoint
You can extend JwtAccessTokenConverter to access once the Authorization Server for the exposed public key.