AshAuthentication.Phoenix.Oauth2Server.RequireScopePlug (ash_authentication_oauth2_server v0.3.0)

Copy Markdown View Source

Gate a pipeline on OAuth scopes, with spec-shaped errors.

Mount after AshAuthentication.Phoenix.Oauth2Server.BearerPlug — it reads the verified claims that plug put in conn.assigns.oauth_claims:

pipeline :mcp_write do
  plug AshAuthentication.Phoenix.Oauth2Server.BearerPlug,
    oauth2_server: MyApp.Oauth2Server

  plug AshAuthentication.Phoenix.Oauth2Server.RequireScopePlug,
    oauth2_server: MyApp.Oauth2Server,
    scope: "mcp.write"
end

When the bearer token lacks a required scope, the response is the RFC 6750 §3.1 shape — 403 with WWW-Authenticate: Bearer error="insufficient_scope", scope="…", resource_metadata="…" — which is what step-up-capable clients (including MCP clients following the 2026-07-28 spec) use to re-authorize with the scopes they're missing. All missing-or-required scopes are emitted in a single challenge, per the spec's guidance against incremental challenges.

When there are no verified claims at all (the plug ran without BearerPlug, or with required?: false and no token), it responds 401 like BearerPlug would — authorization is required before scope can be evaluated.

Options

  • :oauth2_server (required) — your Oauth2Server config module
  • :scope (required) — a scope string or list of scope strings; the token must carry all of them
  • :description — optional error_description for the challenge

Scope hierarchies

Matching is exact set membership. If your scope catalogue is hierarchical (mcp.admin implies mcp.write), expand the hierarchy into the token's scope at consent/mint time, or write your own plug — the spec requires the server to account for hierarchies, and only you know yours.