auth0-java-jwt

repository·master·Indexed 27 days ago

https://github.com/auth0/java-jwt

A Java implementation of JSON Web Token (JWT) following RFC 7519 for server-side JVM applications. It supports signing and verifying tokens using various algorithms including HMAC (HS256, HS384, HS512), RSA (RS256, RS384, RS512, PS256, PS384, PS512), and ECDSA (ES256, ES384, ES512). The library provides tools for creating JWTs with custom claims, verifying tokens with leeway for DateTime claims, and managing keys via RSAKeyProvider and ECDSAKeyProvider. Compatible with Java LTS versions 8, 11, 17, and 21.

Tokens
3.8K
Snippets
8
Records
18
Agent score
81%

What's inside java-jwt

  1. Requirements and Compatibility

    master

    Java Versions

    • Supported LTS versions: 8, 11, 17, and 21.
    • For non-LTS versions above 8, support is provided on a case-by-case basis.

    Platform Note

    • java-jwt is intended for server-side JVM applications.
    • For Android applications, use JWTDecode.Android instead.

    Algorithm Implementation Notes

    • RSASSA-PSS (PS256, PS384, PS512): Relies on JVM support. Available natively from Java 11+ via SunRsaSign. On Java 8, you must register a security provider like BouncyCastle on the classpath.
    • ECDSA (ES256K): Support for secp256k1 with SHA-256 has been dropped because it was disabled in Java 15.
  2. Upgrade from v3.x to v4.0: Breaking Changes

    master

    When upgrading to version 4.0, be aware of the following breaking changes:

    Removed Classes and Methods

    • The impl package is no longer exported.
    • Algorithm#ECDSA256K(ECDSAKeyProvider keyProvider) and Algorithm#ECDSA256K(ECPublicKey publicKey, ECPrivateKey privateKey) have been removed (ES256K is disabled in Java 15+).
    • com.auth0.jwt.interfaces.Clock has been removed. Use java.time.Clock with BaseVerification for testing instead.
    • com.auth0.jwt.impl.NullClaim has been removed. Use Claim#isNull to check for null values.
    • com.auth0.jwt.impl.PublicClaims has been replaced by com.auth0.jwt.RegisteredClaims and com.auth0.jwt.HeaderParams.
    • com.auth0.jwt.interfaces.Verification#withAnyOfAudience no longer has a default implementation.

    Behavioral Changes

    • Date/Time Serialization: All date/time claims are now serialized as seconds since the epoch in both the payload and header. Version 3 used milliseconds for nested values or header parameters.
    • Null Claims in Creation: Passing null to a builder no longer removes the claim; it adds the claim with a literal null value.
    • Claim Validation:
      • Multiple expectations for the same claim name are now all validated (previously, they overrode each other).
      • Passing null to a claim expectation validates that the claim has the literal value null (previously, it removed the expectation).
    • Exception Changes:
      • IncorrectClaimException (subclass of InvalidClaimException) is thrown if a claim exists but has the wrong value.
      • MissingClaimException (subclass of InvalidClaimException) is thrown if an expected claim is missing.
    • Claim Presence: withClaimPresence(String claimName) now considers a claim with a null value as present.
    • Date/Time Equality: Validation of date/time claims now compares values based on seconds rather than strict equality of Date or Instant objects.
    • Claim#isNull() Behavior: Now returns true only if the claim is present and its value is null. To check if a claim is absent, use isMissing().
  3. Validate DateTime claims with leeway

    master

    By default, java-jwt validates standard DateTime claims: iat (issued at) must be in the past, exp (expiration) must be in the future, and nbf (not before) must be in the past. If validation fails, a JWTVerificationException is thrown.

    You can use acceptLeeway(int seconds) to allow a grace period for all DateTime claims. You can also override the leeway for specific claims using acceptExpiresAt(int seconds).

    // Apply 1 second leeway to nbf, iat, and exp
    JWTVerifier verifier = JWT.require(algorithm)
        .acceptLeeway(1)
        .build();
    
    // Apply 1 second leeway to nbf and iat, but 5 seconds specifically for exp
    JWTVerifier verifier = JWT.require(algorithm)
        .acceptLeeway(1)
        .acceptExpiresAt(5)
        .build();
  4. Install java-jwt via Maven or Gradle

    master

    Add the java-jwt dependency to your project using Maven or Gradle to use JSON Web Tokens (JWT) in your server-side JVM applications.

    <dependency>
      <groupId>com.auth0</groupId>
      <artifactId>java-jwt</artifactId>
      <version>4.6.0</version>
    </dependency>
    implementation 'com.auth0:java-jwt:4.6.0'
  5. Create a JWT with custom claims

    master

    Use the JWTCreator.Builder to add custom payload and header claims to a new JWT. Use withHeader(Map<String, Object> header) for headers and withClaim(String name, T value) for payload claims.

    String jwt = JWT.create()
            .withHeader(headerMap)
            .withClaim("string-claim", "string-value")
            .withClaim("number-claim", 42)
            .withClaim("bool-claim", true)
            .withClaim("datetime-claim", Instant.now())
            .sign(algorithm);
  6. Inspect a DecodedJWT

    master

    After successful verification, the verify() method returns a DecodedJWT object. You can use first-class methods to retrieve standard claims (like getSubject() or getAudience()) or use getClaim(String name) to retrieve custom claims. Custom claims return a Claim object, which provides methods like asString() to extract the value in the desired type.

    DecodedJWT jwt = JWT.require(algorithm)
            .build()
            .verify("a.b.c");
    
    // standard claims can be retrieved through first-class methods
    String subject = jwt.getSubject();
    String aud = jwt.getAudience();
    // ...
    
    // custom claims can also be obtained
    String customStringClaim = jwt.getClaim("custom-string-claim").asString();
  7. Verify a JWT

    master

    To verify a JWT, create a JWTVerifier using JWT.require(algorithm). You can chain methods to specify required claim validations (e.g., .withIssuer("auth0")). Call verifier.verify(token) to validate the token. If the signature is invalid or claim requirements are not met, a JWTVerificationException is thrown.

    String token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXUyJ9.eyJpc3MiOiJhdXRoMCJ9.AbIJTDMFc7yUa5MhvcP03nJPyCPzZtQcGEp-zWfOkEE";
    DecodedJWT decodedJWT;
    try {
        Algorithm algorithm = Algorithm.RSA256(rsaPublicKey, rsaPrivateKey);
        JWTVerifier verifier = JWT.require(algorithm)
            // specify any specific claim validations
            .withIssuer("auth0")
            // reusable verifier instance
            .build();
            
        decodedJWT = verifier.verify(token);
    } catch (JWTVerificationException exception){
        // Invalid signature/claims
    }
  8. Verify custom claims during JWT verification

    master

    When building a JWTVerifier, you can enforce requirements on custom claims using the following methods:

    • withClaim(String name, T value): Ensures the claim matches a specific value.
    • withClaimPresence(String name): Ensures the claim exists in the token.
    • withClaim(String name, BiPredicate<Claim, DecodedJWT> predicate): Allows for custom validation logic based on the claim value and the decoded JWT.
    JWTVerifier verifier = JWT.require(algorithm)
            .withClaim("number-claim", 123)
            .withClaimPresence("some-claim-that-just-needs-to-be-present")
            .withClaim("predicate-claim", (claim, decodedJWT) -> "custom value".equals(claim.asString()))
            .build();
    DecodedJWT jwt = verifier.verify("my.jwt.token");
  9. Create a JWT

    master

    To create a JWT, use JWT.create(), configure the desired claims (such as issuer), and then call sign(algorithm) with a valid Algorithm instance. If the signing configuration is invalid or claims cannot be converted, a JWTCreationException will be thrown.

    try {
        Algorithm algorithm = Algorithm.RSA256(rsaPublicKey, rsaPrivateKey);
        String token = JWT.create()
            .withIssuer("auth0")
            .sign(algorithm);
    } catch (JWTCreationException exception){
        // Invalid Signing configuration / Couldn't convert Claims.
    }
  10. Use a KeyProvider for RSA signing and verification

    master

    A KeyProvider allows you to supply the keys required for the Algorithm. For RSA, you can implement RSAKeyProvider to provide the public key (via getPublicKeyById(String kid)), the private key (getPrivateKey()), and the private key ID (getPrivateKeyId()). This is useful when integrating with JWKS providers like jwks-rsa-java to fetch public keys dynamically.

    JwkProvider provider = new JwkProviderBuilder("https://samples.auth0.com/")
            .cached(10, 24, TimeUnit.HOURS)
            .rateLimited(10, 1, TimeUnit.MINUTES)
            .build();
    final RSAPrivateKey privateKey = // private key
    final String privateKeyId = // private key ID
    
    RSAKeyProvider keyProvider = new RSAKeyProvider() {
        @Override
        public RSAPublicKey getPublicKeyById(String kid) {
            return (RSAPublicKey) jwkProvider.get(kid).getPublicKey();
        }
    
        @Override
        public RSAPrivateKey getPrivateKey() {
            // return the private key used 
            return rsaPrivateKey;
        }
    
        @Override
        public String getPrivateKeyId() {
            return rsaPrivateKeyId;
        }
    };
    
    Algorithm algorithm = Algorithm.RSA256(keyProvider);
    //Use the Algorithm to create and verify JWTs.
  11. Use java.time.Instant with JWTCreator

    master

    Version 4.0 introduces support for java.time.Instant when creating JWT claims. Use the following methods on JWTCreator.Builder to add date/time claims:

    • withExpiresAt(Instant expiresAt): Adds the exp claim.
    • withNotBefore(Instant notBefore): Adds the nbf claim.
    • withIssuedAt(Instant issuedAt): Adds the iat claim.
    • withClaim(String claimName, Instant value): Adds a custom claim with an Instant value.
    • withNullClaim(String claimName): Adds a claim with the literal value null.
  12. Perform advanced claim validation with Predicates

    master

    Version 4.0 allows for custom claim validation using BiPredicate. Use the withClaim method on the Verification object to pass a predicate that evaluates the Claim and the DecodedJWT.

    Additionally, you can validate that a claim has a specific Instant value using:

    • Verification#withClaim(String name, Instant value)