Skip to content

Commit 53a9f2a

Browse files
committed
Updated Readme
1 parent a3949c1 commit 53a9f2a

2 files changed

Lines changed: 145 additions & 1 deletion

File tree

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
![Java Version](https://img.shields.io/badge/java-8%2B-blue)
77
![License](https://img.shields.io/badge/license-MIT-green)
88

9-
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.
9+
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.
1010

1111
## 🏗️ Architecture Overview
1212

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

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

5456

auth0-springboot-api/README.md

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ This library builds on top of the standard Spring Security JWT authentication, p
66

77
- **Complete Spring Security JWT Functionality** - All features from Spring Security JWT Bearer are available
88
- **Built-in DPoP Support** - Industry-leading proof-of-possession token security per [RFC 9449](https://datatracker.ietf.org/doc/html/rfc9449)
9+
- **Multi-Custom Domain (MCD) Support** - Validate tokens from multiple Auth0 custom domains with static lists or dynamic resolution
10+
- **Extensible Caching** - Pluggable `AuthCache` interface for OIDC discovery and JWKS caching with distributed backend support (Redis, Memcached)
911
- **Auto-Configuration** - Spring Boot auto-configuration with minimal setup
1012
- **Flexible Authentication Modes** - Bearer-only, DPoP-only, or flexible mode supporting both
1113

@@ -174,6 +176,146 @@ curl -H "Authorization: DPoP <jwt_token>" \
174176
https://your-api.example.com/api/protected
175177
```
176178

179+
## Multi-Custom Domain (MCD) Support
180+
181+
For tenants with multiple custom domains, the SDK can validate tokens from any of the configured issuers. There are three ways to configure domain resolution:
182+
183+
### Option 1: Static Domain List
184+
185+
Configure a list of allowed issuer domains in `application.yml`:
186+
187+
```yaml
188+
auth0:
189+
audience: "https://your-api-identifier"
190+
domains:
191+
- "login.acme.com"
192+
- "auth.partner.com"
193+
- "dev.example.com"
194+
```
195+
196+
You can also set a primary domain alongside the list:
197+
198+
```yaml
199+
auth0:
200+
domain: "primary.auth0.com"
201+
audience: "https://your-api-identifier"
202+
domains:
203+
- "login.acme.com"
204+
- "auth.partner.com"
205+
```
206+
207+
### Option 2: Dynamic Domain Resolver
208+
209+
For scenarios where the allowed issuers depend on runtime context (e.g., tenant headers, database lookups), define a `DomainResolver` bean:
210+
211+
```java
212+
import com.auth0.DomainResolver;
213+
214+
@Configuration
215+
public class McdConfig {
216+
217+
@Bean
218+
public DomainResolver domainResolver(TenantService tenantService) {
219+
return context -> {
220+
// context.getHeaders() — request headers (lowercase keys)
221+
// context.getUrl() — the API request URL
222+
// context.getTokenIssuer() — unverified iss claim (routing hint only)
223+
String tenantId = context.getHeaders().get("x-tenant-id");
224+
String domain = tenantService.getDomain(tenantId);
225+
return Collections.singletonList(domain);
226+
};
227+
}
228+
}
229+
```
230+
231+
When a `DomainResolver` bean is present, it takes precedence over the static `auth0.domains` list. The single `auth0.domain` can still coexist as a fallback.
232+
233+
### Option 3: Single Domain (Default)
234+
235+
For single-tenant setups, just use the `auth0.domain` property:
236+
237+
```yaml
238+
auth0:
239+
domain: "your-tenant.auth0.com"
240+
audience: "https://your-api-identifier"
241+
```
242+
243+
## Extensibility
244+
245+
### Custom Cache Implementation
246+
247+
The SDK caches OIDC discovery metadata and JWKS providers using a unified cache with key prefixes (`discovery:{issuerUrl}` and `jwks:{jwksUri}`). By default, it uses a thread-safe in-memory LRU cache.
248+
249+
You can replace this with a distributed cache (Redis, Memcached, etc.) by implementing the `AuthCache` interface:
250+
251+
```java
252+
import com.auth0.AuthCache;
253+
254+
public class RedisAuthCache implements AuthCache<Object> {
255+
256+
private final RedisTemplate<String, Object> redisTemplate;
257+
private final Duration ttl;
258+
259+
public RedisAuthCache(RedisTemplate<String, Object> redisTemplate, Duration ttl) {
260+
this.redisTemplate = redisTemplate;
261+
this.ttl = ttl;
262+
}
263+
264+
@Override
265+
public Object get(String key) {
266+
return redisTemplate.opsForValue().get(key);
267+
}
268+
269+
@Override
270+
public void put(String key, Object value) {
271+
redisTemplate.opsForValue().set(key, value, ttl);
272+
}
273+
274+
@Override
275+
public void remove(String key) {
276+
redisTemplate.delete(key);
277+
}
278+
279+
@Override
280+
public void clear() {
281+
Set<String> keys = redisTemplate.keys("discovery:*");
282+
if (keys != null) redisTemplate.delete(keys);
283+
keys = redisTemplate.keys("jwks:*");
284+
if (keys != null) redisTemplate.delete(keys);
285+
}
286+
287+
@Override
288+
public int size() {
289+
return 0; // approximate
290+
}
291+
}
292+
```
293+
294+
Then define it as a Spring bean — the auto-configuration picks it up automatically and wires it into `AuthOptions`. No need to create your own `AuthClient` bean:
295+
296+
```java
297+
@Configuration
298+
public class CacheConfig {
299+
300+
@Bean
301+
public AuthCache<Object> authCache(RedisTemplate<String, Object> redisTemplate) {
302+
return new RedisAuthCache(redisTemplate, Duration.ofMinutes(10));
303+
}
304+
}
305+
```
306+
307+
When an `AuthCache` bean is present, the `cacheMaxEntries` and `cacheTtlSeconds` YAML properties are ignored — your implementation controls its own eviction and TTL.
308+
309+
### Default Cache Settings
310+
311+
If no custom cache is provided, the built-in in-memory cache is used with these defaults:
312+
313+
```yaml
314+
auth0:
315+
cacheMaxEntries: 100 # max entries before LRU eviction
316+
cacheTtlSeconds: 600 # 10-minute TTL per entry
317+
```
318+
177319
## Advanced Features
178320

179321
### Manual JWT Validation

0 commit comments

Comments
 (0)