For auth providers, credential vault, and scope challenges, see the Authentication overview.
Overview
The Authorities system provides declarative, built-in authorization on tools, resources, prompts, and skills. Instead of writing imperative access-control checks inside every handler, you declare who can access what directly in decorator metadata. Authorities supports four authorization paradigms:| Paradigm | Description | Use Case |
|---|---|---|
| RBAC | Role-based and permission-based checks | ”Only admins can delete users” |
| ABAC | Attribute-based conditions with operators | ”Only users in the engineering department” |
| ReBAC | Relationship-based checks via an external resolver | ”Only the owner of this document” |
| Custom | Extend with your own evaluator functions | ”Only requests from allowed IP ranges” |
allOf, anyOf, and not combinators to express complex policies.
The system consists of two packages:
@frontmcp/auth— Core types, evaluation engine, registries, and errors@frontmcp/sdk— Built-in flow stages (checkEntryAuthorities,filterByAuthorities) for enforcement, configured via@FrontMcp({ authorities })metadata
Quick Start
Add theauthorities config to your @FrontMcp() decorator and set authorities on any entry.
delete_user, the checkEntryAuthorities flow stage throws an AuthorityDeniedError with MCP error code -32003 before the handler executes.
JWT Claims Mapping
Every identity provider stores roles and permissions in different JWT claim paths. TheclaimsMapping option tells the engine where to find them.
- Auth0
- Keycloak
- Okta
- Cognito
- Frontegg
Auth0 uses namespaced custom claims for roles and the standard
permissions claim.claimsMapping supports dot-path traversal (e.g., realm_access.roles) and also direct key lookup for namespaced claims containing dots (e.g., https://myapp.com/roles).
Custom Claims Resolver
For more complex scenarios, provide aclaimsResolver function instead of (or in addition to) claimsMapping. It takes precedence when both are configured.
Authority Profiles
Profiles are named, reusable authorization policies registered at the server or app level. They let you writeauthorities: 'admin' instead of repeating the full policy object on every entry.
Registering Profiles
Using Profiles on Entries
RBAC
Role-based access control checks the user’s roles and permissions against required values.Roles
Permissions
Permission checks follow the sameall/any semantics as roles.
Combining Roles and Permissions
When bothroles and permissions are specified in the same policy, they are combined with AND by default.
ABAC
Attribute-based access control evaluates conditions against a context envelope with four namespaces:| Prefix | Source |
|---|---|
user.* | Resolved user object (sub, roles, permissions, claims) |
claims.* | Raw JWT claims |
input.* | Tool/prompt input arguments |
env.* | Runtime environment variables |
Simple Match
Thematch field provides simple equality checks. All pairs must match (AND semantics).
Advanced Conditions
Theconditions field supports a rich set of operators for more complex checks.
Operator Reference
| Operator | Description | Value Type |
|---|---|---|
eq | Strict equality (===) | any |
neq | Strict inequality (!==) | any |
in | Value is in the array | array |
notIn | Value is not in the array | array |
gt | Greater than | number |
gte | Greater than or equal | number |
lt | Less than | number |
lte | Less than or equal | number |
contains | String includes substring, or array contains value | string/array |
startsWith | String starts with prefix | string |
endsWith | String ends with suffix | string |
exists | Value is defined (true) or undefined (false) | boolean |
matches | Regular expression match | string (regex) |
Dynamic Value References
Condition values can reference runtime data instead of using static literals.| Ref | Description |
|---|---|
{ fromInput: 'fieldName' } | Resolves to the value of the named tool input argument |
{ fromClaims: 'dot.path' } | Resolves to a value from the user’s JWT claims via dot-path |
ReBAC
Relationship-based access control delegates checks to an external authorization backend (e.g., SpiceDB, OpenFGA, or a custom database query).Configuring a Relationship Resolver
First, implement theRelationshipResolver interface and pass it in the authorities config.
Using ReBAC on Entries
Multiple Relationships (AND)
Pass an array of relationship checks. All must pass.Resource ID Sources
| Source | Example | Description |
|---|---|---|
| Static string | resourceId: 'site-123' | Hardcoded resource ID |
| From input | resourceId: { fromInput: 'siteId' } | Resolved from tool input arguments |
| From claims | resourceId: { fromClaims: 'user.orgId' } | Resolved from JWT claims via dot-path |
Combinators
For complex authorization requirements, compose policies usingallOf, anyOf, not, and the operator field.
allOf (AND)
All nested policies must pass.anyOf (OR)
At least one nested policy must pass.not (Negation)
Invert a nested policy.operator: ‘OR’
By default, top-level fields in a single policy object are combined with AND. Setoperator: 'OR' to use OR instead.
Nested Composition
Combinators nest freely for arbitrarily complex policies.Custom Evaluators
Extend the authorities system with your own evaluators for domain-specific checks.Defining an Evaluator
Implement theAuthoritiesEvaluator interface.
Registering Evaluators
Using Custom Evaluators in Policies
Reference evaluators under thecustom field. The key must match the evaluator name.
custom evaluator '<name>' is not registered.
Discovery Filtering
List flows automatically filter entries based on the caller’s authorities via the built-infilterByAuthorities stage. When a client calls tools/list, resources/list, or prompts/list, entries the user is not authorized to access are silently removed from the results.
| Flow | Stage | Runs After |
|---|---|---|
tools:list-tools | filterByAuthorities | findTools |
resources:list-resources | filterByAuthorities | findResources |
prompts:list-prompts | filterByAuthorities | findPrompts |
Hooking into Authority Checks
Authority enforcement runs as native flow stages, not plugin hooks. This means developers can hook into them withWill, Did, and Around decorators — just like any other flow stage.
Flow Stages Reference
| Flow | Stage | Purpose |
|---|---|---|
tools:call-tool | checkEntryAuthorities | Enforce before tool execution |
tools:list-tools | filterByAuthorities | Filter unauthorized tools from discovery |
resources:read-resource | checkEntryAuthorities | Enforce before resource read |
resources:list-resources | filterByAuthorities | Filter unauthorized resources from discovery |
prompts:get-prompt | checkEntryAuthorities | Enforce before prompt execution |
prompts:list-prompts | filterByAuthorities | Filter unauthorized prompts from discovery |
Will Hook — Run Before the Authority Check
UseWill to add custom pre-checks, logging, or feature-flag gates that run before the built-in authority evaluation.
Did Hook — Run After the Authority Check
UseDid to audit authority decisions or emit metrics after the check completes (whether it passed or threw).
Around Hook — Replace the Entire Authority Check
UseAround to wrap or completely replace the built-in authority evaluation with custom logic. This is useful for integrating external policy engines like OPA or Cedar.
Hooking into List Filtering
Error Handling
When an authorities check fails at execution time (as opposed to list filtering), thecheckEntryAuthorities stage throws an AuthorityDeniedError.
AuthorityDeniedError
| Property | Type | Value |
|---|---|---|
mcpErrorCode | number | -32003 (FORBIDDEN) |
statusCode | number | 403 |
code | string | AUTHORITY_DENIED |
entryType | string | 'Tool', 'Resource', 'Prompt', 'Skill' |
entryName | string | Name of the denied entry |
deniedBy | string | Human-readable reason (e.g., "roles.all: missing 'admin'") |
JSON-RPC Error Format
The error serializes to a standard JSON-RPC error for MCP transport:Denial Reasons
ThedeniedBy field provides actionable feedback:
| Pattern | Example |
|---|---|
roles.all: missing '<role>' | roles.all: missing 'admin' |
roles.any: user has none of '<role>', ... | roles.any: user has none of 'admin', 'superadmin' |
permissions.all: missing '<perm>' | permissions.all: missing 'users:delete' |
permissions.any: user has none of '<perm>', ... | permissions.any: user has none of 'data:export' |
attributes.match: '<path>' expected ... | attributes.match: 'claims.dept' expected 'eng' but got 'sales' |
attributes.conditions: '<path>' failed '<op>' check | attributes.conditions: 'claims.credits' failed 'gt' check against '0' |
relationships: user '<sub>' is not '<type>' of <resource>:<id> | relationships: user 'u-123' is not 'owner' of document:doc-456 |
profile '<name>' is not registered | profile 'admin' is not registered |
custom evaluator '<name>' is not registered | custom evaluator 'ipAllowList' is not registered |
Type-Safe Profiles
Use theFrontMcpAuthorityProfiles global interface augmentation to get autocomplete and compile-time checks for profile names.
Declaring Profiles
Create a type declaration file (e.g.,authorities.d.ts) in your project:
Autocomplete in Decorators
Once declared, TypeScript provides autocomplete when using string profile references:Metadata Augmentation
The@frontmcp/auth authorities module automatically augments all entry metadata interfaces to accept the authorities field:
authorities is accepted on @Tool(), @Resource(), @ResourceTemplate(), @Prompt(), and @Skill() decorators without any additional configuration.