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:reqstays optional. Defaults toNoizu.MCP.Auth.Server.CIMD.ReqFetcher's transport when:reqis available.