# `AttestoMCP.Plug.RequireScopes`
[🔗](https://github.com/XukuLLC/attesto_mcp/blob/v1.0.5/lib/attesto_mcp/plug/require_scopes.ex#L1)

Require scopes on a request authenticated by `AttestoMCP.Plug.Authenticate`.

The plug reads the verified scope list from `conn.assigns` and checks it with
`Attesto.Scope` (the same scope algebra `Attesto.Plug.RequireScopes` uses). It
does not encode MCP policy; routes choose their own required scopes.

    plug AttestoMCP.Plug.RequireScopes, scopes: [AttestoMCP.Scopes.tools_call()]

Rejections are rendered through `Attesto.Plug.OAuthError`: a request that is
not authenticated gets a 401 `invalid_token`, and an authenticated request
that is missing a required scope gets a 403 `insufficient_scope` (RFC 6750
§3.1). Both delegate to `Attesto.Plug.OAuthError`, threading the per-request
`:www_authenticate` / `:send_error` transport hooks
`AttestoMCP.Plug.ProtectResource` injects, so a scope rejection carries the
same RFC 9728 `resource_metadata` challenge and host-controlled error envelope
the authentication rejection does.

This plug reads MCP-specific assign keys (`:attesto_mcp_claims` /
`:attesto_mcp_scopes`, set by `AttestoMCP.Plug.Authenticate`) and a pre-split
granted-scope list; that is why it is a thin wrapper over the OAuthError
renderer rather than a direct use of `Attesto.Plug.RequireScopes` (which reads
the `scope` claim under its own key).

---

*Consult [api-reference.md](api-reference.md) for complete listing*
