Skip to content

Commit 775c133

Browse files
kjgbotclaude
andcommitted
fix(docs/mint-api-key): correct sage scope set — identity:manage:*, not identity:create:*
POST /v1/identities requires relayauth:identity:manage:*. The scope matcher treats 'manage' as implying create/read/write/delete, but not the reverse — so an api-key with identity:create:* cannot call that route. The previous example would succeed at mint and fail at runtime with 403 insufficient_scope. Caught while rotating sage's key during phase 122 wrap-up, 2026-04-23. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent b12cd18 commit 775c133

2 files changed

Lines changed: 20 additions & 3 deletions

File tree

docs/operations/api-key-minting.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ which is the wrong scope set entirely).
2020
./scripts/mint-api-key.sh \
2121
--name sage-relayfile-minter \
2222
--scopes-json '[
23-
"relayauth:identity:create:*",
23+
"relayauth:identity:manage:*",
2424
"relayauth:token:create:*",
2525
"relayfile:fs:read:*",
2626
"relayfile:fs:write:*"
@@ -58,13 +58,23 @@ So sage's api-key needs:
5858

5959
```json
6060
[
61-
"relayauth:identity:create:*",
61+
"relayauth:identity:manage:*",
6262
"relayauth:token:create:*",
6363
"relayfile:fs:read:*",
6464
"relayfile:fs:write:*"
6565
]
6666
```
6767

68+
Note: `POST /v1/identities` requires `relayauth:identity:manage:*`, not
69+
`create:*`. The scope matcher treats `manage` as implying
70+
`create/read/write/delete` (one-way). An api-key with only `create:*`
71+
gets 403 insufficient_scope on the route that demands `manage:*`. The
72+
same check-the-route pattern applies to every other scope string you're
73+
tempted to pick: grep `authenticateAndAuthorizeFromContext` /
74+
`authenticateBearerOrApiKeyAndAuthorize` in the route handler you
75+
intend to call, and match that exact scope string (or a broader
76+
superset).
77+
6878
The relayfile scopes are required because the new identity sage creates
6979
inherits its own scopes from its sponsor's scope set (the api-key's
7080
synthesized claims). Without `relayfile:fs:*`, the minted token would

scripts/mint-api-key.sh

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,17 @@
2121
# Usage:
2222
# ./scripts/mint-api-key.sh \
2323
# --name sage-relayfile-minter \
24-
# --scopes-json '["relayauth:identity:create:*","relayauth:token:create:*","relayfile:fs:read:*","relayfile:fs:write:*"]' \
24+
# --scopes-json '["relayauth:identity:manage:*","relayauth:token:create:*","relayfile:fs:read:*","relayfile:fs:write:*"]' \
2525
# --to-gh-secret AgentWorkforce/cloud:SAGE_RELAYAUTH_API_KEY \
2626
# --revoke-prior ak_3a7317be58de40f39ef18028393fd0f9
2727
#
28+
# Scope-picking note
29+
# Scope actions are NOT commutative. The matcher treats `manage` as
30+
# implying `create/read/write/delete`, but not the reverse — an
31+
# api-key with `identity:create:*` cannot call a route that requires
32+
# `identity:manage:*`. Always check the required-scope string at the
33+
# route you need to call (see docs/operations/api-key-minting.md).
34+
#
2835
# Common flags:
2936
# --name <string> Required. api-key name (operator-readable).
3037
# --scopes-json <json-array> Required. JSON array of scope strings.

0 commit comments

Comments
 (0)