Product
Unlimited SSO. Same bill. Same wire.
Point the stock better-auth client at an instance. Adding a prospect's identity provider is a configuration change, not a purchase order. Users, sessions, and secrets live in your Postgres. The argument is on /friday.
What is builtAgent tokensThe wireThe instanceYour PostgresThe receiptAppendix
[server]
listen = "0.0.0.0:3000"
base_url = "https://auth.example.com"
[database]
adapter = "postgres" # or SIGNET_DATABASE_URL
# users, sessions + secrets live in YOUR Postgres| Kind | Holds | How they arrive | The path |
|---|---|---|---|
| People | a session | email, passkey, SSO | revoke |
| Services | a token | minted once | revoke |
| Agents | a scoped token | MCP auth | revoke |
What is built.
What the engine does today, one row per capability, each with its receipt. The rule of this table: built and driven means listed; partial or unproven means explicitly scoped or absent. Nothing on it exceeds the record, and the embedded /docs of any live instance is the reference it must agree with.
| Capability | Standing | The receipt |
|---|---|---|
| Email + password | built | Sign-up and sign-in on the certified wire, with the password policy, breached-password check, and reset flow behind it. |
| Magic links | built | Send and verify. A sign-in completed in a real browser. |
| Email OTP | built | One-time codes for sign-in, email verification, password reset, and email change. |
| Passkeys (WebAuthn) | built | Real ceremony cryptography across four routes, exercised against a soft authenticator in tests. |
| Two-factor | built | TOTP, an emailed one-time code as second factor, and single-use backup codes; the lost-authenticator recovery path is driven in a browser end to end. |
| Social sign-in | built | Sign in with, link, and unlink upstream providers on the same wire. |
| Organisations + invitations | built | Twelve organization routes: members, invitations, roles. |
| API keys | built | Five routes for issuing and managing programmatic credentials. |
| Device-code flow | built | Five routes: sign a CLI or a TV in from another device. |
| MCP auth | built | Five routes for agent-facing auth; the machine caller is a first-class client. |
| Agent tokens (audience-bound) | built | An access token that lives five minutes to an hour on one config key, names up to eight APIs it may be presented to, carries only the scopes the signed-in person approved, and reads dead at every door the moment you revoke it. The OAuth surface and the MCP surface read the same key and the same binding, so the two cannot drift apart. What that buys → |
| Session + token inventory | built | Enumerate and revoke what is outstanding from the console and the wire. |
| OAuth2 / OIDC provider | scoped | Signet issues tokens as the provider: the authorization-code flow with PKCE is built and was proven in a real browser. Not every sibling endpoint of the provider surface ships yet, so this row is scoped to the flow that did. |
| Enterprise SSO (SAML + OIDC) | scoped | Both transports complete full round trips against real test identity providers: SAML against a conformance IdP, OIDC against a containerised IdP with PKCE, nonce and JWKS validation. Conformance against the commercial IdPs your buyers run is not yet recorded, so this row does not claim it. |
| Enterprise-managed agents | scoped | The engine accepts a signed authorization decision from the identity provider your customer already runs, and mints a token to match, with no per-tenant secret mailed around. Built to the finished profile and driven against a signing identity provider we run ourselves; a capture from a live commercial tenant is not yet recorded, so this row does not claim it. How it is checked → |
Absent from this table is absent from the product today. If a capability you need is missing, ask us. The answer might be a date.
Give an agent a token that expires in minutes.
Your agent signs in as the person using it. The token it gets back names the API it may be handed to. It runs on a short clock. It dies when you revoke it. And every door tells the same story about it.
Where the decision comes from your customer’s own identity provider rather than from your app, that is the enterprise-managed road →
Point a better-auth client at it.
Your side of the integration is a base URL. The client stays the stock better-auth package you already use: it points at your Signet instance instead of your current vendor, and the calls you have written keep working. That holds whether the instance is one we host or one running inside your walls under an enterprise licence: the wire is the contract, and it does not change when the engine changes address.
import { createAuthClient } from "better-auth/client";
// Your existing better-auth client: point baseURL
// at your Signet instance. The wire is the contract.
export const authClient = createAuthClient({
baseURL: "https://auth.example.com/api/auth",
});
// The same calls you already write. They just work.
await authClient.signIn.email({ email, password });- The instance checks itself before it serves. Its configuration is validated with no network at all, then validated again against the live URL; both checks are in the engine, so there is no external tooling to install or trust.
- Nothing secret sits in the config file. The signing secret and the database URL are supplied to the process separately, and the schema applies itself on first boot.
- You point your better-auth client at
/api/auth. That is the whole change on your side: one URL. It reads the same hosted or on-prem.
Working in a framework? The quickstart has five literal framework paths: Next.js, React Router v7, Node/Express, Vue 3, and Svelte, plus React and vanilla-client foundations.
What one Signet instance serves.
The routes a live instance answers. Open to read the ledger.
/llms-full.txtTerse and deep machine on-ramps for AI agents. An instance derives its enabled endpoint inventory from the same source as OpenAPI; the marketing companion stays scoped to product and integration guidance.machine
The docs are not a separate site: every deployed instance serves its own /docs, /llms.txt, and inventory-derived /llms-full.txt from inside the engine, so its route reference stays tied to the build you are running.
Appendix
The wire, by surface.
The API reference, distilled to product proof. Every row traces to the repo README.md or to the embedded /docs a running instance serves. If it is not in those, it is not on this page. Open to read the rows.
README.md or to the embedded /docs a running instance serves. If it is not in those, it is not on this page. Open to read the rows.| Surface | Wire tokens | What you get |
|---|---|---|
| Sign-up | sign-up auto_sign_in | Account creation on the certified wire. Flip auto_sign_in and a new user is signed in immediately after sign-up, rather than requiring a separate sign-in. |
| Sign-in | sign-in/email | Email sign-in. The embedded docs use this path as the per-path rate-limit example. |
| Sessions | session expires_in fresh_age | Lifetime defaults to seven days (expires_in) and refreshes on use (update_age); a configurable fresh_age window gates sensitive actions. |
| OAuth + OIDC | social_providers pkce | Social sign-in on the same certified wire: google and github carry built-in defaults, custom providers declare their endpoints, PKCE available. An optional oauth_proxy plugin ships. |
| Password policy | password | 8–128 characters by default; optional password-strength scoring and a tunable hashing cost factor. |
| CLI preflight | init doctor env pull | The same build scaffolds a secret-free config without overwriting, validates config or a live instance, and writes the public client URL without extracting server secrets. |
| Breached-password check | haveibeenpwned | Optional Have I Been Pwned range check. Point the range endpoint at a self-hosted mirror. |
| Verification + reset delivery | delivery smtp.templates dead_letter | Verification codes and reset links leave by signed-JSON webhook (HMAC signature) or SMTP, or not at all. SMTP subjects and plain-text bodies are configurable per flow with strict placeholders; failed sends can dead-letter for replay from the admin surface. |
| Rate limiting | rate_limit | On by default: 100 requests per 10-second window, with per-path override rules. |
| Liveness + machine schema | /health open-api/generate-schema | Confirm liveness at /health; browse the wire's machine schema at /api/auth/open-api/generate-schema. |
Sources: README.md (the surfaces table, the quickstart) and the embedded /docs: read a live instance's copy, served from inside the engine.
Your Postgres. Same build, wherever it runs.
Every user, session, and secret lives in your own PostgreSQL, behind an /admin operator surface you control. Signet is the same build whether we run it or you do: start on a managed instance and, the day you need to, take it onto your own hardware under an enterprise licence, without changing a line of client code. The wire does not change.
Leaving does not require us. pg_dump, pg_restore, boot. An enterprise licence puts the engine in your hands, so if we disappeared tomorrow your auth keeps running, and the wire never changes.
Ownership runs to the configuration too: every setting lives in signet.toml in your own repository, not a hosted console. Configuration is the dashboard →
What the receipt records, and what it does not.
The differential conformance sweep is 280 / 280: every check in the public compatibility profile runs against the reference implementation and against Signet, and the results are compared. The profile counts only checks the reference implementation itself passes; Signet is not graded on checks the reference fails. The compatibility gap (a check the reference passes and Signet does not) is 0.
Separately, end-to-end acceptance is 14 / 14: better-auth’s unmodified client drives real sign-up, session, organization, and two-factor flows. Both runs were recorded 2026-07-25. The receipt is a recorded pointer to those runs, not an implied cryptographic attestation, and every instance serves its own copy so you can verify it yourself.
| Property | Value |
|---|---|
| Compatibility profile | better-auth 1.6.23 |
| Profile version | Signet compatibility profile v1 |
| Differential conformance | 280 / 280 |
| Compatibility gap | 0 |
| End-to-end acceptance | 14 / 14 |
| Recorded | 2026-07-25 |
| Operating envelope | Not published. The max users, sustained request rate, and resource footprint under load have not been measured, so no capacity number is claimed. A measured envelope will be added once recorded. |
Signing up provisions the instance automatically. The process ends in a receipt: a live /health check plus an end-to-end sign-up, sign-in, and get-session smoke against the live URL. Proven from zero on 2026-07-21: health 200, smoke 3/3.
Start on ours. Take it onto yours.
There is no trial build and no cut-down edition. The hosted instance is the same certified build an enterprise licensee runs.