AuthorizationNEW · FastMCP

Authorization controls what authenticated users can do with your FastMCP server. While authentication verifies identity (who you are), authorization determines access (what you can do). FastMCP provides a callable-based authorization system that works at both the component level and globally via middleware. The authorization model centers on a simple concept: callable functions that receive context about the current request and return True to allow access or False to deny it. Multiple checks combine with AND logic, meaning all checks must pass for access to be granted.

Auth Checks

An auth check is any callable that accepts an AuthContext and returns a boolean. Auth checks can be synchronous or asynchronous, so checks that need to perform async operations (like reading server state or calling external services) work naturally.

FastMCP provides two built-in auth checks that cover common authorization patterns.

require_scopes

Scope-based authorization checks that the token contains all specified OAuth scopes. When multiple scopes are provided, all must be present (AND logic).

require_roles

Scopes are standardized, so require_scopes works the same everywhere. Roles and groups are not part of OIDC, so every identity provider puts them under a different claim. require_roles handles the comparison and takes an extract callable that tells it where to look.

Multiple roles are required together, matching require_scopes. A token whose claims lack the path entirely is denied rather than raising, so the extractor can index directly. Keeping the claim path at the call site means any provider works, including ones with unusual shapes. Common locations:

ProviderExtractor
Keycloaklambda c: c["realm_access"]["roles"]
Microsoft Entralambda c: c["roles"]
AWS Cognitolambda c: c["cognito:groups"]
Auth0lambda c: c["permissions"]

Verify the claim against your own tenant before relying on it. Auth0’s namespaced custom claims are configured per tenant, and Entra emits roles or groups depending on the app manifest.

Checking Other Claims

require_roles is a convenience for the common case. AccessToken.claims holds every claim from the token, so gating on anything else needs no special API — just an auth check that reads it.

The same caveat applies: a check like this is opaque, so it suppresses scope disclosure for its siblings.

restrict_tag

Tag-based restrictions apply scope requirements conditionally. If a component has the specified tag, the token must have the required scopes. Components without the tag are unaffected.

Combining Checks

Multiple auth checks can be combined by passing a list. All checks must pass for authorization to succeed (AND logic).

Custom Auth Checks

Any callable that accepts AuthContext and returns bool can serve as an auth check. This enables authorization logic based on token claims, component metadata, or external systems.

Async Auth Checks

Auth checks can be async functions, which is useful when the authorization decision depends on asynchronous operations like reading server state or querying external services.

Sync and async checks can be freely combined in a list — each check is handled according to its type.

Error Handling

Auth checks can raise exceptions for explicit denial with custom messages:

  • AuthorizationError: Propagates with its custom message, useful for explaining why access was denied
  • InsufficientScopeError: A subclass of AuthorizationError raised by AuthMiddleware when the denial is a missing scope; it names the scopes the caller needs
  • Other exceptions: Masked for security (logged internally, treated as denial)

Component-Level Authorization

The auth parameter on decorators controls visibility and access for individual components. When auth checks fail for the current request, the component is hidden from list responses and direct access returns not-found.

Server-Level Authorization

For server-wide authorization enforcement, use AuthMiddleware. This middleware applies auth checks globally to all components—filtering list responses and blocking unauthorized execution with explicit AuthorizationError responses. When the denial is specifically a missing scope, the error names the scopes the caller needs.

Component Auth + Middleware

Component-level auth and AuthMiddleware work together as complementary layers. The middleware applies server-wide rules to all components, while component-level auth adds per-component requirements. Both layers are checked—all checks must pass.

Tag-Based Global Authorization

A common pattern uses restrict_tag with AuthMiddleware to apply scope requirements based on component tags.

Signaling Scope Shortfalls

A denial is more useful when it says what would fix it. When AuthMiddleware blocks a call because the token is missing scopes — rather than because some other policy rejected it — it raises InsufficientScopeError, which carries the specific scopes the caller needs in its required_scopes attribute. An agent that reads the error knows exactly which scopes to re-authorize for, instead of retrying blindly against an opaque refusal. InsufficientScopeError subclasses AuthorizationError, so existing handlers that catch AuthorizationError keep catching it and nothing about your error handling has to change to adopt this. Only the scopes the token lacks are named, so re-authorizing accumulates permissions rather than replacing them. A caller holding read that needs read and write is told to obtain write alone, and keeps read through the re-authorization. When several scope requirements fail at once, every unmet scope is reported together — a caller granted them all in one round succeeds on the retry, instead of discovering the next missing scope only after obtaining the first.

This holds across several AuthMiddleware instances too, not just several checks within one. In the tag-based configuration each middleware contributes its own requirement, and the first to find a shortfall reports the requirements of the others alongside its own — so one re-authorization covers the whole chain rather than one layer at a time. A shortfall is reported only when the scope requirement is what actually caused the denial. If you combine checks and a non-scope check rejects the request first — a tenant policy, say — the denial stays a plain AuthorizationError and names no scopes at all. Disclosing a scope requirement for a component the caller could not reach anyway would leak information about components they are not authorized to see. That rule also bounds what gets aggregated. Combining requirements only reaches as far down the chain as the request itself would have gone: it stops at the first layer holding a custom check, since whether that layer would admit the caller is unknown until it runs, and running it early would trigger authorization logic the request had not reached yet. Requirements at or beyond that point sit behind an unverified gate and are left out. So a custom check early in the chain makes the reported set partial, and a caller may need more than one round to satisfy everything. The reported set is complete when the layers ahead are scope-only and conservative otherwise: it may name fewer scopes than the full chain requires, but it never names scopes behind a policy that might reject the caller regardless.

Accessing Tokens in Tools

Tools can access the current authentication token using get_access_token() from fastmcp.server.dependencies. This enables tools to make decisions based on user identity or permissions beyond simple authorization checks.

Reference

AccessToken

The AccessToken object contains information extracted from the OAuth token.

PropertyTypeDescription
tokenstrThe raw token string
client_idstr | NoneOAuth client identifier
scopeslist[str]Granted OAuth scopes
expires_atdatetime | NoneToken expiration time
claimsdict[str, Any]All JWT claims or custom token data

AuthContext

The AuthContext dataclass is passed to all auth check functions.

PropertyTypeDescription
tokenAccessToken | NoneCurrent access token, or None if unauthenticated
componentTool | Resource | PromptThe component being accessed

Access to the component object enables authorization decisions based on metadata like tags, name, or custom properties.

Imports

Read the original on gofastmcp.com ↗