Noizu.MCP.Auth.Server.Upstream.OIDC (Noizu MCP v0.1.6)

Copy Markdown View Source

Optional fallback Noizu.MCP.Auth.Server.Upstream: run an OIDC authorization-code round trip against the IdP ourselves.

Only for a host with no browser session to reuse. Prefer Noizu.MCP.Auth.Server.Upstream.HostSession — a host that already logs people in should not grow a second login with its own session, its own callback, and its own bugs.

upstream: {Noizu.MCP.Auth.Server.Upstream.OIDC,
           issuer: "https://auth.derobot.is/application/o/myapp",
           client_id: System.fetch_env!("OIDC_CLIENT_ID"),
           client_secret: {MyApp.Secrets, :oidc_secret},
           redirect_uri: "https://app.example.com/oauth/callback",
           authorization_endpoint: "...", token_endpoint: "...",
           scope: "openid profile email"}

What is deliberately not sent upstream

No RFC 8707 resource parameter. Authentik's support for it is unconfirmed, and it would not matter if it were: the upstream token is exchanged here, read for its sub, and discarded. It is never presented to an MCP client and never reaches a resource server, so there is no audience to narrow. Sending an unsupported parameter to an IdP that rejects unknown parameters would break the login for no benefit.

Also not sent: anything the MCP client supplied. The downstream request's PKCE verifier, scope and resource belong to our grant, not to the upstream one; this leg runs its own PKCE.

Options

  • :client_id (required), :client_secret (binary, {mod, fun}, or fun/0)
  • :redirect_uri (required) — must be registered with the IdP
  • :authorization_endpoint / :token_endpoint (required — discovery is the host's job, so a release does no network I/O at boot)
  • :scope — default "openid profile email"
  • :subject_claim — which ID-token claim becomes the subject, default "sub"
  • :fetcher{mod, fun} for the token exchange, so this is testable and :req stays optional. Defaults to Noizu.MCP.Auth.Server.CIMD.ReqFetcher's transport when :req is available.