Latchkey

Changelog

What shipped.

  1. orgs

    Orgs on anythink tenants, tenant and org delete, and a Sandboxes page

    An org can move under another as a tenant subtree — tenants, clients, grants and settings in one step, with a dry run first, a flat move for orgs with their own tenant tree, and a way back out (PR latchkey#292). An owner can delete an archived tenant and staff can delete an org; a delete is final but recorded, and every delete takes ?dry_run=1 (PRs latchkey#295, latchkey#296). In the console, Create organization starts from an anythink tenant you administer (PR ui#53), a Sandboxes page lists an org’s sandboxes and the admin view nests them under their org (PR ui#55), deleted orgs leave the org list and search (PR ui#52), and staff and site admins follow the configured house org (PR ui#51).

  2. auth

    One-click MCP sign-in, generated refs and confidential-client sign-in

    MCP clients such as Claude Code, Cursor and Codex sign a person into a house MCP server in one click: every issuer host serves RFC 8414 metadata and open dynamic registration, Client ID Metadata Documents are accepted, resource= binds the token’s audience, and people approve each app on a consent page and can revoke it later (PRs latchkey#170, latchkey#171, latchkey#172, latchkey#174, latchkey#175). An org lists the APIs it owns with PUT /org/{slug}/resources (PR latchkey#208). New orgs and tenants are named by a generated ref that never changes, so a rename no longer breaks a product’s authorization; existing orgs move onto refs with one call and can move back (PRs latchkey#155, latchkey#158, latchkey#159, latchkey#160). A server-side app holding a secret can run the browser authorization-code flow, authenticating at the token endpoint for the code and every refresh.

  3. org api

    Client scoping, the products claim and org rename

    A confidential client can be scoped to a set of tenants and role prefixes (POST /org/{slug}/clients/scope, or scope on the client PUT), so a product’s backend manages only its own roles on its own tenants; refusals say why, and GET /org/{slug}/clients?unscoped=true lists the clients still unscoped (PR latchkey#117). A tenant records the products it has turned on (PUT /org/{slug}/tenants/{tenant}/products), every token for the tenant carries them in a products claim, and a tenant.products_set webhook fires on change — so a product refuses a tenant that has not enabled it without calling anything (PR latchkey#116). An org’s owner can rename it with POST /org/{slug}/rename; the old slug keeps resolving to the same org and no one else can claim it (PR latchkey#125).

  4. machines

    Machine credentials, and staying signed in

    A person can register a machine for an org — a CLI signed in with the device flow, terraform login, or a client-secret machine for scripts — and its tokens name the person who operates it, so a product authorizes a machine as its operator. The console’s org page lists an org’s machine credentials and revokes them (PR ui#50). Consoles built on the shared app shell refresh the access token ahead of expiry, once across tabs, so people are no longer signed out when the hour-long token lapses (PRs ui#40, ui#54).

  5. auth

    GitHub sign-in, passkey scope, fresh-login clients and tenant invitations

    Settings → Sign-in offers GitHub as a sign-in method, with Settings → GitHub for the GitHub App and its proxy (PRs ui#38, ui#42, ui#43). An auth domain can set its passkey scope (rp_id) (PR ui#41). A client can require a fresh login every time instead of riding an existing session (PR ui#44), and the store-review sign-in takes a test-identity domain (PR ui#47). Tenants have an Invitations tab and their own tenant_invite email template (PR ui#37). Publishable keys may be unrestricted, and the key list shows each key in full (PR ui#39).

  6. console

    Email deliverability, delivery webhooks, people tables and bulk invites

    Settings → Email → Activity runs a deliverability check on the org’s sender, and delivery events can be sent to a webhook you configure, with an event feed in the console (PRs ui#29, ui#30). The People page has filterable people and event tables, each person has a detail page, and invites go out in bulk (PRs ui#31, ui#33, ui#34). Missing pages answer with a real 404 and errors with an error page instead of a blank screen, and empty lists say so plainly (PRs ui#32, ui#36).

  7. console

    Sandboxes, role levels, secret rotation and browser keys

    Orgs and tenants have a sandbox beside production, and a production/sandbox switch on the org and tenant pages flips between them (PRs ui#22, ui#23, ui#26). Settings → Roles lets a role extend a level (PR ui#25). A client can flip between public and confidential and rotate its secret from the console, clients can be deleted, and browser (publishable) API keys are issued per org (PRs ui#24, ui#27, ui#28). Clients that ship through an app store get a review-login setting with its own sign-in section, and the sign-in code email has its own template tab (PRs ui#16, ui#17, ui#18).

  8. auth

    Session links, passkeys, and magic links hardened

    Product-minted sign-in links redeem at /oauth/go and are single-use, expiring and revocable (PR #45). Passkeys sign people in and enrol after a magic-link sign-in, with a hosted management page (PR #34). Magic-link tickets are hashed at rest, so nothing stored is a live link, and the confirm page consumes on POST so mail scanners cannot burn one (PR #44). Refused sign-ins are recorded and shown on the console’s Attempts page (PR #40).

  9. org api

    Org API indexes, paging and delivery visibility

    Clients, members, sessions and users are single filtered queries with ?limit=&offset= instead of registry scans. GET /org/{slug}/mail/activity folds the login-ticket log into per-email created / sent / consumed / expired rows, so “sent 2m ago — not used” is answerable without ticket ids.

  10. mail

    Per-org email templates

    Login and invite emails are per organisation: a strict variable allowlist, the link injected by the service, and a console editor with a variable-aware preview. Sender credentials live in org settings, sealed under KMS, with the platform sender as the fallback.