Skip to content

Conversation

@jhrozek
Copy link
Contributor

@jhrozek jhrozek commented Dec 12, 2025

Summary

This PR improves the registry authentication documentation based on hands-on testing with a Kind cluster. The main changes address several issues found during review:

  • The docs incorrectly equated OAuth with JWT tokens - the server actually supports both JWT and opaque tokens via introspection
  • The Kubernetes authentication section had outdated configuration that wouldn't work in practice
  • The kubectl get secret example used a legacy approach that produces tokens incompatible with the documented OAuth setup

Related server changes: stacklok/toolhive-registry-server#298

Changes

OAuth token type support

  • Clarified that OAuth mode supports both JWT tokens (validated via JWKS) and opaque tokens (validated via introspection)
  • Added an example showing opaque token configuration with introspectionUrl
  • Updated the token validation section to explain both validation methods

Kubernetes authentication overhaul

  • Fixed the issuerUrl - K8s tokens use https://kubernetes.default.svc.cluster.local (with the .cluster.local suffix), not https://kubernetes.default.svc
  • Added new configuration fields to the provider table: jwksUrl, authTokenFile, allowPrivateIP
  • Added a client workload example showing how to mount projected service account tokens with a specific audience
  • Replaced the legacy kubectl get secret example with kubectl create token

Minor improvements

  • Added note about WWW-Authenticate header behavior for 401 responses
  • Clarified that scopesSupported is currently only advertised in the discovery endpoint

Testing

Tested in a Kind cluster by deploying the registry server with Kubernetes OAuth authentication enabled. The setup used projected service account tokens with a custom audience (registry-server) to verify that audience-based access control works correctly.

Registry server config:

auth:
  mode: oauth
  oauth:
    resourceUrl: http://registry-api.registry-test.svc.cluster.local:8080
    providers:
      - name: kubernetes
        issuerUrl: https://kubernetes.default.svc.cluster.local
        jwksUrl: https://kubernetes.default.svc/openid/v1/jwks
        audience: registry-server
        caCertPath: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
        authTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
        allowPrivateIP: true

Client workload with projected token:

volumes:
  - name: registry-token
    projected:
      sources:
        - serviceAccountToken:
            audience: registry-server
            expirationSeconds: 3600
            path: token

Verified that clients with tokens issued for the correct audience can access the registry, while clients using the default Kubernetes service account token (wrong audience) are rejected with 401. Also confirmed that requests without tokens or with invalid tokens are properly rejected.

The key finding was that the legacy kubectl get secret approach produces tokens with issuer kubernetes/serviceaccount, which doesn't match the expected issuerUrl. Only the modern kubectl create token approach (or projected tokens) produces tokens compatible with the OAuth configuration.

- Clarify OAuth mode supports both JWT and opaque tokens
- Add introspectionUrl field to provider configuration table
- Add opaque token configuration example using Google
- Update terminology from OIDC-compliant to OAuth-compliant
Move JWT-specific signature verification details under a separate
paragraph that distinguishes between JWT and opaque token validation
methods.
- Update provider config with correct issuerUrl (.cluster.local suffix)
- Add jwksUrl, authTokenFile, and allowPrivateIP fields to config table
- Add client workload example with projected service account tokens
- Replace legacy kubectl get secret with kubectl create token
- Add tip explaining projected tokens vs kubectl create token
- Update "How it works" section to reflect audience-based auth
- Add note about WWW-Authenticate header in RFC 9728 section
- Clarify that scopesSupported is for discovery endpoint advertisement
Copilot AI review requested due to automatic review settings December 12, 2025 17:08
@vercel
Copy link

vercel bot commented Dec 12, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
docs-website Ready Ready Preview Comment Dec 12, 2025 5:08pm

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves the registry authentication documentation based on hands-on testing with a Kubernetes cluster. The changes address critical inaccuracies in the OAuth token support description and Kubernetes authentication configuration, while adding practical examples for client workloads.

Key changes:

  • Clarified that OAuth mode supports both JWT tokens (via JWKS) and opaque tokens (via introspection), not just JWT
  • Fixed Kubernetes authentication configuration with correct issuerUrl, added missing fields (jwksUrl, authTokenFile, allowPrivateIP), and replaced legacy token retrieval commands
  • Added new sections for opaque token configuration and client workload examples with projected service account tokens


1. Workloads in the cluster mount service account tokens automatically at
`/var/run/secrets/kubernetes.io/serviceaccount/token`
1. Workloads mount projected service account tokens with a specific audience
Copy link

Copilot AI Dec 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the "How Kubernetes authentication works" step 1, the phrase "Workloads mount projected service account tokens" could be clearer. Consider revising to "Workloads mount projected service account tokens (configured with a specific audience)" to make it clear that this requires configuration, as shown in the client workload example below.

Suggested change
1. Workloads mount projected service account tokens with a specific audience
1. Workloads mount projected service account tokens (configured with a specific audience)

Copilot uses AI. Check for mistakes.
@jhrozek jhrozek merged commit 0808957 into main Dec 12, 2025
14 checks passed
@jhrozek jhrozek deleted the auth-review branch December 12, 2025 17:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants