zaniiid

Changelog

Dates are 2026. The plan log in tasks/todo.md has the detail behind every entry; the architecture decisions are AD-n in docs/architecture.md.

Server

2026-09-07, Plan 22: CIBA, mix-up defence, and the rights ones (AD-83..86)

  • CIBA (POST /bc-authorize + the CIBA grant): a client authenticates a person who is not at a browser, and they approve on their own device. Poll delivery only.
  • RFC 9207: every authorization response carries iss. Discovery used to advertise that we did not support it.
  • A person can leave an organization themselves; recovery codes can be reissued without disabling two-step verification; a pending email change is visible and cancellable; a passkey can be renamed.
  • Operator visibility: audit search, /manage/v1/stats, /readyz separate from /healthz, and listing plus replay of stuck webhook deliveries.
  • Organizations: a test-webhook, per-client delivery history, self-deletion, and resendable invitations.

2026-09-07, Plan 21: the ten routes an incident would need (AD-78..82)

  • Forced signing-key rotation, with an explicit revoke_previous for a suspected compromise.
  • Operator reissue of an organization API key, behind AD-74's self-service recovery.
  • PATCH /manage/v1/clients/{id}, so first-party clients can be edited like org ones.
  • RFC 7592 client management at /register/{client_id} with a registration access token.
  • GET /orgs/events: an organization exports its own audit trail, paginated.
  • Resend a lost verification email; a client can drop its own consent by a token it holds; an operator can sign a user out without suspending, or delete an account on request.
  • Introspection understands opaque refresh tokens, which used to answer a confident and wrong active: false.
  • {action} path segments replaced by explicit routes: a catch-all segment silently swallows every sibling declared after it, which had caused two real bugs.

2026-09-07, Plan 20: the missing halves (AD-73..77)

  • A client can be edited in place (PATCH /orgs/clients/{id}) instead of delete-and-recreate, which used to discard every consent and token bound to the old client_id.
  • Organization key recovery through a confirmed contact address, single-use, key never emailed.
  • Console pages for members and invitations, protected resources, and the declared model.
  • An agent can withdraw a pending approval; a decision already made returns 409. Decided approvals are visible history on the account page.
  • One user account can be suspended and restored, with sessions and token families revoked and the CAEP account-disabled signal pushed.
  • PATCH for a resource's name and scopes and for a member's role; invitations can be listed and revoked.

2026-09-07, Plan 18: the identity layer an agent company needs (AD-66..72)

  • MCP-ready: RFC 8414 metadata where OAuth clients look, registered protected resources, RFC 8707 resource validated into the token's audience, RFC 9728 metadata per resource.
  • Task-bounded agent grants: a purpose, a number of uses, a deadline and a declared ceiling, approved on the consent screen, carried as tsk, spent per token, revocable, receipted.
  • Shared signals (CAEP/RISC): signed Security Event Tokens pushed or polled, emitted in the same transaction as the change they describe.
  • Ask-my-human approvals: an agent stops, the person decides on their account page, both outcomes receipted; an unanswered request expires refused.
  • Declared model provenance in the agent claim and the public registry, labelled as the operator's own statement.
  • Organizations with members, invitations and an org-wide two-step requirement; new organization scope and org claim.
  • Passwordless accounts for anyone with a passkey, and Arabic hosted pages negotiated from Accept-Language with a saved per-user preference.

2026-09-07, Plan 17: what Google Sign-In had that we did not (AD-62..65)

  • Consent is per permission: a checkbox per optional scope, and the granted subset is what the code, the consent row, the receipt and the tokens all carry.
  • login_hint on /authorize and through PAR; a QR of the device-flow verification URI at /device/qr.svg, advertised as verification_uri_qr.
  • The account page shows the twenty most recent security events about the account; a sign-in from an unfamiliar browser sends one email (new_device_alerts to turn it off).
  • given_name and family_name as optional profile claims; POST /ui/account/export hands the user their own records as JSON, with no credential material in it.

2026-09-05, Plan 16: accountable to others (AD-57..61)

  • Receipt outbox: every self-receipt is an intent row, retried with backoff on ledger stalls; /manage/v1/reconcile names what the ledger lacks.
  • A separate sealed cosigner key countersigns every recorded receipt (/.well-known/zanii-cosignatures.json).
  • The IdP witnesses the ledger: ledger_ops.py witness co-signs append-only tree heads (/.well-known/zanii-witness.json).
  • Sovereignty declaration: hosting region from the cloud, declared sub-processors, daily residency claim, per-mail transfer receipts (/.well-known/zanii-sovereignty.json).
  • Selective disclosure of one field of an age assertion or a consent from the account page.
  • ERC-8004 registration files and signed AgentCVs at /agents/{did}/erc8004.json and /cv.json.
  • Dark mode and writing-direction support on every hosted page.

2026-09-05, Plan 15: agent identity as the product (AD-53..56)

  • Public agent registry /agents/{did} and /profile.json.
  • Proof-carrying consent: cst claim on tokens, POST /introspect (RFC 7662) with the consent behind the token.
  • Every constitution version served by hash; zanii-id verify <did> in the Python SDK.
  • Agent-to-agent login: token exchange between two organizations' agents with mutual, receipted screening.

2026-09-05, Plan 14: SDKs catch up with the server (AD-52)

  • Server unchanged; see SDK 0.3.0.

2026-09-05, Plan 13: bounded by construction (AD-51)

  • Retention sweeps over nine tables, hot-path indexes, bounded feed and paginated admin listings.
  • Statement timeout, body cap, receipt backlog cap, bundle semaphore, own executor for ledger writes.
  • deploy.py --harden: systemd ceilings, uvicorn concurrency cap, journald cap, nginx include.

