Skip to content
FoxAuth

Features

Everything is in the box. Most of it is switched off.

FoxAuth ships one server with no feature editions. Authorization Code with PKCE and OpenID Connect run from the first start, and most of the rest wait behind a named flag — so your attack surface is the set of features you actually asked for. Each card says which of the two it is.

Each flag below links to its entry in the Settings reference, which is generated from the code and names the default and the consequence.

Protocol

Every grant an OAuth 2.1 client can ask for.

The grants and endpoints. Authorization Code with PKCE and OpenID Connect are always on; most of the rest wait for a flag.

Authorization Code with PKCE

PKCE is mandatory for every client, public or confidential, as OAuth 2.1 requires. Redirect URIs match exactly.

RFC 7636

OpenID Connect Core 1.0

ID tokens, the UserInfo endpoint and discovery, with the standard claim set and pairwise subjects.

OIDC Core 1.0

Issuer identification

Every authorization response carries iss, so a client cannot be tricked into accepting another issuer’s code.

RFC 9207

Resource Indicators

Audience-restrict a token with the resource parameter, and validate it at the resource server. On by default.

resourceIndicators.enabledRFC 8707

Client Credentials grant

Machine-to-machine tokens with no end-user, scoped per client.

clientCredentials.enabled

Refresh Token grant

Long-lived sessions with rotation and reuse detection — a replayed token revokes the whole grant.

refreshToken.enabled

Device Authorization Grant

Sign in on a TV or a CLI by typing a user code on another device.

deviceFlow.enabledRFC 8628

CIBA

Client-initiated backchannel authentication: the client asks, the user approves out of band.

ciba.enabledCIBA Core 1.0

Pushed Authorization Requests

The client posts the request to the server first and sends only a request_uri through the browser.

par.enabledRFC 9126

Request objects

Signed request and request_uri parameters, so the authorization request itself is integrity-protected.

requestObjects.enabled

JARM

JWT-secured authorization responses, signed and optionally encrypted.

responseMode.jwt.enabledJARM

Rich Authorization Requests

Fine-grained authorization_details instead of a scope string, for payments and similar.

richAuthorizationRequests.enabledRFC 9396

Token introspection

Resource servers ask the issuer whether a token is still active, and what it carries.

introspection.enabledRFC 7662

JWT introspection responses

Signed introspection responses, for a resource server that must prove what it was told.

jwtIntrospection.enabledRFC 9701

Token revocation

A client retires an access or refresh token it no longer needs.

revocation.enabledRFC 7009

Signed UserInfo responses

Return UserInfo as a signed JWT rather than plain JSON.

jwtUserinfo.enabled

The claims parameter

Per-request claim selection, including essential claims and the acr request.

claimsParameter.enabled

RP-initiated logout

End the session from the client, with a confirmation step so a link cannot log a user out silently. On by default.

rpInitiatedLogout.enabled

Backchannel logout

Notify every client of a session that ended, server to server.

backchannelLogout.enabled

Security

Sender constraint, and defences that are already on.

The banking-grade profiles are flags, not editions. The rest of this list is on from the first start.

DPoP

Sender-constrained access and refresh tokens, including server nonces, so a stolen token is not enough.

dpop.enabledRFC 9449

mTLS client authentication

Client certificates for authentication and certificate-bound access tokens.

mTLS.enabledRFC 8705

FAPI profile behaviours

The stricter checks the Financial-grade API profiles require, as one switch.

fapi.enabled

Token and response encryption

Encrypted ID tokens, UserInfo and JARM responses using the client’s registered keys.

encryption.enabled

TOTP second factor

Per-bucket time-based one-time passwords, optionally enforced for the admin console.

RFC 6238

Pairwise subject identifiers

A different sub per sector, salted from the database, so two relying parties cannot correlate a user.

Sign-in brute-force throttle

Persisted per-identity failure counters with escalating lockouts. A throttled refusal looks exactly like a wrong password.

Per-origin rate limiting

Tiered by route class and on by default, with the trusted-proxy hop configurable.

rateLimit.enabled

CORS closed by data

An origin is readable only if it is listed on the project that owns the calling client — not by a wildcard setting.

cors.enabled

Security headers

HSTS, Permissions-Policy, framing and content-type protections on every response.

Scope-based access control

Per-client scope enforcement, checked at the authorization endpoint and again at the token endpoint.

The admin audit trail listing actor, action, target and timestamp for each change.
The audit trail. Entries are written before the mutation and the store exposes no update or delete, so an entry cannot be altered after the fact.

Administration

One management API, three front doors.

The console, the HTTP API and the MCP tools dispatch into the same routes, so the checks and the audit write cannot drift.

Administration console

Projects, OAuth clients, administrators, user buckets, end-users, upstream providers, settings, SMTP and signing keys.

Append-only audit trail

Every state-changing admin action records actor, action, target and time — written before the mutation, with no update or delete path.

Administration over MCP

60 tools served to an AI agent at POST /mcp as an OAuth 2.1 protected resource, with two-call confirmation on high-consequence operations.

mcp.enabledRFC 9728

Dynamic client registration

Clients register themselves, subject to the project’s policy.

registration.enabledRFC 7591

Registration management

Read, update and delete a registration with its registration access token.

registrationManagement.enabledRFC 7592

Database-backed clients

Clients live in the server’s own store, created through the console, the API, dynamic registration or the setup script. There is no static client file.

Group ownership

Projects and user buckets are owned by a group; membership is the only thing that grants access, re-resolved on every request.

End-user self-service

Email verification and password reset per bucket, each with attempt caps, cooldowns and single-use links.

Upstream OIDC federation

Let end-users sign in through an external provider, configured per project.

federation.enabled

Signing key management

View, generate and delete keys over the key store; a generated key is applied to the live keystore and published at /jwks.

The admin console settings pane showing the grant-type flags and their current values.
Settings, one pane per domain. A flag here is the same key the Reference documents; changes are validated as a whole configuration before they are saved.

Extensibility

Change behaviour without forking.

Named seams and one adapter interface, so your changes survive an upgrade.

31 override seams

Account lookup, interaction policy, refresh-token rotation, resource resolution, pairwise identifiers, RAR handling and more, replaced at call time.

Pluggable storage

Every persisted model goes through one adapter interface. MongoDB and in-memory implementations ship.

Mountable Elysia app

Import the app and mount it in your own Bun service. There is no init step — importing is what boots it.

Built-in login and consent UI

React and Ant Design screens you can theme, or replace through the interaction policy.

Operations

What you need when something is wrong.

Ship it, watch it, and find out why a request failed.

Published container image

ghcr.io/redfox-soft/oauth-server-ts, tagged per release and latest, with a Compose file that provisions the schema.

Server error store

Internal faults are recorded and readable in the console. Routine client rejections are correct behaviour and never appear.

errorStore.enabled

Optional Sentry reporting

Reporting sits off the request path entirely: a fault reaches it only after it is classified as a defect, so responses are unchanged.

sentry.enabled

Settings you can read

Every server-wide setting is documented with its type, default and consequence, and edited in the console.

Machine-readable reference

The endpoint, settings, admin API, MCP tool and environment references are generated from the code itself.

Next

Compare it with what you run today.

We keep a factual, dated comparison against the servers teams usually weigh this against.