Skip to content

Registry API Authentication FAQ

Common questions about authenticating against the Registry API (/api/*, /v0.1/*). For the full authentication model, see Registry API Authentication.

Can I use an IdP token and the static token on the same deployment?

Yes, as of #871. When REGISTRY_STATIC_TOKEN_AUTH_ENABLED=true, the static token is accepted as an additional credential, not an exclusive gate. Valid Okta / Entra / Cognito / Keycloak JWTs, UI-issued self-signed JWTs, and session cookies all continue to work on /api/*. A bearer that doesn't match the static token falls through to the JWT validation pipeline.

Before #871, turning on static-token mode silently broke every non-static-token caller on /api/* with a 401/403 before JWT validation ran.

Do I need to seed MongoDB with mcp-servers-unrestricted/* scope docs for the static token to work?

After #779: Yes, the standard scope-resolution path is used for all static-token keys (including the legacy REGISTRY_API_TOKEN). The auth server resolves each key's groups to scopes via group_mappings in MongoDB. If the group-to-scope mappings are missing, the key will authenticate but carry an empty scope set, which means the registry will treat it as a non-admin caller.

Before #779: No. The registry hard-coded full admin access when the auth server set X-Auth-Method == "network-trusted". Scopes returned in the /validate response were informational only.

Can I give a static token read-only access?

Yes, since #779. Define a key in REGISTRY_API_KEYS whose groups list maps to read-only scopes (e.g., mcp-servers-unrestricted/read). The key will authenticate successfully but will not carry mutating scopes, so the registry treats it as a non-admin caller.

{"ci-readonly": {"key": "<generated-token>", "groups": ["mcp-readonly"]}}

Make sure the group mcp-readonly is mapped to the desired read-only scopes in your group_mappings collection.

Why does the static token not work on /<server>/tools/list?

By design. The static token is only accepted on Registry API paths (/api/*, /v0.1/*). MCP gateway tool invocations always require full IdP authentication regardless of static-token settings. This is a deliberate boundary, not a bug: the static token grants admin-level access on registry metadata endpoints, but tool invocations — which can have real-world side effects — stay gated behind per-user identity and scopes from the IdP.

A curl with -H "Authorization: Bearer $REGISTRY_API_TOKEN" against an MCP gateway path will currently return a 500 wrapping the JWT validation failure. That's a pre-existing error-code bug (separate from #871), not a sign the call should have succeeded.

What status code does a fully invalid bearer get?

Since #871: 401 from the JWT block (detail: "Missing or invalid Authorization header. Expected: Bearer <token> or valid session cookie").

Before #871: 403 from the static-token block (detail: "Invalid API token").

No caller with a valid credential is affected by this change. The status-code shift only applies to bearers that were going to be rejected anyway.

Is my UI-issued JWT usable against /api/*?

Yes, since #871. Before the fix, the Get JWT Token sidebar in the UI produced valid HS256 JWTs that were nonetheless rejected on /api/* when static-token mode was on. After #871 they flow through the same _validate_self_signed_token path as any other UI-issued token, regardless of whether static-token mode is on.

How do I rotate a static token without downtime?

With REGISTRY_API_KEYS (recommended): Zero-downtime rotation is straightforward:

  1. Add a new key entry to the JSON array (the old key stays).
  2. Deploy the updated config. Both keys are now valid.
  3. Migrate clients to the new key at your own pace.
  4. Remove the old key entry and redeploy.

With legacy REGISTRY_API_TOKEN only: There is still a cutover window during which old clients are rejected while new clients have yet to pick up the new value. Mitigations:

  • Roll out the new token value to clients first, then flip the server value.
  • Or accept a brief 401/403 window and notify callers.
  • Or migrate to REGISTRY_API_KEYS for zero-downtime rotation.

Where do I see the current values in the UI?

The Settings → Authentication page shows:

Field Label Behavior
registry_static_token_auth_enabled Static Token Auth Enabled Displayed as true / false
registry_api_token Registry API Token Masked
registry_api_keys Registry API Keys Masked
m2m_direct_registration_enabled M2M Direct Registration Enabled Displayed as true / false (from #851)

The field registry is defined in registry/api/config_routes.py.

What's the roadmap?

Three improvements, landing in order on top of each other:

  1. #871 — coexistence (shipped): static token and JWT auth work together on /api/*.
  2. #779 — multi-key static tokens (shipped): replaces the single REGISTRY_API_TOKEN with a REGISTRY_API_KEYS JSON object, each key carrying its own groups. Lets operators give scripts the minimum privilege they need. Zero-downtime rotation is built in.
  3. #826 — external user access tokens: lets a frontend application that has its own IdP integration call the Registry API on behalf of a logged-in user, either via /userinfo group enrichment (Solution A) or a new token-exchange endpoint (Solution B).

See the full design in Registry API Authentication.