2026-09-05, Plan 12: the deliberately-left-out list (AD-45..50)

  • Front-channel logout; subject-tag index for relay ingestion; opt-in OpenTelemetry export.
  • Age assurance: 18+ gate at registration, provider hook, age scope.
  • Know-your-agent: org deny lists, screening at token exchange, /orgs/agents/screen.
  • WebAuthn PRF: passkey-wrapped identity key backup.

2026-09-05, Plan 11: the ledger ecosystem inside the IdP (AD-41..44)

  • Sealed signing identity; build and constitution stamps on every receipt; consent and retention receipts.
  • Organization DIDs with domain binding; ldp_vc credentials; evidence packs; sentinel; workload bindings; post-quantum key binding.

2026-09-05, Plan 10: audit remediation and the 2026 surface (AD-33..40)

  • Resend transport fixed; opaque session cookie; client credentials, token exchange, device flow, PAR, DPoP, private_key_jwt, back-channel logout, OID4VCI, passkey conditional UI, JSON logs, request ids, Prometheus.

2026-09-05, Plans 7..9: customer-ready controls, audit

  • Account page, TOTP, lifecycle webhooks, org quotas, console, email-change revert, step-up, terms versioning, operator MFA reset, passkeys, dynamic client registration; UAE-law legal drafts.

2026-08-26..27, Plans 1..6

  • OAuth 2.1 / OIDC core with PKCE, refresh rotation with reuse detection, consent, pairwise subjects per organization, agent activity with offline verification, custody verdicts, ledger watchdog, self-receipting.

SDKs (zanii-id, @zanii-id/sdk, @zanii-id/react, in lockstep)

0.7.0, 2026-09-07

  • CIBA: backchannel_authorize / backchannelAuthorize and a poller that returns denied and expired as answers rather than raising - an unanswered request expires refused, and code that reads a timeout as success is the failure the flow prevents.
  • Approval cancellation, and RFC 7592 self-management for dynamically registered clients (the registration_access_token was previously discarded).
  • OrgClient gains everything Plans 20-22 added: update_client (the most damaging gap - without it, changing a callback URL meant delete-and-recreate, discarding every consent bound to the old client_id), resource and member-role edits, invitation list/revoke/ resend, the audit export, client-initiated consent revocation, the test webhook, delivery history, and organization deletion. signup_organization / signupOrganization is a module function, because it produces the key OrgClient requires.
  • A coverage guard in both packages. docs/openapi.json is a committed contract, and a test now fails when a server route has no SDK counterpart and no recorded decision. The server outran its clients twice in one day; this is what makes the third time noisy.

0.6.0, 2026-09-07

  • The SDKs can now ask for everything the server can do. Audited every route against both clients and closed each gap; the request side had fallen behind the server through Plans 17 and 18, so features shipped that no SDK user could reach.
  • Authorization request: login_hint, resource (RFC 8707) and a task-bounded task grant. The task's four fields are validated in the SDK, so a malformed one fails before the user is redirected rather than as invalid_request after it.
  • resource on client_credentials and on token exchange.
  • Approvals: create_approval / createApproval, get_approval / getApproval, and await_approval / awaitApproval, which polls at the server's interval and returns refused or expired rather than raising - silence is an answer your code must handle.
  • Shared signals: configure_stream, poll_signals, signal_status and verify_security_event (camelCase in TypeScript). Verify before acting: a push endpoint is a URL anyone can POST to.
  • OrgClient: protected resources, members and invitations, declared agent model, require_member_mfa, and RFC 7591 dynamic registration.
  • agent_profile / agentProfile reads an agent's public registry page.
  • Deliberately still absent: the /manage/v1 admin API. It is authenticated by the single global admin token, and an application SDK is the wrong place to invite that token.

0.5.1, 2026-09-07

  • UserInfo was dropping claims the server sends. Python's model had no extra="allow", so given_name and family_name were discarded silently; TypeScript's interface did not declare them. Both now carry given_name, family_name and org, and both keep unknown claims rather than losing them — a new claim should degrade to "untyped", never to "gone".
  • ZaniiClaims / IdTokenClaims gain the same fields plus cst.

0.5.0, 2026-09-07

  • @zanii-id/react: opt-in popup sign-in (popup prop / mode: "popup"). The page stays mounted; the result comes back over a same-origin BroadcastChannel, so a Cross-Origin-Opener-Policy header does not break it. A blocked popup falls back to a redirect, a closed window rejects distinctly, five-minute timeout, and a mobile tab that refuses to close navigates home instead of stranding the user. Redirect remains the default.
  • zanii-id and @zanii-id/sdk carry no changes; the three move in lockstep.

0.4.0, 2026-09-05

  • introspect in both SDKs with typed consent proof; zanii-id verify <did> command (extra [verify]) in Python.

0.3.0, 2026-09-05

  • Client credentials, token exchange with actor tokens, device flow polling at the server's pace.
  • DPoP proofs, private_key_jwt, PAR; logout URL with state; logout token verification and framework handlers for both logout channels.
  • Receipt relay, organization API client, typed act / cnf / age claims.
  • One bounded connection pool (Python) or a timeout on every fetch (TS); reads retried once on 429/5xx with Retry-After; token grants never retried.

0.2.0, 2026-09-05

  • Public-client client_id, revoke auth, step-up options, memoised JWKS, Next refresh route, React completeZaniiSpaLogin, offline_access default.

0.1.3, 0.1.2, 0.1.1, 2026-09-05

  • Lifecycle verify helper; homepage corrected to ids.zanii.agency; Apache-2.0 metadata.

0.1.0, 2026-08-27

  • First release: authorization URL with PKCE, code exchange, refresh, revoke, userinfo, id-token verification, FastAPI / Express / Next helpers, React login button.