FusionAuth JWT

repository·main·Indexed 41 days ago

https://github.com/fusionauth/fusionauth-jwt

A high-performance Java library for signing and verifying JSON Web Tokens (JWT) supporting HMAC, RSA, EC, and EdDSA algorithms. Version 7.0.0 provides utilities for JWKS endpoint retrieval, public/private key conversion to JWK, and clock skew handling during verification.

Tokens
2.8K
Snippets
14
Records
14
Agent score
2%

What's inside FusionAuth JWT

  1. Enable a third-party JCE provider

    main

    To use a third-party JCE provider like Bouncy Castle, insert the provider into the Java Security configuration. Once inserted, no changes to your FusionAuth JWT code are required.

    // Insert the provider ahead of the JCA.
    Security.insertProviderAt(new BouncyCastleFipsProvider(), 1);
  2. Install the Savant build tool

    main

    If you do not have Savant installed, follow these steps to download and install it:

    1. Create a directory named ~/savant.
    2. Download and extract the Savant core tarball.
    3. Create a symbolic link named current.
    4. Add the Savant bin directory to your PATH.
    mkdir ~/savant
    cd ~/savant
    wget http://savant.inversoft.org/org/savantbuild/savant-core/2.0.2/savant-2.0.2.tar.gz
    tar xvfz savant-2.0.2.tar.gz
    ln -s ./savant-2.0.2 current
    export PATH=$PATH:~/savant/current/bin/
  3. Install FusionAuth JWT

    main

    You can add FusionAuth JWT to your project using Maven, Gradle, or Savant. The library has a single external dependency on Jackson.

    ### Maven
    ```xml
    <dependency>
      <groupId>io.fusionauth</groupId>
      <artifactId>fusionauth-jwt</artifactId>
      <version>7.0.0</version>
    </dependency>

    Gradle

    implementation 'io.fusionauth:fusionauth-jwt:7.0.0'

    Gradle Kotlin

    implementation("io.fusionauth:fusionauth-jwt:7.0.0")

    Savant

    dependency(id: "io.fusionauth:fusionauth-jwt:7.0.0")
  4. Sign and verify JWTs using EC

    main

    Use ECSigner to sign JWTs using an Elliptic Curve private key and ECVerifier to verify them using an EC public key. Supported hash functions include SHA-256, SHA-384, and SHA-512.

    // Sign using EC
    Signer signer = ECSigner.newSHA256Signer(new String(Files.readAllBytes(Paths.get("private_key.pem"))));
    
    JWT jwt = new JWT().setIssuer("www.acme.com")
                       .setIssuedAt(ZonedDateTime.now(ZoneOffset.UTC))
                       .setSubject("f1e33ab3-027f-47c5-bb07-8dd8ab37a2d3")
                       .setExpiration(ZonedDateTime.now(ZoneOffset.UTC).plusMinutes(60));
    
    String encodedJWT = JWT.getEncoder().encode(jwt, signer);
    
    // Verify using EC
    Verifier verifier = ECVerifier.newVerifier(Paths.get("public_key.pem"));
    JWT decodedJwt = JWT.getDecoder().decode(encodedJWT, verifier);
  5. Sign and verify JWTs using RSA

    main

    Use RSASigner to sign JWTs using a private key (or a PEM string) and RSAVerifier to verify them using a public key (or a PEM file path). Supported hash functions include SHA-256, SHA-384, and SHA-512.

    // Sign using RSA
    Signer signer = RSASigner.newSHA256Signer(new String(Files.readAllBytes(Paths.get("private_key.pem"))));
    
    JWT jwt = new JWT().setIssuer("www.acme.com")
                       .setIssuedAt(ZonedDateTime.now(ZoneOffset.UTC))
                       .setSubject("f1e33ab3-027f-47c5-bb07-8dd8ab37a2d3")
                       .setExpiration(ZonedDateTime.now(ZoneOffset.UTC).plusMinutes(60));
    
    String encodedJWT = JWT.getEncoder().encode(jwt, signer);
    
    // Verify using RSA
    Verifier verifier = RSAVerifier.newVerifier(Paths.get("public_key.pem"));
    JWT decodedJwt = JWT.getDecoder().decode(encodedJWT, verifier);
  6. Verify JWT with clock skew or time travel

    main

    When verifying JWTs, you can account for clock drift using .withClockSkew(seconds) on the decoder.

    For testing purposes, you can use JWT.getTimeMachineDecoder(ZonedDateTime) to verify a JWT against a specific point in time (e.g., to test expired tokens). Note: The time machine decoder is for testing only and should not be used in production.

    // Verify with 60 seconds of clock skew allowed
    Verifier verifier = ECVerifier.newVerifier(Paths.get("public_key.pem"));
    JWT jwt = JWT.getDecoder().withClockSkew(60).decode(encodedJWT, verifier);
    
    // Time machine decoder for testing (do not use in production)
    ZonedDateTime thePast = ZonedDateTime.of(2019, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC); 
    JWT jwt = JWT.getTimeMachineDecoder(thePast).decode(encodedJWT, verifier);
  7. Sign and verify JWTs using HMAC

    main

    Use HMACSigner to sign a JWT with a shared secret and HMACVerifier to verify it. Supported hash functions include SHA-256, SHA-384, and SHA-512.

    // Sign and encode a JWT using HMAC
    Signer signer = HMACSigner.newSHA256Signer("too many secrets");
    
    JWT jwt = new JWT().setIssuer("www.acme.com")
                       .setIssuedAt(ZonedDateTime.now(ZoneOffset.UTC))
                       .setSubject("f1e33ab3-027f-47c5-bb07-8dd8ab37a2d3")
                       .setExpiration(ZonedDateTime.now(ZoneOffset.UTC).plusMinutes(60));
                           
    String encodedJWT = JWT.getEncoder().encode(jwt, signer);
    
    // Verify and decode the encoded string JWT
    Verifier verifier = HMACVerifier.newVerifier("too many secrets");
    JWT decodedJwt = JWT.getDecoder().decode(encodedJWT, verifier);
  8. Retrieve JSON Web Keys from a JWKS endpoint

    main

    Use JSONWebKeySetHelper to fetch a list of JSONWebKey objects from various OpenID Connect or JWKS endpoints. You can provide a URL string or an optional HttpURLConnection if you need to customize the connection logic.

    // Retrieve JSON Web Keys using a known JWKS endpoint
    List<JSONWebKey> keys = JSONWebKeySetHelper.retrieveKeysFromJWKS("https://www.googleapis.com/oauth2/v3/certs");
    
    // Retrieve JSON Web Keys using a well known OpenID Connect configuration endpoint
    List<JSONWebKey> keys = JSONWebKeySetHelper.retrieveKeysFromWellKnownConfiguration("https://accounts.google.com/.well-known/openid-configuration");
    
    // Retrieve JSON Web Keys using an OpenID Connect issuer endpoint
    List<JSONWebKey> keys = JSONWebKeySetHelper.retrieveKeysFromIssuer("https://accounts.google.com");
  9. Extract a Public Key from a JWK

    main

    To recover a PublicKey from a JSON representation of a JWK, first deserialize the JSON bytes into a JSONWebKey instance using Mapper.deserialize, then use JSONWebKey.parse(jwk) to obtain the key.

    String json = "{\"e\":\"AQAB\",\"kty\":\"RSA\",\"n\":\"...\",\"use\":\"sig\"}";
    byte[] bytes = json.getBytes(StandardCharsets.UTF_8);
    JSONWebKey jwk = Mapper.deserialize(bytes, JSONWebKey.class);
    PublicKey publicKey = JSONWebKey.parse(jwk);