Repository navigation
Conversation
Introduce the open-core identity model: a just-in-time provisioned users table keyed by (issuer, subject), an agent_members join table, and api_keys that act as one agent. Keys are presented as "Bearer atr_..." on the agent runtime routes alongside IdP JWTs; only a SHA-256 is stored and a key stops validating when revoked, expired, or its creator is disabled. The operator middleware now attaches an authz.Principal for any user from a login-enabled issuer; legacy operator routes keep admin-only semantics via RequireAdmin, while agents, keys and members are authorized per resource through the new pkg/authz seam (WithAuthorizer, WithAuthenticatedRoutes for embedding programs). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Open an agent to find two new tabs: API keys (generate with optional expiry, token shown once with copy, revoke) and Members (list; admins add/remove). A Users page lets admins disable/re-enable users and flip roles. The sidebar hides admin-only pages from members, who now get a membership-filtered agent list and can self-serve keys for their agents. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
`atryum login` signs in through the server's IdP with the OAuth 2.0 device grant and stores the session in ~/.atryum/credentials.json (0600), refreshing silently when it expires. `atryum agent list|create` and `atryum agent key list|create|revoke` drive the new operator endpoints. `atryum setup claude` chains it all: sign in if the server requires it, pick or create the agent, issue a key into ~/.atryum/agent-key (0600), and install the Claude Code hooks pointed at the server with ATRYUM_TOKEN_COMMAND reading that file, replacing any previously installed Atryum hook commands. The Keycloak dev realm now enables the device grant on the public admin client. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…rors Auth0 only allows the device authorization grant on Native applications, so the CLI cannot reuse the SPA admin client there. [[auth]] gains an optional cli_client_id (defaults to admin_client_id) that /api/v1/auth/config advertises and `atryum login` uses. The device-authorization error now quotes the IdP's error and description and names the client, instead of a bare "response had no device_code". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…info Access tokens from Auth0 (and some other IdPs) carry only a sub, so users showed up as "google-oauth2|…". [[auth]] gains email_claims / name_claims lookup lists (defaults cover OIDC, Okta, Keycloak and Entra claim names) and a userinfo toggle (default on): when a verified token has no email, Atryum calls the issuer's discovered OIDC userinfo endpoint once with that token and stores what it learns. UpsertLogin no longer overwrites known email/name with empty values, so later bare tokens keep the enriched row. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Invocations made with an agent API key carry the agent record's own id, but the Invocations page only mapped alias agent_ids and Claude bindings, so they rendered as "Unassociated". Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… hook hardening
Users UI
- Fix the "you" badge stacking under the user's name; it now sits beside
the email, which links into a new per-user view. Rows gain Agents/Keys
links.
- New /ui/users/{id}/agents and /ui/users/{id}/keys tabs listing every
agent the user belongs to (with membership removal) and every API key
they issued across agents (with revocation in place).
- Backed by admin-only GET /api/v1/users/{id}/agents and
GET /api/v1/users/{id}/keys, plus a store join returning a user's
memberships with agent display fields. Key rows carry agent_name.
ATRYUM_HOME as the single root for the Claude hook
- setup claude / hooks install claude-code place the hook script under
$ATRYUM_HOME/hooks/, reference it by absolute path, and bake
ATRYUM_STATE_DIR=$ATRYUM_HOME/agent-hook-state into the hook commands
whenever the home is not the stock ~/.atryum.
- The claude-code target honours CLAUDE_CONFIG_DIR for settings.json.
- Default agent and key names gain the home's basename so two instances
never share an agent record. One env pair per instance:
ATRYUM_HOME=~/.atryum-b CLAUDE_CONFIG_DIR=~/.claude-b atryum setup claude
- The shared hook falls back to $ATRYUM_HOME/agent-hook-state.
Security
- The hook no longer writes atr_ API keys to its on-disk token cache; the
token command already reads them from disk.
- setup claude and the hook refuse to send a bearer over plain http to a
non-loopback host. --allow-insecure-http / ATRYUM_ALLOW_INSECURE_HTTP=1
opts back in.
Tests
- isolateHome clears CLAUDE_CONFIG_DIR and ATRYUM_STATE_DIR so the CLI
tests can never rewrite the live Claude Code settings they run under.
- End-to-end coverage for both new endpoints (403/404/405, revoke cascade
after membership removal), the multi-home install layout, the insecure
transport refusal, and the instance label.
Docs: README, CHANGELOG, claude-code-hook and nono-profile READMEs.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Code reviewReviewed the full diff (46 files, ~6,000 added lines: users/agent-members/api_keys stores, migration 030, the Findings1. Key-authenticated agents carry the
2. Hook uninstall only runs when
3. Postgres published on all interfaces with static credentials — Moving from 4. Agent existence probed before authorization in
5.
6.
Checked and satisfied
Design note (not a defect)
|
This adds 'api keys' directly to atryum open source.
This separates how users and agents authenticate to atryum.
Users authenticate with oauth2. Agents authenticate with their api key.
Authenticated users can create api keys, the keys are bound to a specific agent.
This sets up a few awesome behaviors:
atryum setup claude