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.
| Endpoint | What it does |
|---|---|
| discovery + key set | the issuer's metadata and its public signing keys, generated from the running configuration |
| authorization | authorization code with PKCE S256, and pushed authorization requests |
| token | authorization codes, refresh tokens and client credentials |
| revocation | revokes a refresh token together with its whole family |
| UserInfo | names under profile, groups and roles under groups, read from the store at that moment |
| logout | RP-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.
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
acrandamrfrom 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_jktor by the proof at the pushed request.
- redemption 1
- POST /oauth2/token
- spend code (one conditional write)
- tokens issued, family F1
- redemption 2
- POST /oauth2/token
- code already spent
- invalid_grant, family F1 revoked
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.
- client, with its key
Authorization: DPoP eyJ… + DPoP: proof(ath, htm, htu)answered - someone who copied the token
Authorization: DPoP eyJ… + no proof from the key401 invalid_token - the same token as a bearer token
Authorization: Bearer eyJ…refused
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.

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-operatorfor the first operator andresealfor a new key-encryption key.- A container image,
tessaridb/oauth, forlinux/amd64andlinux/arm64.
- region us
GET id.us.example.com/acme/oauth2/authorize?…307 → eu - region eu
GET id.eu.example.com/acme/oauth2/authorize?…answered where acme lives