JWT as an Authentication Token
Learn about JWT authentication with signature and asymmetric RSA keys with a code example.
Overview
In this lesson, we will use a JWT (this time a signature with asymmetric RSA keys) to authenticate ourselves when calling the application. We will create a JWT that is verified on the server-side, where the subject can be used to identify who called the endpoint. This does not make use of the standards demonstrated in the following example.
This example can be used in machine-to-machine communication where data exchange is performed using REST endpoints. A program will generate a public and private RSA key, which will be used to create a JWT token. The JAX-RS filter will use this token to authenticate.
Create the project
We start once again from the project template that we defined earlier and add the required dependencies and classes to it.
If you want to work within the Educative platform, simply use the project we’ve created at the end of this lesson. If you choose to work locally, you will need to create a Maven project
jwtauth
as described in "Introduction to Window Shopping."
Add dependency
Add the following dependency to the pom.xml
file:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>be.rubus.security.workshop</groupId><artifactId>jwtAuth</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>11</maven.compiler.source><maven.compiler.target>11</maven.compiler.target><failOnMissingWebXml>false</failOnMissingWebXml></properties><dependencies><dependency><groupId>jakarta.platform</groupId><artifactId>jakarta.jakartaee-web-api</artifactId><version>8.0.0</version><scope>provided</scope></dependency><dependency><groupId>com.nimbusds</groupId><artifactId>nimbus-jose-jwt</artifactId><version>9.21</version></dependency></dependencies><build><finalName>jwtAuth</finalName></build></project>
Explanation
Lines 25–29: We add the JWT dependency, which contains all the utility classes and methods to work with JWT and similar concepts.
RSA key creation
We will first create a small helper program to generate an RSA key pair and write it out in a JSON structure. This is defined in the JWK specification.
Note: The private key is not protected by a password or passphrase. Someone who has access to the file can therefore perform all actions that only the owner of the private key should be able to perform.
Let's go ahead and create a new class file JWKManager.java
in the Maven jwt
directory src/main/java/be/rubus/security/workshop/jwt
.
package be.rubus.security.workshop.jwt;import com.nimbusds.jose.Algorithm;import com.nimbusds.jose.jwk.JWK;import com.nimbusds.jose.jwk.KeyUse;import com.nimbusds.jose.jwk.RSAKey;import java.security.KeyPair;import java.security.KeyPairGenerator;import java.security.NoSuchAlgorithmException;import java.security.interfaces.RSAPrivateKey;import java.security.interfaces.RSAPublicKey;import java.util.UUID;public class JWKManager {public static void main(String[] args) {String xApiKey = UUID.randomUUID().toString();JWK jwk = make(2048, xApiKey);System.out.println("x-api-key");System.out.println(xApiKey);System.out.println("Private");System.out.println(jwk.toJSONString());System.out.println("Public");System.out.println(jwk.toPublicJWK().toJSONString());}private static RSAKey make(int keySize, String kid) {try {KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA");generator.initialize(keySize);KeyPair kp = generator.generateKeyPair();RSAPublicKey pub = (RSAPublicKey) kp.getPublic();RSAPrivateKey priv = (RSAPrivateKey) kp.getPrivate();return new RSAKey.Builder(pub).privateKey(priv).keyID(kid).build();} catch (NoSuchAlgorithmException e) {throw new RuntimeException("Unexpected exception ", e);}}}
Explanation
Lines 21–33: We create the
main
method to call the method with the appropriate parameters and write out the information.Lines 35–52: We create a method,
RSAKey
, that takes the key size and the identification of the key as ...