Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
![Java Version](https://img.shields.io/badge/java-8%2B-blue)
![License](https://img.shields.io/badge/license-MIT-green)

A comprehensive Java library for Auth0 JWT authentication with built-in **DPoP (Demonstration of Proof-of-Possession)** support. This multi-module project provides both a core authentication library and Spring Boot integration for secure API development.
A comprehensive Java library for Auth0 JWT authentication with built-in **DPoP (Demonstration of Proof-of-Possession)** and **Multi-Custom Domain (MCD)** support. This project provides both a core authentication library and Spring Boot integration for secure API development.

## 🏗️ Architecture Overview

Expand Down Expand Up @@ -49,6 +49,8 @@ The core library (`auth0-api-java`) is currently an internal module used by the

- JWT validation with Auth0 JWKS integration
- DPoP proof validation per [RFC 9449](https://datatracker.ietf.org/doc/html/rfc9449)
- Multi-Custom Domain (MCD) support — static domain lists, or dynamic resolution at request time
- Extensible caching — pluggable `AuthCache` interface for distributed backends (Redis, Memcached)
- Flexible authentication strategies


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
import com.auth0.models.AuthToken;
import com.auth0.models.AuthenticationContext;
import com.auth0.models.HttpRequestInfo;
import com.auth0.validators.DPoPProofValidator;
import com.auth0.validators.JWTValidator;

import java.util.HashMap;
import java.util.List;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.models.AuthenticationContext;
import com.auth0.models.HttpRequestInfo;
import com.auth0.validators.DPoPProofValidator;
import com.auth0.validators.JWTValidator;

import java.util.Map;
class AllowedDPoPAuthentication extends AbstractAuthentication {

public AllowedDPoPAuthentication(JWTValidator jwtValidator,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.auth0.cache;
package com.auth0;

/**
* Cache abstraction for storing authentication-related data such as
Expand Down
4 changes: 0 additions & 4 deletions auth0-api-java/src/main/java/com/auth0/AuthClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@
import com.auth0.models.AuthenticationContext;
import com.auth0.models.AuthOptions;
import com.auth0.models.HttpRequestInfo;
import com.auth0.validators.DPoPProofValidator;
import com.auth0.validators.JWTValidator;

import java.util.Map;

public class AuthClient {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.auth0;

public class AuthConstants {
class AuthConstants {
public static final String AUTHORIZATION_HEADER = "authorization";
public static final String DPOP_HEADER = "dpop";
public static final String BEARER_SCHEME = "bearer";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.auth0.validators;
package com.auth0;

import com.auth0.exception.*;
import com.auth0.jwt.interfaces.DecodedJWT;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.auth0.validators;
package com.auth0;

import com.auth0.exception.BaseAuthException;
import com.auth0.exception.InvalidDpopProofException;
Expand All @@ -20,13 +20,13 @@
import java.time.Instant;
import java.util.*;

public class DPoPProofValidator {
class DPoPProofValidator {

private final AuthOptions options;
private final ObjectMapper objectMapper = new ObjectMapper();;


public DPoPProofValidator(AuthOptions options) {
DPoPProofValidator(AuthOptions options) {
this.options = options;
}

Expand All @@ -38,7 +38,7 @@ public DPoPProofValidator(AuthOptions options) {
* @param requestInfo HTTP request info: method and URL
* @throws BaseAuthException if the DPoP proof is invalid.
*/
public void validate(String dpopProof, DecodedJWT decodedJwtToken, HttpRequestInfo requestInfo)
void validate(String dpopProof, DecodedJWT decodedJwtToken, HttpRequestInfo requestInfo)
throws BaseAuthException {

DecodedJWT proofJwt = decodeDPoP(dpopProof);
Expand Down Expand Up @@ -197,7 +197,7 @@ String calculateJwkThumbprint(Map<String, Object> jwk) throws BaseAuthException
}
}

public static ECPublicKey convertJwkToEcPublicKey(Map<String, Object> jwkMap)
static ECPublicKey convertJwkToEcPublicKey(Map<String, Object> jwkMap)
throws JwkException {

Jwk jwk = Jwk.fromValues(jwkMap);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,6 @@
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.models.AuthenticationContext;
import com.auth0.models.HttpRequestInfo;
import com.auth0.validators.JWTValidator;

import java.util.Map;

class DisabledDPoPAuthentication extends AbstractAuthentication {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.auth0.cache;
package com.auth0;

import java.util.LinkedHashMap;
import java.util.Map;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package com.auth0.validators;
package com.auth0;

import com.auth0.cache.AuthCache;
import com.auth0.cache.InMemoryAuthCache;
import com.auth0.exception.BaseAuthException;
import com.auth0.exception.MissingRequiredArgumentException;
import com.auth0.exception.VerifyAccessTokenException;
Expand All @@ -17,6 +15,7 @@
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.models.HttpRequestInfo;
import com.auth0.models.RequestContext;
import com.auth0.OidcDiscoveryFetcher;

import java.net.MalformedURLException;
import java.net.URL;
Expand All @@ -32,7 +31,7 @@
* algorithm
* and JWKS (JSON Web Key Set) for public key retrieval.
*/
public class JWTValidator {
class JWTValidator {

static final String JWKS_CACHE_PREFIX = "jwks:";

Expand All @@ -47,7 +46,7 @@ public class JWTValidator {
*
* @param authOptions Authentication options containing domain and audience
*/
public JWTValidator(AuthOptions authOptions) {
JWTValidator(AuthOptions authOptions) {
if (authOptions == null) {
throw new IllegalArgumentException("AuthOptions cannot be null");
}
Expand All @@ -66,7 +65,7 @@ public JWTValidator(AuthOptions authOptions) {
* @param authOptions Authentication options containing domain and audience
* @param jwkProvider Custom JwkProvider for key retrieval
*/
public JWTValidator(AuthOptions authOptions, JwkProvider jwkProvider) {
JWTValidator(AuthOptions authOptions, JwkProvider jwkProvider) {
if (authOptions == null) {
throw new IllegalArgumentException("AuthOptions cannot be null");
}
Expand Down Expand Up @@ -117,7 +116,7 @@ private static AuthCache<Object> resolveCache(AuthOptions options) {
* @return the decoded and verified JWT
* @throws BaseAuthException if validation fails
*/
public DecodedJWT validateToken(String token, HttpRequestInfo httpRequestInfo) throws BaseAuthException {
public DecodedJWT validateToken(String token, HttpRequestInfo httpRequestInfo) throws BaseAuthException {

if (token == null || token.trim().isEmpty()) {
throw new MissingRequiredArgumentException("access_token");
Expand Down Expand Up @@ -167,7 +166,7 @@ public DecodedJWT validateToken(String token, HttpRequestInfo httpRequestInfo) t
/**
* Validates a JWT and ensures all required scopes are present.
*/
public DecodedJWT validateTokenWithRequiredScopes(String token, HttpRequestInfo httpRequestInfo, String... requiredScopes) throws BaseAuthException {
DecodedJWT validateTokenWithRequiredScopes(String token, HttpRequestInfo httpRequestInfo, String... requiredScopes) throws BaseAuthException {
DecodedJWT jwt = validateToken(token, httpRequestInfo);
try {
ClaimValidator.checkRequiredScopes(jwt, requiredScopes);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.auth0.validators;
package com.auth0;

import com.auth0.cache.AuthCache;
import com.auth0.exception.VerifyAccessTokenException;
import com.auth0.models.OidcMetadata;
import com.fasterxml.jackson.databind.JsonNode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.models.AuthenticationContext;
import com.auth0.models.HttpRequestInfo;
import com.auth0.validators.DPoPProofValidator;
import com.auth0.validators.JWTValidator;

import java.util.Map;

class RequiredDPoPAuthentication extends AbstractAuthentication {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.auth0.models;

import com.auth0.DomainResolver;
import com.auth0.cache.AuthCache;
import com.auth0.AuthCache;
import com.auth0.enums.DPoPMode;

import java.util.ArrayList;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
import com.auth0.models.AuthToken;
import com.auth0.models.AuthenticationContext;
import com.auth0.models.HttpRequestInfo;
import com.auth0.validators.DPoPProofValidator;
import com.auth0.validators.JWTValidator;
import org.junit.Before;
import org.junit.Test;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
import com.auth0.models.AuthToken;
import com.auth0.models.AuthenticationContext;
import com.auth0.models.HttpRequestInfo;
import com.auth0.validators.DPoPProofValidator;
import com.auth0.validators.JWTValidator;
import org.junit.Before;
import org.junit.Test;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.auth0.validators;
package com.auth0;

import com.auth0.exception.BaseAuthException;
import com.auth0.exception.InsufficientScopeException;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.auth0.validators;
package com.auth0;

import com.auth0.exception.*;
import com.auth0.jwt.JWT;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.models.AuthenticationContext;
import com.auth0.models.HttpRequestInfo;
import com.auth0.validators.JWTValidator;
import org.junit.Before;
import org.junit.Test;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.auth0.validators;
package com.auth0;

import com.auth0.cache.InMemoryAuthCache;
import com.auth0.exception.InsufficientScopeException;
import com.auth0.exception.InvalidRequestException;
import com.auth0.exception.MissingRequiredArgumentException;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.auth0.validators;
package com.auth0;

import com.auth0.cache.InMemoryAuthCache;
import com.auth0.exception.VerifyAccessTokenException;
import com.auth0.models.OidcMetadata;
import org.apache.http.HttpVersion;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
import com.auth0.models.AuthToken;
import com.auth0.models.AuthenticationContext;
import com.auth0.models.HttpRequestInfo;
import com.auth0.validators.DPoPProofValidator;
import com.auth0.validators.JWTValidator;
import org.junit.Before;
import org.junit.Test;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.auth0.cache;

import com.auth0.InMemoryAuthCache;
import org.junit.Before;
import org.junit.Test;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.auth0.models;

import com.auth0.DomainResolver;
import com.auth0.cache.AuthCache;
import com.auth0.cache.InMemoryAuthCache;
import com.auth0.AuthCache;
import com.auth0.InMemoryAuthCache;
import com.auth0.enums.DPoPMode;
import org.junit.Test;

Expand Down
6 changes: 6 additions & 0 deletions auth0-springboot-api-playground/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,16 @@ dependencies {

implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-security'

testImplementation 'org.junit.jupiter:junit-jupiter-api'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
}

test {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed"
}
}

tasks.named('bootJar') {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.auth0.playground;

import com.auth0.spring.boot.Auth0DomainResolver;
import com.auth0.spring.boot.Auth0RequestContext;
import com.auth0.DomainResolver;
import com.auth0.models.RequestContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

Expand All @@ -14,20 +14,17 @@
* Example: Multi-Custom Domain (MCD) configuration with a dynamic domain
* resolver.
* <p>
* Demonstrates how an end developer uses {@link Auth0DomainResolver} to
* dynamically
* resolve allowed issuer domains at request time — without any direct
* dependency
* on the core {@code auth0-api-java} module.
* Demonstrates how an end developer uses {@link DomainResolver} to dynamically
* resolve allowed issuer domains at request time.
* </p>
*
* <h3>How it works</h3>
* <ol>
* <li>Define an {@link Auth0DomainResolver} bean in a {@code @Configuration}
* <li>Define a {@link DomainResolver} bean in a {@code @Configuration}
* class</li>
* <li>The auto-configuration picks it up and bridges it into the SDK's
* internal domain resolution pipeline</li>
* <li>On each request, the resolver receives an {@link Auth0RequestContext}
* <li>The auto-configuration picks it up and passes it to the SDK's
* domain resolution pipeline</li>
* <li>On each request, the resolver receives a {@link RequestContext}
* containing the request URL, headers, and unverified token issuer</li>
* <li>The resolver returns the list of allowed issuer domains for that
* request</li>
Expand All @@ -36,7 +33,7 @@
* <h3>Activation</h3>
* <p>
* Just define this {@code @Configuration} class in your project.
* The auto-configuration detects the {@link Auth0DomainResolver} bean
* The auto-configuration detects the {@link DomainResolver} bean
* automatically — no extra YAML properties needed.
* </p>
*
Expand All @@ -50,8 +47,8 @@
* against a known allowlist</li>
* </ul>
*
* @see Auth0DomainResolver
* @see Auth0RequestContext
* @see DomainResolver
* @see RequestContext
*/
@Configuration
public class McdDomainResolverExample {
Expand All @@ -72,7 +69,7 @@ public class McdDomainResolverExample {
* Dynamic domain resolver that resolves allowed issuers based on the
* {@code X-Tenant-ID} request header.
* <p>
* The resolver receives an {@link Auth0RequestContext} with:
* The resolver receives a {@link RequestContext} with:
* <ul>
* <li>{@code context.getUrl()} — the API request URL</li>
* <li>{@code context.getHeaders()} — all request headers (lowercase keys)</li>
Expand All @@ -88,10 +85,10 @@ public class McdDomainResolverExample {
* http://localhost:8080/api/protected
* </pre>
*
* @return an {@link Auth0DomainResolver} that maps tenant IDs to Auth0 domains
* @return a {@link DomainResolver} that maps tenant IDs to Auth0 domains
*/
@Bean
public Auth0DomainResolver domainResolver() {
public DomainResolver domainResolver() {
return context -> {
String tenantId = context.getHeaders().get("x-tenant-id");

Expand Down
Loading
Loading