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

signet.toml
[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
One Postgres. One revoke path.
KindHoldsHow they arriveThe path
Peoplea sessionemail, passkey, SSOrevoke
Servicesa tokenminted oncerevoke
Agentsa scoped tokenMCP authrevoke

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.

CapabilityStandingThe receipt
Email + passwordbuiltSign-up and sign-in on the certified wire, with the password policy, breached-password check, and reset flow behind it.
Magic linksbuiltSend and verify. A sign-in completed in a real browser.
Email OTPbuiltOne-time codes for sign-in, email verification, password reset, and email change.
Passkeys (WebAuthn)builtReal ceremony cryptography across four routes, exercised against a soft authenticator in tests.
Two-factorbuiltTOTP, 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-inbuiltSign in with, link, and unlink upstream providers on the same wire.
Organisations + invitationsbuiltTwelve organization routes: members, invitations, roles.
API keysbuiltFive routes for issuing and managing programmatic credentials.
Device-code flowbuiltFive routes: sign a CLI or a TV in from another device.
MCP authbuiltFive routes for agent-facing auth; the machine caller is a first-class client.
Agent tokens (audience-bound)builtAn 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 inventorybuiltEnumerate and revoke what is outstanding from the console and the wire.
OAuth2 / OIDC providerscopedSignet 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)scopedBoth 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 agentsscopedThe 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.

minutes, not an hourOne config key sets how long an access token lives, from five minutes to an hour. The OAuth door and the MCP door read that one key, so the two cannot drift apart.one key
named for one APIThe agent names the APIs it will call when it asks for the token, up to eight of them. Ask “is this token good for my API?” about a token bound somewhere else, and the door says no rather than yes. The MCP session doors read the same binding, so the fence holds at the doors the agent itself knocks on.bound
only what the person approvedThe token carries the scopes the signed-in person agreed to, and never more than the client registered for.intersected
revoke means goneOne call kills an agent’s MCP access token, not only an ordinary OAuth one. Before this, that call answered 200 and touched nothing.killed
one answer at every doorIntrospection, userinfo and revoke all read the same credential family. A live agent token reads live at each of them, and reads dead at each of them once you kill it.one truth
A token that named no API stays unrestricted. We say that out loud, because a client that never asked for a binding sees no change.
In every build. No add-on. None of the above needs a feature flag, a plan upgrade or an enterprise line item. It is how the engine mints tokens.

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.

auth-client.ts
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.

/api/auth/*The certified auth wire (sign-up, sign-in, session, OAuth, OIDC), compatible with the stock better-auth client, plus JSONB user metadata with public, private, and browser-owned access boundaries. Differential conformance 280 / 280 with gap 0; separately, end-to-end acceptance 14 / 14.certified
/Front door: the certification receipt rendered as the hero, plus a what/why/three-step-integrate landing.served
/adminOperator dashboard (admin-key gated): users, session revoke and ban, events and audit export, dead-letter replay. Zero-JS, server-rendered, CSRF-protected.yours
/docsEmbedded quickstart plus the generated config reference and lifecycle-ops docs (upgrade, backup, restore, export). Zero external fetch; it travels inside the engine.embedded
/certificationThe compatibility receipt (HTML and JSON, rendered from one source so they cannot drift): conformance 280 / 280, end-to-end acceptance 14 / 14, gap 0, build identity, and an honest operating-envelope and support posture.verifiable
/llms.txt
/llms-full.txt
Terse 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.

SurfaceWire tokensWhat you get
Sign-upsign-up auto_sign_inAccount 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-insign-in/emailEmail sign-in. The embedded docs use this path as the per-path rate-limit example.
Sessionssession expires_in fresh_ageLifetime defaults to seven days (expires_in) and refreshes on use (update_age); a configurable fresh_age window gates sensitive actions.
OAuth + OIDCsocial_providers pkceSocial 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 policypassword8–128 characters by default; optional password-strength scoring and a tunable hashing cost factor.
CLI preflightinit doctor env pullThe 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 checkhaveibeenpwnedOptional Have I Been Pwned range check. Point the range endpoint at a self-hosted mirror.
Verification + reset deliverydelivery smtp.templates dead_letterVerification 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 limitingrate_limitOn by default: 100 requests per 10-second window, with per-path override rules.
Liveness + machine schema/health open-api/generate-schemaConfirm 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.

Hosted instance, then your own metal under an enterprise licence, then sealed or air-gapped: your PostgreSQL at every step, and an exit marked leave without us. HOSTED a managed instance · start here the wire does not change YOUR METAL the same build · enterprise licence your data was always yours SEALED / AIR-GAP needs nothing from the public internet leave without us pg_dump · pg_restore · boot · no cooperation required
The same build at every step. Your users, sessions, and secrets in your own PostgreSQL throughout.

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.

Scope. The compatibility profile is a public, replayable set of checks; the same checks run against the better-auth reference implementation and against Signet, and the gap is the count of checks the reference passes and Signet does not. Gap 0 means that on every check in the profile, a client cannot tell the two apart. It is not a claim that every better-auth route is implemented: the profile is scoped to what those checks exercise, and anything they do not exercise sits outside it. Ask about a specific route and we will tell you plainly whether it is in the profile.

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.

PropertyValue
Compatibility profilebetter-auth 1.6.23
Profile versionSignet compatibility profile v1
Differential conformance280 / 280
Compatibility gap0
End-to-end acceptance14 / 14
Recorded2026-07-25
Operating envelopeNot 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.
Support posture. Self-serve documentation, email support on the Team plan, priority support on Business. Write to support@signetauth.com: you get a reference number back, and the request goes on a queue rather than into one person’s inbox. Any response target is written into a contract; outside one, no SLA is offered or implied.

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.