TessariDB OAuth
Get started

Features

What 0.1.0 serves

An OAuth 2.1 authorization server and OpenID provider with one issuer per company, the pages its users sign in on, an account portal they keep themselves, and an admin console on a listener of its own.

The protocol

One issuer per company

Company acme answers at <PUBLIC_URL>/acme, with its own discovery document, key set, clients, users and audit trail.

Endpoints and what each one answers
EndpointWhat it does
discovery + key setthe issuer's metadata and its public signing keys, generated from the running configuration
authorizationauthorization code with PKCE S256, and pushed authorization requests
tokenauthorization codes, refresh tokens and client credentials
revocationrevokes a refresh token together with its whole family
UserInfonames under profile, groups and roles under groups, read from the store at that moment
logoutRP-initiated and back-channel logout

The browser flow

Step through a sign-in

The one browser flow is the authorization code with PKCE. Each step below names what the issuer checks before it moves on; a step it refuses ends the flow there.

authorization code + PKCEstep 1 of 6

Application → Browserredirect → /oauth2/authorize code_challenge (S256), state, nonce

The application keeps the code verifier. Only its SHA-256 hash travels.

Tokens

Short, addressed, and spent once

  • Access tokens last five minutes and are addressed to one resource; a token for another audience is refused.
  • ID tokens carry acr and amr from the methods actually verified in that sign-in.
  • Subjects are pairwise: two applications cannot join their data on one identifier.
  • Codes redeem once under concurrency; a replayed code or a reused refresh token revokes the refresh family.
  • DPoP-bound tokens, including codes bound to a key by dpop_jkt or by the proof at the pushed request.

Clients

No shared secrets

A client authenticates with private_key_jwt (EdDSA or ES256) or is public, always with PKCE. No client secret is ever made, so there is none to leak from a configuration file.

cnf.jkt = thumbprint(client key)sender-constrained
  • client, with its keyAuthorization: DPoP eyJ… + DPoP: proof(ath, htm, htu)answered
  • someone who copied the tokenAuthorization: DPoP eyJ… + no proof from the key401 invalid_token
  • the same token as a bearer tokenAuthorization: Bearer eyJ…refused
a proof is spent once; keys are named by their JWK thumbprint (RFC 7638)

Sign-in

Passwords, authenticator apps, recovery codes and passkeys

  • A second factor is the user's own choice or the company's rule, and is never removed by an email alone.
  • Holds that end by themselves instead of lockouts.
  • New passwords are screened against a breached-password range service, sent only the first five hex digits of a hash.
  • Password reset, enrolment links, address verification, changes of sign-in address and sign-in notices by mail, worded per company.
  • Self-registration under company policy.

The account portal

Users look after themselves

The portal shows a user's profile, sign-in factors, sessions and the applications that hold access, and lets them remove any of it. Removing an application's access revokes it at once; its access tokens stop within five minutes.

The admin console

On its own listener

Companies, users, groups, clients, operators, sign-in policy, branding, mail wording, signing-key rotation and withdrawal, and the audit trail. Every change records who made it and why.

The admin console's audit trail: numbered events with their time, kind and the fields recorded with each, such as the account, the reason and the operator.
The audit trail, oldest first, as the console shows it

Operations

Regions, limits, the record

  • Regions with home-region redirects: each company's identity data lives in one region, and a request elsewhere is sent there.
  • Per-address request limits counted in TessariDB.
  • The audit trail on a TessariDB topic kept for 400 days.
  • bootstrap-operator for the first operator and reseal for a new key-encryption key.
  • A container image, tessaridb/oauth, for linux/amd64 and linux/arm64.
acme → home region euredirected, never proxied
  • region usGET id.us.example.com/acme/oauth2/authorize?…307 → eu
  • region euGET id.eu.example.com/acme/oauth2/authorize?…answered where acme lives
each region is its own TessariDB store; peers read each other’s directory every five seconds