Share an org credential
A manager stores one key for the whole organization; a plain member is refused but still sees the status.
One vendor key for the whole team: stored once by an organization manager, served by resolve to every member, invisible as a record to non-managers.
Goal
As an org manager, store the organization's default credential; as a plain member, get 403 on the inventory but a truthful credential-status.
Cast
| Actor | Raw org role | May |
|---|---|---|
| Olha | admin (a manager role) |
read and write /v1/org-credentials |
| Marko | member |
neither — but credential-status works |
Both tokens must carry the same org_id (User Plane Tokens).
Steps
1. Olha stores the shared key
Call POST /v1/org-credentials — same body shape as a personal create; the owner comes from the token's org_id:
curl -s -X POST "$CREDS_BASE/v1/org-credentials" \
-H "Authorization: Bearer $OLHA_TOKEN" -H "Content-Type: application/json" \
-d '{
"provider_code": "'$CODE'",
"name": "Team key",
"credentials": {"api_key": "sk-org-0123456789abcdef"},
"make_default": true
}'
Expected 201: owner_type: "organization", owner_id = the org UUID, is_default: true, mask instead of the secret.
2. Olha sees it in the org inventory
GET /v1/org-credentials → expected 200 with the record. Another organization's manager would see an empty list — isolation is by owner_id.
3. Marko is refused the inventory
The same list call with Marko's token:
curl -s "$CREDS_BASE/v1/org-credentials" -H "Authorization: Bearer $MARKO_TOKEN"
Expected 403 FORBIDDEN — member is not in the manager list (JWT_ORG_MANAGER_ROLES). Reads are gated exactly like writes: the org's secret inventory is manager business.
4. Marko still learns what he needs
Marko calls credential-status for the provider. Expected 200 with "organization_credentials_configured": true and — assuming Marko has no personal key — "effective_credential_source": "organization": his translations will run on the team key he cannot inspect.
Verified by the test test_s05_share_an_org_credential.