Skip to content

[gateway] GitHub OIDC token support for custom HTTP MCP server authentication #2901

Closed

Description

@lpcox

Problem

Custom HTTP MCP servers currently rely on static, long-lived API keys or tokens stored in GitHub Secrets and injected via headers: in workflow frontmatter. This has significant security and operational drawbacks:

  • Long-lived secrets — must be stored indefinitely and manually rotated
  • No identity context — MCP server receives an opaque token with no repo/actor/workflow information
  • Secret sprawl — each custom MCP server requires its own stored secret

The request is to support auth.type: github-oidc for custom HTTP MCP servers so the gateway handles OIDC token acquisition and refresh transparently, eliminating stored secrets entirely.

Source: github/gh-aw#23566


Analysis

The feature has been implemented in PR #2878. The following components are involved:

internal/oidc/provider.go — New package that:

  • Acquires JWTs from ACTIONS_ID_TOKEN_REQUEST_URL with the configured audience parameter
  • Caches tokens per audience and proactively refreshes them 60 seconds before expiry (handling the GitHub Actions 5-minute token lifetime)
  • Extracts the exp claim from the JWT without signature verification; falls back to a 5-minute TTL if parsing fails

internal/config/config_stdin.go — Config schema changes:

  • StdinServerConfig gains an Auth *AuthConfig field (json:"auth,omitempty")
  • stripExtensionFieldsForValidation() strips auth before upstream schema validation (extension field)
  • convertStdinServerConfig() copies the Auth config to ServerConfig, defaulting Audience to the server URL when not specified

internal/launcher/launcher.go — Runtime wiring:

  • New() reads ACTIONS_ID_TOKEN_REQUEST_URL + ACTIONS_ID_TOKEN_REQUEST_TOKEN from env and initialises oidc.Provider
  • GetOrLaunch() passes the provider and audience to mcp.NewHTTPConnection() for servers with auth.type: github-oidc
  • Emits a clear error log if a server requires OIDC but the env vars are absent

internal/config/config_core.go — AuthConfig struct definition (type + audience fields).


Proposed Solution

The core implementation is done. Remaining follow-up items to consider:

  1. Integration test coverage — Add an integration test that configures an HTTP MCP server with auth.type: github-oidc and a mock OIDC endpoint, verifying that requests carry a fresh Authorization: Bearer <token> header and that tokens are refreshed before expiry.

  2. TOML config support — Verify or add support for the auth block in the TOML configuration format (config.toml), not just the JSON stdin format. Check internal/config/config_core.go and LoadFromFile() paths.

  3. Schema update — Confirm that the auth object is injected into the upstream MCP Gateway JSON schema (or documented as a gateway extension) so tooling and editors surface it correctly.

  4. Documentation — Update README.md and AGENTS.md with the auth.type: github-oidc configuration option, the required permissions: { id-token: write } workflow permission, and an example configuration snippet.

  5. Error UX — The current error message when ACTIONS_ID_TOKEN_REQUEST_URL is absent is logged but the gateway continues. Consider whether a startup failure is more appropriate when auth.type: github-oidc is configured but the env vars are missing.

Testing

# Example workflow snippet to verify end-to-end
permissions:
  id-token: write

mcp-servers:
  my-server:
    url: "(myserver.example.com/redacted)
    auth:
      type: github-oidc
      audience: "(myserver.example.com/redacted)"
    allowed: ["*"]
  • Confirm gateway requests to my-server include Authorization: Bearer <jwt> with a token whose aud claim matches the configured audience.
  • Confirm the gateway fetches a fresh token when the cached one is within 60 seconds of expiry.
  • Confirm a clear error is surfaced (not a silent failure) when ACTIONS_ID_TOKEN_REQUEST_URL is absent.

Generated by Gateway Issue Dispatcher · ◷

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions