# How AuthClient Handles Metadata Discovery and Caching for OAuth Server Configuration

> Learn how AuthClient discovers and caches OAuth server metadata efficiently using OpenID Connect. Optimize performance with automatic TTL and deduplication.

- Repository: [Auth0/auth0-auth-js](https://github.com/auth0/auth0-auth-js)
- Tags: internals
- Published: 2026-02-25

---

**The AuthClient performs an OpenID Connect discovery request to the issuer's well-known endpoint, stores the resulting ServerMetadata in a shared LRU cache with a configurable TTL (default 600 seconds), and deduplicates concurrent calls through an in-flight promise map to optimize performance across the process lifetime.**

The `auth0/auth0-auth-js` library provides a production-ready OAuth 2.0 client that automatically handles OpenID Connect discovery. Understanding how the **AuthClient** manages **metadata discovery and caching** is essential for optimizing authentication flows in high-throughput applications. This implementation ensures that discovery requests are both efficient and resilient by leveraging a global caching strategy with built-in request deduplication.

## The Lazy Discovery Flow

The AuthClient employs a **lazy initialization** pattern where discovery only occurs when a public method first requires server metadata. This happens transparently when calling methods like `buildAuthorizationUrl()`, `getTokenByCode()`, or `getServerMetadata()` from [`packages/auth0-auth-js/src/auth-client.ts`](https://github.com/auth0/auth0-auth-js/blob/main/packages/auth0-auth-js/src/auth-client.ts).

### Cache Key Generation

Before issuing any network request, the client computes a deterministic cache key in the `#getDiscoveryCacheKey` method (lines 55-58 of [`auth-client.ts`](https://github.com/auth0/auth0-auth-js/blob/main/auth-client.ts)). The key normalizes the tenant domain and incorporates the mTLS configuration flag using the format `domain|mtls:0|1`. This ensures that metadata for the same Auth0 tenant is reused even when different clients request it, while keeping mTLS and non-mTLS configurations isolated.

### Deduplicating Concurrent Requests

To prevent redundant network calls when multiple methods trigger discovery simultaneously, the `#discover` method (lines 102-112 of [`auth-client.ts`](https://github.com/auth0/auth0-auth-js/blob/main/auth-client.ts)) maintains a private `#inFlightDiscovery` map. If a discovery request is already pending for a given cache key, subsequent callers await the existing promise rather than initiating a new HTTP request. This guarantees that only one discovery request per tenant exists in-flight at any moment, regardless of application concurrency.

## Global LRU Cache Architecture

The caching layer is implemented through a sophisticated factory pattern that promotes cache reuse across process boundaries. The `DiscoveryCacheFactory` defined in [`packages/auth0-auth-js/src/cache-provider.ts`](https://github.com/auth0/auth0-auth-js/blob/main/packages/auth0-auth-js/src/cache-provider.ts) (lines 83-100) manages a **global cache map** (`globalCaches`) that ensures all AuthClient instances with identical cache configurations share the same underlying storage.

The `resolveCacheConfig` function (lines 65-76 of [`cache-provider.ts`](https://github.com/auth0/auth0-auth-js/blob/main/cache-provider.ts)) normalizes user-provided options with sensible defaults:

- **TTL**: 600 seconds (10 minutes)
- **Max entries**: 100 tenants

The concrete implementation uses an internal `LruCache` class (located in [`packages/auth0-auth-js/src/lru-cache.ts`](https://github.com/auth0/auth0-auth-js/blob/main/packages/auth0-auth-js/src/lru-cache.ts)) that provides per-entry TTL expiration and least-recently-used eviction semantics.

## Practical Implementation

When you instantiate an AuthClient, no network activity occurs until a method requires server metadata:

```typescript
import { AuthClient } from '@auth0/auth0-auth-js';

// Initialization does not trigger discovery
const auth = new AuthClient({
  domain: 'tenant.auth0.com',
  clientId: 'CLIENT_ID',
  clientSecret: 'CLIENT_SECRET',
});

// First call triggers discovery and populates cache
const authUrl = await auth.buildAuthorizationUrl();

```

Subsequent operations against the same instance reuse the cached metadata instantly:

```typescript
// No HTTP request performed; uses cached ServerMetadata
const tokens = await auth.getTokenByCode(callbackUrl, { codeVerifier });

```

### Cross-Instance Cache Sharing

Because the underlying LRU cache is global, separate AuthClient instances targeting the same domain automatically benefit from shared metadata:

```typescript
const auth2 = new AuthClient({
  domain: 'tenant.auth0.com',  // Same tenant
  clientId: 'OTHER_CLIENT_ID',
  clientSecret: 'OTHER_SECRET',
});

// Returns immediately from global cache populated by first client
const metadata = await auth2.getServerMetadata();

```

## Configuring Cache Behavior

You can customize the discovery cache through the `discoveryCache` option in the AuthClient constructor. The configuration flows through `resolveCacheConfig` to the global cache factory:

```typescript
const auth = new AuthClient({
  domain: 'tenant.auth0.com',
  clientId: 'CLIENT_ID',
  clientSecret: 'CLIENT_SECRET',
  discoveryCache: {
    ttl: 300,        // 5 minutes instead of 10
    maxEntries: 200  // Increase tenant capacity
  }
});

```

These parameters affect the cache identity in the global map, meaning instances with different TTL or size limits maintain separate cache stores.

## Summary

- **Lazy discovery** ensures the first method call requiring metadata triggers a single OpenID Connect discovery request to `/.well-known/openid-configuration`.
- **Global LRU caching** shares metadata across all AuthClient instances with matching configurations, keyed by normalized domain and mTLS flag.
- **Request deduplication** via the `#inFlightDiscovery` map prevents duplicate network calls during concurrent access patterns.
- **Configurable TTL** defaults to 600 seconds (10 minutes) and can be adjusted per client instance through `DiscoveryCacheOptions`.
- **Automatic reuse** applies to all public methods including `buildAuthorizationUrl`, `getTokenByCode`, and `getServerMetadata`.

## Frequently Asked Questions

### How does AuthClient prevent duplicate discovery requests for the same tenant?

The AuthClient maintains a private `#inFlightDiscovery` map in [`auth-client.ts`](https://github.com/auth0/auth0-auth-js/blob/main/auth-client.ts) that tracks pending discovery promises keyed by the normalized domain and mTLS flag. When multiple methods trigger discovery concurrently, subsequent callers await the existing in-flight promise rather than initiating new HTTP requests, ensuring only one network call per tenant occurs regardless of application concurrency.

### What is the default TTL for OAuth server metadata in AuthClient?

By default, the AuthClient caches server metadata for **600 seconds** (10 minutes). This default is set in `resolveCacheConfig` within [`packages/auth0-auth-js/src/cache-provider.ts`](https://github.com/auth0/auth0-auth-js/blob/main/packages/auth0-auth-js/src/cache-provider.ts) and applies to the global LRU cache unless overridden through the `discoveryCache.ttl` configuration option.

### Is the discovery cache shared across multiple AuthClient instances?

Yes. The `DiscoveryCacheFactory` creates cache instances through a global map (`globalCaches`), meaning all AuthClient instances with identical `ttl` and `maxEntries` configurations share the same underlying LRU cache. This design allows metadata retrieved by one client instance to be instantly available to others targeting the same Auth0 domain.

### How does the cache key differentiate between mTLS and standard connections?

The `#getDiscoveryCacheKey` method appends an mTLS indicator to the normalized domain using the format `domain|mtls:0|1`, where `1` indicates mutual TLS is enabled. This ensures that mTLS-specific metadata endpoints are cached separately from standard OAuth configurations, preventing credential context contamination between different authentication modes.