---
title: "Sign-in and sessions"
url: /identity/sign-in
---

# Sign-in and sessions

> How every principal proves who it is: sign-in methods, sessions, publishable keys, second factors and step-up, recovery, and agents on the access ladder.

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.

**From sign-in to a held move.** A person on your Domain.

1. Sign in: passkey or SSO. Or refused: no factor.
2. Session (a method passes): on your Domain. Or second factor: if policy asks.
3. Call (a short token): under the session.
4. Step-up (a Verb that asks): a fresh factor. Or 401: step-up asked.
5. The move runs (confirmed): once.

Every product serves the same sign-in on every Interface.

## Ways in, for every principal
Sign-in belongs to the product, under your brand, so a UI built on [the UI contracts](/interfaces/ui-contracts.md) 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](/reference/platform.md#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/openid-configuration` |
| 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](/every-product.md) |

### 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.

```ts title="definition.ts"
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 title="Response"
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](/reference/platform.md#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](/identity.md#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](/reference/contract.md#mandate) 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.