Configuration¶
For AI Agents¶
Prompt: "Configure the rust-oauth2-server with PostgreSQL database, proper JWT secret, and Redis caching enabled"
Common configuration tasks:
| Task | Prompt Example |
|---|---|
| Basic local setup | "Set up minimal environment variables for local development with SQLite" |
| Production config | "Configure production environment with PostgreSQL, strong secrets, and proper session keys" |
| Enable Redis cache | "Configure Redis cache for distributed deployment" |
| Database migration | "Switch from SQLite to PostgreSQL and migrate the database" |
| Enable CORS | "Configure CORS to allow requests from https://myapp.example.com" |
| Social login | "Enable Google OAuth login with client ID and secret" |
| Distributed mode | "Enable all distributed features (Redis cache, rate limiting, event bus)" |
Key config files:
- .env - Runtime environment variables (create from .env.example)
- application.conf - HOCON configuration file (optional, overridden by env vars)
- .env.example - Canonical reference for all config keys
- application.conf.example - HOCON example
Configuration precedence: HOCON file (application.conf) is loaded first with environment variable substitution; a handful of env vars (e.g. OAUTH2_ALLOWED_ORIGINS) are applied as explicit overrides on top. If no HOCON file is present the server falls back to environment variables only.
Use this page for the settings you are actually likely to touch. When you need exact keys, defaults, or comments, use .env.example and application.conf.example as the canonical contract.
Source of truth¶
Check these first when docs and runtime behavior disagree:
.env.exampleapplication.conf.examplecrates/oauth2-config/crates/oauth2-server/src/lib.rs
Runtime precedence is:
- environment variables
application.conf- built-in defaults
Minimum local config¶
For a useful local run, these are the only values most people need to set:
| Variable | Why it matters |
|---|---|
OAUTH2_DATABASE_URL |
Defaults to SQLite and is fine for local work. |
OAUTH2_JWT_SECRET |
Required for token signing; startup fails on insecure defaults. |
OAUTH2_SESSION_KEY |
Keeps sessions stable across restarts. Use a 128-character hex string. |
OAUTH2_SEED_PASSWORD |
Password for the seeded admin account. |
RUST_LOG |
Runtime log level. |
Example:
OAUTH2_DATABASE_URL=sqlite:oauth2.db
OAUTH2_JWT_SECRET=replace-with-a-random-32+-char-secret
OAUTH2_SESSION_KEY=replace-with-128-hex-characters
OAUTH2_SEED_PASSWORD=replace-with-a-local-admin-password
RUST_LOG=info
Generate a session key with:
Database pool tuning¶
These settings control the SQLx connection pool when using SQLite or PostgreSQL:
| Variable | Default | Purpose |
|---|---|---|
OAUTH2_DATABASE_MAX_CONNECTIONS |
50 |
Maximum number of connections in the pool |
OAUTH2_DATABASE_MIN_CONNECTIONS |
1 |
Minimum idle connections to keep open |
OAUTH2_DATABASE_ACQUIRE_TIMEOUT_SECS |
30 |
Seconds to wait when acquiring a connection |
OAUTH2_DATABASE_IDLE_TIMEOUT_SECS |
600 |
Seconds before an idle connection is closed |
OAUTH2_DATABASE_READ_URL |
— | Optional read-replica URL for read traffic |
URL, proxy, and browser settings¶
These matter when the bind address is not the same as the public address clients use.
| Variable | Use it when |
|---|---|
OAUTH2_SERVER_PUBLIC_BASE_URL |
the externally visible issuer/base URL differs from the bind address |
OAUTH2_SERVER_TRUST_PROXY_HEADERS |
the server sits behind a trusted reverse proxy |
OAUTH2_ALLOWED_ORIGINS |
browsers call the server cross-origin |
OAUTH2_SERVER_WORKERS |
you want to pin Actix worker count |
The runtime also accepts OAUTH2_PUBLIC_URL as an alias for the public base URL.
Security-sensitive settings¶
These are worth calling out because startup and auth flows depend on them.
| Variable | Notes |
|---|---|
OAUTH2_JWT_SECRET |
Must be strong and must not use the insecure default. |
OAUTH2_SESSION_KEY |
Persistent 64-byte key encoded as 128 hex characters. |
OAUTH2_SEED_USERNAME |
Optional; defaults to admin. |
OAUTH2_SEED_EMAIL |
Optional; defaults to admin@example.com. |
OAUTH2_SEED_PASSWORD |
Required in normal mode; the server aborts on changeme. |
OAUTH2_ALLOW_INSECURE_DEFAULTS |
Development-only escape hatch. Never set in production. |
OAUTH2_JWT_STATELESS_VALIDATION |
Skips DB-backed introspection checks for higher throughput. |
OAUTH2_ACCESS_TOKENS_OPAQUE |
Issue opaque (reference-style) access tokens instead of JWTs. Default false. |
OAUTH2_PUBLIC_INTROSPECTION |
Allows unauthenticated callers to use introspection. Default false. |
OAUTH2_DYNAMIC_REGISTRATION_ENABLED |
Enables the public RFC 7591 endpoint POST /connect/register. Default false; when not true that endpoint returns 403. Create clients through the admin endpoint POST /admin/clients/register instead. |
OAUTH2_ADMIN_CLIENT_IDS |
Comma-separated client_ids whose bearer tokens (carrying the admin scope) may access /admin/*. Default empty, meaning no machine client is treated as admin. Set this to your MCP/automation client_id to grant machine-to-machine admin access. |
Privileged scopes (admin, write) cannot be requested through the public
RFC 7591 registration or RFC 7592 update endpoints; such requests are rejected
with an error, and these scopes may only be granted via
POST /admin/clients/register.
Social login¶
Implemented provider flows today:
- Microsoft
- Azure
- GitHub
Important caveats:
/auth/login/azureand/auth/callback/azurepreferOAUTH2_AZURE_*settings and fall back toOAUTH2_MICROSOFT_*when Azure-specific config is unset.- Okta and Auth0 config fields exist, but those routes currently return HTTP
503.
Example Microsoft setup:
export OAUTH2_MICROSOFT_CLIENT_ID=your-client-id
export OAUTH2_MICROSOFT_CLIENT_SECRET=your-client-secret
export OAUTH2_MICROSOFT_REDIRECT_URI=http://localhost:8080/auth/callback/microsoft
export OAUTH2_MICROSOFT_TENANT_ID=common
OIDC signing¶
If you want RS256 id tokens and a populated JWKS endpoint, configure:
| Variable | Purpose |
|---|---|
OAUTH2_ID_TOKEN_PRIVATE_KEY_PEM |
RSA private key PEM; literal newlines and \n-escaped values both work |
OAUTH2_ID_TOKEN_KID |
Key id published through JWKS |
OAUTH2_ID_TOKEN_ALG |
Usually RS256; defaults to RS256 when a private key is present |
If these are not set, id tokens fall back to HS256 using OAUTH2_JWT_SECRET.
Eventing, caching, and traffic control¶
Runtime defaults:
OAUTH2_EVENTS_ENABLED=trueOAUTH2_EVENTS_BACKEND=in_memoryOAUTH2_EVENTS_FILTER_MODE=allow_all
Event ingest authentication:
| Variable | Purpose |
|---|---|
OAUTH2_EVENTS_PUBLIC_INGEST |
Allow unauthenticated callers to POST /events/ingest. Default false. |
OAUTH2_EVENTS_INGEST_BEARER_TOKEN |
Shared bearer token required when OAUTH2_EVENTS_PUBLIC_INGEST=false. Callers send Authorization: Bearer <token>. |
Feature-gated broker backends:
| Backend | Build requirement |
|---|---|
| Redis Streams | --features events-redis |
| Kafka | --features events-kafka |
| RabbitMQ | --features events-rabbit |
Cluster and performance knobs:
| Variable | What it controls |
|---|---|
OAUTH2_DATABASE_READ_URL |
Optional read replica for geographically local reads |
OAUTH2_CACHE_REDIS_URL |
Redis L2 cache (requires redis-cache) |
OAUTH2_TOKEN_ACTOR_SHARDS |
Per-process token actor shard count |
OAUTH2_RATE_LIMIT_* |
In-memory or Redis-backed request throttling |
OAUTH2_RESILIENCE_* |
Back-pressure and circuit-breaker middleware |
For the bundled clustered profile, build with:
Conformance test mode¶
Test-only mode that lets the external
oauth2-conformance runner
drive this server as a black-box SUT (its contract/sut-interface.md). It is
off by default and must never be enabled outside an ephemeral test process.
| Variable | Purpose |
|---|---|
OAUTH2_CONFORMANCE_MODE |
1/true enables; unset/0/false disables; anything else aborts. |
OAUTH2_CONFORMANCE_SEED |
Path to the seed file (YAML or JSON, schemas/seed.schema.json). Required when the mode is on; ignored (with a warning) when it is off. |
What it does when on:
- Loads the seed's
issuer,clients,usersandsigningKeysinto the process-local store before the server binds a port. The seeded issuer is used foriss, discovery and JWKS; eachsigningKeysentry (RS256,HS256) gets freshly generated key material under the seededkid, which becomes the current key. Key material is never read from or written to the seed. - Replaces the default
adminaccount: only seeded users exist. Passwords are Argon2-hashed at seed time, so the normalPOST /auth/loginform is the test login and/oauth/authorizeis the unmodified production path. There is no consent screen in this server, so seeded clients are consented implicitly. GET /readyadds aconformanceobject (seed_applied, counts, signing key ids; never credentials) once the seed is applied./healthis unchanged.
It fails closed. Startup aborts, before any storage is opened, when:
OAUTH2_ENV,OAUTH2_ENVIRONMENT,OAUTH2_PROFILE,APP_ENV,ENVIRONMENTorRUST_ENVis set to anything other thantest,testing,conformance,dev,development,localorci(an unknown name is refused, not assumed safe);- the database is not process-local in-memory SQLite
(
OAUTH2_DATABASE_URL=sqlite::memory:) or a read replica is configured; - the seed is missing, unreadable, not valid against the schema (unknown keys,
duplicates, a confidential client without a secret, an unsupported signing
algorithm such as
ES256, a trailing/on the issuer, ...).
Example:
OAUTH2_CONFORMANCE_MODE=1 OAUTH2_CONFORMANCE_SEED=./conformance-seed.yaml \
OAUTH2_ENV=test OAUTH2_DATABASE_URL=sqlite::memory: \
OAUTH2_JWT_SECRET=$(openssl rand -hex 32) cargo run
HOCON vs env files¶
Use environment variables when:
- you deploy with containers or Kubernetes
- secrets come from a secret manager
- you want a twelve-factor-style setup
Use application.conf when:
- you want a checked-in local baseline
- you prefer grouped config over a long env file
- you are mixing defaults with a few environment overrides