docs/python-sdk/fastmcp-utilities-authorization.mdx
fastmcp.utilities.authorizationAuthorization checks for FastMCP components.
Auth checks are callables that receive an AuthContext and return True to
allow access or False to deny it. They can also raise AuthorizationError to
deny with a custom message; other exceptions are masked and treated as denial.
require_scopes <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/utilities/authorization.py#L143" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>require_scopes(*scopes: str) -> AuthCheck
Require all of the given OAuth scopes.
require_roles <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/utilities/authorization.py#L148" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>require_roles(*roles: str) -> AuthCheck
Require all of the given roles, read from the token's claims.
Roles and groups are not part of OIDC, so every identity provider puts them
somewhere different: realm_access.roles on Keycloak, roles on Microsoft
Entra, cognito:groups on AWS Cognito, permissions or a namespaced custom
claim on Auth0. extract receives the token's claims and returns the
caller's roles, which keeps that provider-specific knowledge at the call
site instead of guessing it here.
from fastmcp.server.auth import require_roles
keycloak = require_roles("admin", extract=lambda c: c["realm_access"]["roles"])
cognito = require_roles("admins", extract=lambda c: c["cognito:groups"])
A token missing the claim entirely is denied rather than treated as an
error, so extract may index into the claims without guarding. An
extractor returning a bare string is treated as one role, since a provider
that stores a single role as a scalar is common.
Unlike require_scopes, this check cannot signal a shortfall: OAuth has no
way to request a role, so there is no insufficient_scope challenge to
emit. A role denial is therefore reported as a plain AuthorizationError,
and it suppresses any scope shortfall alongside it — a caller blocked by
their role must not be told to go obtain a scope that would not help.
Scope shortfalls are still reported normally whenever the role check
passes.
Args:
*roles: Roles the caller must hold. All are required (AND logic).extract: Callable mapping the token's claims to the caller's roles.Raises:
ValueError: If no roles are given, which would allow any authenticated
caller and is more likely a mistake than an intent.restrict_tag <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/utilities/authorization.py#L197" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>restrict_tag(tag: str) -> AuthCheck
Require scopes when the accessed component has a specific tag.
scope_requirements <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/utilities/authorization.py#L202" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>scope_requirements(checks: AuthCheck | list[AuthCheck], ctx: AuthContext) -> list[str] | None
Scopes a check list requires but the token lacks, without running it.
Returns None when the list contains any opaque (non-scope) check. Such a
check might deny for a reason unrelated to scopes, and evaluating it here
would run authorization logic — with whatever side effects it carries —
outside its normal place in the chain. Since its verdict is unknown, its
siblings' scopes must not be disclosed either, so the whole list is withheld.
When every check is scope-aware, the result is their combined shortfall, computed purely from the token and component (an empty list means the list is already satisfied). This lets a shortfall be aggregated across authorization layers without evaluating anything that would otherwise be skipped.
run_auth_checks_with_shortfall <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/utilities/authorization.py#L253" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>run_auth_checks_with_shortfall(checks: AuthCheck | list[AuthCheck], ctx: AuthContext) -> tuple[bool, list[str]]
Run auth checks with AND logic, classifying the denial cause.
Returns (authorized, missing_scopes). missing_scopes names every
scope the caller must obtain to satisfy all scope requirements at once:
the union of the shortfalls across every scope-aware check, not just the
first one to fail. Reporting only the first would strand a caller in a
step-up loop — it obtains that scope, retries, and is denied again for the
next — so the union is what makes a single re-authorization converge.
The challenge is withheld entirely (an empty list, which the caller surfaces
as a plain AuthorizationError) unless every non-scope check passes. A
custom policy denial — a tenant check, say — must never be reported as an
insufficient_scope shortfall, and must never name the scopes of a
component the caller could not otherwise reach. To guarantee that, the
opaque checks are all evaluated before any scope is disclosed; a shortfall
is only reported once they have all passed.
An AuthorizationError raised by a check propagates unchanged.
run_auth_checks <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/utilities/authorization.py#L304" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>run_auth_checks(checks: AuthCheck | list[AuthCheck], ctx: AuthContext) -> bool
Run auth checks with AND logic, stopping at the first failure.
AuthContext <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/utilities/authorization.py#L27" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>Context passed to auth check callables.
Attributes:
token: The current access token, or None if unauthenticated.component: The tool, resource, resource template, or prompt being accessed.tool: Backwards-compatible alias for component when it is a Tool.Methods:
tool <sup><a href="https://github.com/PrefectHQ/fastmcp/blob/main/fastmcp_slim/fastmcp/utilities/authorization.py#L40" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>tool(self) -> Tool | None
Backwards-compatible access to the component as a Tool.