Sign-in and sessions
Open in
Sign-in and sessions is how each principal proves who it is: people by passkey, email link or single sign-on; agents and apps by credential.
Every product serves the same sign-in on every Interface. Filled: what the person sees.
Ways in, for every principal
Sign-in belongs to the product, under your brand, so a UI built on the UI contracts never invents its own.
| Family | What it does |
|---|---|
| Sign-in methods | Passkeys, an email link or code, a password, a social account, and single sign-on per org over SAML or OIDC; the file names which a product offers |
| Sessions and tokens | A session per device, each with its own short-lived access token and a refresh that rotates; listed, named and revoked one by one or all at once |
| Publishable keys | A Key a browser or a mobile app holds in public, bound to its origins, acting only through a signed-in member's session |
| Second factors and step-up | A factor per org policy (everyone, admins, or nobody), and a fresh factor confirmed within five minutes before any Verb stepUp names |
| Recovery and devices | Account recovery by a second factor, a recovery code or an org admin, and devices a person trusts or forgets |
| Org policy | An org admin enforces single sign-on, sets session and idle limits, picks the methods and factors allowed, and links accounts by a checked email domain |
| The product as identity provider | Every product is an OIDC provider for its own UIs and for apps Customers connect, with its keys at /.well-known/ |
| Brand, one level down | A Customer's own customers sign in on that Customer's Domain, under its name and logo; no other brand appears |
| How a UI signs in | The authorization code flow with PKCE, a session cookie on the product's own Domain, and every read and move through the same Verbs as an agent |
| Principal | How it signs in | Where |
|---|---|---|
| A Customer's member | Passkey, email link, password or single sign-on | Your Domain, in your brand |
| A Customer's own customer | The methods the Customer's org allows | The Customer's Domain, in its brand |
| A supplier | Email, then verification, then a passkey | Your Domain, under the supplier account kind |
| A party without an account | A single-use link for one act | The link's own page |
| An app | OAuth, with scopes a Customer's admin consents to | The product's identity provider |
| An agent | A Key, an OAuth 2.1 token over MCP, a signed request, and a mandate | Every Interface |
Example
Members sign in by passkey, email or their org's single sign-on, admins keep a second factor, and a win asks for a fresh one.
import { define } from 'apis.dev'
/** Deals for each Customer, kicked off when won. */
export default define({
name: 'pipeline', domain: 'pipeline.apis.dev',
Company: { name: 'string', domain: 'url!#', deals: '<-Deal.company' },
Deal: {
title: 'string', amount: 'decimal(12, 2)', company: '->Company.deals',
stage: { open: [], qualify: 'opened', win: 'qualified', lose: ['opened', 'qualified'] },
},
auth: {
methods: ['passkey', 'email', 'sso'], // single sign-on per org, when its admin connects one
session: '30d', idle: '7d',
mfa: 'admins', // every admin keeps a second factor
stepUp: ['Deal.win'], // a fresh factor before a win
},
offer: { Team: { month: 49, seats: 5, seat: 9 }, 'Deal.open': 0.001 },
})A win from a session whose factor is an hour old waits for a fresh one.
HTTP/1.1 401 Unauthorized
Content-Type: application/ problem+json
X-Cost: price= 0, currency= "USD"
X-Request-Id: req_2f7a91c04e6b3d58a1c2
{
"type": "https: //pipeline.apis.dev/ docs/ errors#step_up_required",
"title": "Unauthorized",
"status": 401,
"detail": "Deal.win asks for a factor confirmed in the last five minutes.",
"code": "step_up_required",
"stepUp": "https: //pipeline.apis.dev/ auth/ step-up? for= req_2f7a91c04e6b3d58a1c2",
"instance": "req_2f7a91c04e6b3d58a1c2"
}Sessions, factors and connections, state by state
Every move below is a Verb on the product's own API, MCP server and CLI.
An agent with an admin's grant makes each one with no UI.
| Thing | States | What moves it |
|---|---|---|
| A session | active, idle, then expired, signed_out or revoked | A sign-in starts it; its idle and total limits end it; the person or an admin revokes it with Session.revoke |
| An access token | issued, refreshed, expired, revoked | Each refresh rotates it; revoking the session revokes every token under it |
| A factor | enrolled, verified, removed | Factor.enroll and its first use; the person or an admin removes it, and the last one only after another is enrolled |
| A step-up | asked, then confirmed or lapsed | A Verb stepUp names; the person confirms within five minutes, and the move runs once |
| A recovery | requested, verified, then completed or expired | Recovery.start, then a second factor, a recovery code or an admin's approval; every session ends when it completes |
| A single sign-on connection | draft, testing, enforced, disabled | The org's admin connects it, tests it with one member, then enforces it for the org's domain |
| A publishable key | active, rolled, revoked | You or the Customer's admin; a roll keeps the old one answering for its grace period |
Every sign-in, failure, factor change and revoke writes an Event to the org's audit log, so Session.revoked reaches a Watch like any other.
Agents on the access ladder
An agent call stands on one rung, and each Verb names the lowest rung it accepts.
The rung is an input to the one decision, beside the Role and the mandate. A call below the rung answers 401 with the cure: a signature, a mandate, or the person present.
| Rung | What the call carries | What it may do |
|---|---|---|
anonymous | Nothing | Read the offer card and the docs, and pay for one call in the call |
keyed | A Key or an OAuth token | Call the Verbs its Customer's plan and Role allow |
signed | A request signed by the agent's provider, checked against the key directory Signature-Agent names | Calls whose seller wants to know which agent and which provider is calling |
mandated | A mandate presentation from its person | Verbs that commit money or act in the Customer's name |
present | A mandate, with its person signed in and able to step up | Verbs that reserve a fresh factor or a person's own act |
agents.accept sets the rung per Verb. A seller may take orders only from a mandated agent, while its reads stay open to any keyed one.
Crawlers and answer engines meet the same ladder. discovery.crawlers says what an answer engine reads (full, an excerpt or none) and whether a model trainer pays per read or is refused. A crawler that does not sign is anonymous.
What members, admins and agents meet
- A member. Sign in with a passkey on your Domain, see every session and device, and sign out of one or all of them.
- An admin. Connect single sign-on, enforce it, require a second factor, set session limits, and recover a locked-out member.
- A Customer's own customer. Sign in under that Customer's brand and Domain, never yours or the platform's.
- A UI builder. One authorization flow, one session cookie and the Verbs the API serves, so the UI holds no rule of its own.
- An agent. A Key for its Customer, a signature for its provider, a mandate for its person, and a 401 that names the missing rung.
Every principal signs in the same way on every Interface, so no UI and no agent holds a rule the product does not.
Tenancy
Every record belongs to one scope; each Customer gets its own Namespace and its own layer of your file, and can sell to its own customers.
Org graphs
Customer orgs linked to each other: one identity in many orgs, parents over children, partners acting for clients, resellers, and moves between orgs.