registry/internal/api/handlers/v0/auth
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Radoslav Dimitrov 9e762b03c7
docs(auth): document fine-grained PAT permission for org publishing (+ pagination-cap test) (#1435)
Follow-up to #1383, surfaced while validating that change end-to-end
against staging.

## Why

#1383 hardened org-namespace publishing to require Owner (`admin`) role,
read via `GET /user/memberships/orgs`. Validating on staging revealed a
gap: the docs only mention the classic `read:org` scope, but a
**fine-grained PAT** (GitHub's recommended token type) needs a
*different* permission to expose org membership. Without it, GitHub
returns no org memberships for the token, so the exchange silently
grants only the personal namespace — with no hint why org publishing
"doesn't work."

This is **not** a code bug (the behavior is fail-closed and correct
given GitHub's response); it's a documentation/UX gap.

## What

- **Docs** (`authentication.mdx`, `github-actions.mdx`): spell out both
token types —
  - Classic PAT → `read:org` scope
- Fine-grained PAT → **Organization permissions → Members → Read-only**
(the equivalent), noting a fine-grained PAT is bound to a single
resource owner.
  - Also clarified `read:user` is not required.
- **Test** (`github_at_test.go`): cover the `maxOrgMembershipPages`
pagination cap — when every page is full, the exchange **fails closed**
(no token) rather than returning a possibly-truncated org grant. This
path was previously untested.
- **Comment** (`github_at.go`): qualify the `X-GitHub-SSO` 403 check as
best-effort — we have not confirmed the memberships *list* endpoint
emits that header on SSO enforcement (it may just omit the org). The
check is safe either way, but the comment no longer overstates it as a
guarantee.

## Verification (live, against staging)

Confirmed by exchanging real tokens for `rdimitrov` on
`staging.registry.modelcontextprotocol.io`:

- **Classic `read:org` PAT** across 16 real org memberships → the JWT
granted exactly the 8 **admin** orgs + personal namespace, and **zero**
of the 8 **member** orgs (incl. `stacklok`, `modelcontextprotocol`) —
the core #1383 behavior, working.
- **Fine-grained PAT**: without Members:read → personal namespace only
(fail-closed); after adding Members:read → the org (Owner) namespace is
granted. This is what the new docs describe.

No runtime behavior change here beyond the added test; the docs and
comment are the substance.

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 18:48:56 -04:00
..
common.go refactor: rename readBody to readErrorBody and cap body size (#1246) 2026-05-04 07:09:57 -04:00
common_test.go security: fix open redirect and add small hardening (#1227) 2026-04-29 19:14:00 -04:00
dns.go fix(auth): better DNS verification errors and wrong-selector hint (#1202) 2026-04-25 11:22:06 -04:00
dns_test.go security: fix open redirect and add small hardening (#1227) 2026-04-29 19:14:00 -04:00
github_at.go docs(auth): document fine-grained PAT permission for org publishing (+ pagination-cap test) (#1435) 2026-07-10 18:48:56 -04:00
github_at_internal_test.go fix(auth): grant org namespace only to org Owners, not all members (#1383) 2026-07-10 17:05:47 -04:00
github_at_test.go docs(auth): document fine-grained PAT permission for org publishing (+ pagination-cap test) (#1435) 2026-07-10 18:48:56 -04:00
github_oidc.go refactor: rename readBody to readErrorBody and cap body size (#1246) 2026-05-04 07:09:57 -04:00
github_oidc_test.go auth: bind GitHub OIDC token exchange to a per-deployment audience (#1229) 2026-04-29 20:27:26 -04:00
http.go fix(auth/http): extend SSRF blocklist to IPv6 6to4/NAT64/site-local prefixes (#1250) 2026-05-04 09:41:23 -04:00
http_internal_test.go fix(auth/http): extend SSRF blocklist to IPv6 6to4/NAT64/site-local prefixes (#1250) 2026-05-04 09:41:23 -04:00
http_test.go security: fix open redirect and add small hardening (#1227) 2026-04-29 19:14:00 -04:00
main.go Introduce v0.1 version of the API (#658) 2025-10-14 11:04:48 +03:00
none.go Replace / with - for operation IDs (#660) 2025-10-14 15:26:43 +03:00
none_test.go Changes on the server.json format and the API (#562) 2025-09-29 23:30:35 +03:00
oidc.go auth/oidc: support slice-typed extra claims via overlap match (#1238) 2026-05-04 06:24:34 -04:00
oidc_internal_test.go auth/oidc: test slice-typed extra claims comparison (#1245) 2026-05-04 06:52:12 -04:00
oidc_test.go Stop pinning Go to patch versions, use stable in CI (#1137) 2026-04-09 11:57:21 -04:00