tai42-contract only and never imports the
skeleton. It is an identity provider:
AccountsProvider subclasses IdentityProvider, so the session tokens it mints
are validated back through the same validate_token seam every other credential
passes through. Installing an accounts provider adds login flows, not a second
enforcement path.
Implement the contract
SubclassAccountsProvider and implement its three methods plus the inherited
validate_token:
login_methods()— declare the login methods you offer as metadata (see below). Cheap and side-effect free; it is config-derived data, not I/O.needs_bootstrap()— a live store read:Truewhile the deployment still needs its first (owner) account,Falseonce it exists. A provider with no bootstrap concept returnsFalse.revoke_session(token)— revoke the session behindtokenif it is yours; returnFalsefor a token that is not yours (wrong prefix, unknown) so the application’s single logout route can dispatch across every provider. Raise only on a backend failure.validate_token(token)(inherited) — resolve one of your own session tokens to itsAuthIdentity,Noneotherwise.
tai-sess-, to
distinguish them from sk- API keys at a glance — and store only a hash, with a
TTL. Token storage, hashing, and lifetime are entirely provider-owned; the
contract never parses a token’s contents.
Declare login methods as metadata
A provider declares how a human signs in as data; the generic login screen renders it. Exactly two shapes exist:FormMethod— a credentials form. It carries atitle, a list ofFormField(each with aname,label, and asecretflag for password inputs), asubmit_paththe renderer POSTs the fields to as JSON, and apurposeoflogin,bootstrap, orinvite— the renderer shows the bootstrap form only when the deployment reports bootstrap, and the invite form only when the login URL carries an invite token.ButtonMethod— a redirect button carrying alabel, optional inline-SVGicon, and anhrefthe renderer navigates to (for example an OIDC authorize route).
submit_path and href are validated to same-origin paths under /api/ —
an absolute or ..-climbing target is rejected — so a provider can never steer
the pre-auth screen off the deployment origin.
The login and lifecycle HTTP routes themselves (the submit endpoints, the
redirect and callback flows, the bootstrap and invite handlers) are shipped by
your plugin as ordinary router modules. The contract carries only the metadata
that lets the generic screen render them.
Policy is applied through injected admin services
An accounts provider mutates account records in its own store, but it never touches application-owned policy directly. The factory receives anAccountsProviderSettings whose admin is the application’s
AccountsAdminServices — the only way plugin code reaches policy state:
apply_role(user_id, role)— copy a role template into the user’s enforced policy.remove_policy(user_id)— delete the user’s policy (and revoke keys it owned).set_user_disabled(user_id, disabled)— flip the disabled marker.
Register on import
register_accounts_provider registers your factory into both the accounts
registry and the identity registry under one name — an accounts provider is the
token answerer for its own sessions, so registering into only one would make
sessions mintable but not validatable:
Ship the store’s schema and its apply command
A store-backed accounts provider owns its own schema. Ship the DDL and a small apply command in your plugin package, and document how to run it in your repository’s README — the deployment applies your schema per your own instructions before enabling the provider. The skeleton stays out of it: it never runs a plugin’s migrations and never documents a specific provider’s apply command. Keep the concrete DSN, settings, and apply steps in your repo, not on this site.Load it
The host loads the provider by naming its module(s) underlifecycle_modules
(registration) and routers_modules (its login/lifecycle routes), and listing
its registration name in the ordered
ACCESS_CONTROL_AUTH_PROVIDERS chain. To surface a
users-admin page in the Studio, ship it as a studio plugin as
well — router modules mount API routes, not UI.
Shipped implementations
Shipped accounts providers appear in the ecosystem catalog, each linking to its own repository.See also
- Accounts — the session, ownership, and role model.
- Sign in to the Studio — the login screen your metadata drives.
- Author an identity provider — the validate-only base an accounts provider extends.
- Python SDK reference — the
AccountsProvider,LoginMethod, and registry surface.

