JWT Testing Server
Creating a testing environment is useful to perform
Performance & Load Tests
Security Tests
Other User Acceptance tests
...
By using OAuth2/OIDC you have an additional external component in place that is required to run your clients and server applications.
To support testing environments without having external dependencies you have several possibilities:
Spring Integration Tests for JWT (see last lab)
Test using your own self-signed JWT tokens
Test using the TestContainers library using a dockerized Keycloak instance
Option 3 is a bit out of focus of this workshop, so we will go for option 2 as part of this workshop.
Lab Contents
The Keycloak identity provider is not required anymore for this lab.
Learning Targets
In this fourth lab you will see how you can configure the resource server from Lab 1 with a custom static private/public key pair and create an application to generate your own JWT tokens using the corresponding self-signing private key.
This is quite helpful in testing environments, e.g. doing load/performance testing and preventing from load testing the identity server as well.
This lab is actually split into three steps:
Look into a resource server with static public key to verify JWT tokens
Generate custom JWT tokens for different user identities to be used at the resource server of step 1
Make requests to the resource server of step 1 with generated JWT from step 2
Folder Contents
In the lab 5 folder you find 3 applications:
library-server-static-complete: This application is the complete static resource server
jwt-generator: This application is the JWT generator to generate custom JWT tokens
Start the Lab
In this lab you will not really implement anything yourself, but you will see how to use such static resource server with custom generated JWt tokens. So let's start.
Step 1: Resource server with static token validation
Now, let's start with step 1 of this lab. Here we will have a look into the required changes we need compared to the resource server of Lab 1 to support static public keys for token signature validation.
In Lab 1 we have seen how Spring security 5 uses the OpenID Connect Discovery specification to completely configure the resource server to use our keycloak instance.
As we will now locally validate the incoming JWT access tokens using a static public key we do not need the discovery entries (especially the JWKS uri) anymore.
You can see the changes in application.yml, here no issuer uri property is required anymore. Instead, we specify a location reference to a file containing a public key to verify JWT tokens.
This looks like this:
Now we have to use this public key to configure the JwtDecoder to use this for validating JWT tokens instead of contacting keycloak.
This requires a small change in the class com.example.library.server.config.WebSecurityConfiguration:
Open the class com.example.library.server.config.WebSecurityConfiguration and look at the changes:
This configuration above looks like the one as in Lab 1 with one important change:
Here we use the public key (using RSA crypto algorithm) we read from the publicKeyLocation and create a NimbusJwtDecoder using this public key instead of configuring a JwtDecoder from issuer uri.
With this configuration in place we have already a working resource server that can handle JWt access tokens transmitted via http bearer token header. Spring Security also validates by default:
the JWT signature against the given static public key
the JWT iss claim against the configured issuer uri
that the JWT is not expired, if the JWT contains such entry
Step 2: Run JWT generator web application
Please navigate your Java IDE to the lab4/jwt-generator project. Then start the application by running the class com.example.jwt.generator.Lab5JwtGeneratorApplication.
After starting navigate your browser to localhost:9093.
Then you should see a screen like the following one.
To generate an JWT access token with the correct user identity and role information please fill the shown form with one of the following users and roles:
After filling the form click on the button Generate JWT then you should get another web page with the generate access token. This should look like this one.
To continue with this lab copy the contents of the JWT and use this JWT as access token to make a request to the resource server in the next step.
Step 3: Run and test static resource server
Please navigate your Java IDE to the lab5/library-server-static-complete project and at first explore this project a bit. Then start the application by running the class com.example.library.server.Lab5CompleteStaticLibraryServerApplication.
Same as in Lab 1 we require bearer tokens in JWT format to authenticate at our resource server.
To do this we will need to run the copied access token from the JWT generator web application in the previous step.
To make a request for a list of users we have to specify the access token as part of a Authorization header of type Bearer like this:
httpie:
curl:
You have to replace [access_token] with the one you have obtained from the JWt generator application.
Navigate your web browser to jwt.io and paste your access token into the Encoded text field.
If you scroll down a bit on the right hand side then you will see the following block (depending on which user you have specified when generating a JWT):
As you can see our user has the scopes library_admin, email and profile. These scopes are now mapped to the Spring Security authorities SCOPE_library_admin, SCOPE_email and SCOPE_profile.
This request should succeed with an '200' OK status and return a list of users.
Step 4: Use new approach for JWT based authorization tests
As of version 5.2 of spring security new support for JWT based authorization tests is provided.
To see the new approach please have a look into the test class com.example.library.server.api.BookApiJwtAuthorizationTests.
Here you see that you may configure either default or customized JWT tokens to test different authorization scenarios.
Details on JWT testing support can be found in the corresponding spring security reference documentation section.
This concludes the Lab 5.
Last updated