Security · Authorization Directives

Enforce field-level permissions from the schema itself

Declare access requirements with @authenticated and @requiresScopes. The router evaluates them before any resolver runs. Directives propagate from subgraph schemas to the federated graph automatically.

Requires Router 0.60.0+. Works with JWT Authentication.

Available onFreeProEnterprise

The problem

Authorization scattered across resolvers is a liability

In a federated graph, each team implements access control independently. The result is inconsistent enforcement and no visible record of what each field requires.

Authorization logic lives in resolver code

Each resolver that handles sensitive data contains its own access checks. There is no single place to see what each field requires. Auditing means reading every resolver.

Enforcement is inconsistent across subgraphs

In a federated graph, each subgraph team implements authorization independently. One subgraph enforces scope checks; another does not. The gaps are invisible until something is accessed that should not be.

Access requirements are not visible in the schema

Developers reading the schema cannot tell which fields require authentication or which scopes are needed. That context exists only in the implementation — not in the API contract.

Our solution

The schema documents and enforces access requirements

Authorization directives embed access requirements directly in the GraphQL schema. The router evaluates them before execution — no code changes needed in resolvers.

From schema declaration to enforcement

  1. Declare @authenticated on any field, object, interface, enum, or scalar that requires authentication.

  2. Declare @requiresScopes with a nested array of scope requirements. Inner arrays are AND conditions; outer arrays are OR conditions.

  3. Directives declared in a subgraph schema propagate automatically to the federated schema during composition.

  4. At request time, the router evaluates directives before query execution — no resolver code runs for unauthorized fields.

  5. Nullable fields return partial data with authorization errors. If a non-nullable field fails authorization, the entire response data returns null.

  6. @requiresScopes error messages specify the required and actual scopes, giving clients actionable context. @authenticated errors state the reason: not authenticated.

JWT Authentication must be configured. Router 0.60.0+, Control Plane 0.58.0+.

Authorization directives

Before & After

Before CosmoWith Cosmo
Authorization checks scattered across resolver functionsDeclarative directives in the schema
No single source of truth for access requirementsSchema documents and enforces requirements simultaneously
Each subgraph implements authorization independentlyDirectives propagate automatically to the federated graph
Custom code for every protected field@authenticated or @requiresScopes in one line

Scope logic

AND / OR with nested arrays

@requiresScopes(scopes: [["hr:read"]])
Requires "hr:read".

@requiresScopes(scopes: [["admin", "write"]])
Requires "admin" AND "write".

@requiresScopes(scopes: [["management:read"], ["hr:admin"]])
Requires "management:read" OR "hr:admin".

Inner arrays: AND conditions. Outer arrays: OR conditions.

How authorization directives work in Cosmo

01
Schema is the source of truth.

Declare

Add @authenticated or @requiresScopes to any field, type, interface, enum, or scalar in a subgraph schema. @requiresScopes uses a nested array: inner arrays are AND, outer arrays are OR. Example: [["hr:read"]] requires "hr:read". [["admin", "write"], ["superuser"]] requires ("admin" AND "write") OR "superuser".

02
Cross-subgraph propagation, automatic.

Propagate

During federation composition, directives declared in any subgraph propagate to the federated schema. Directives on types protect all fields returning that type. @authenticated on an interface field protects only that interface field — it does not protect the corresponding fields on implementing types.

03
Evaluated at the router, pre-execution.

Evaluate

The router evaluates directives before query execution. JWT claims must be present and validated first. @authenticated checks for any valid authentication. @requiresScopes checks scope claims against the configured AND/OR logic. Requires Router 0.60.0+ and Control Plane 0.58.0+.

04
Partial data for nullable fields.

Respond

For nullable fields, the router returns partial data with authorization errors in the errors array. If a non-nullable field fails authorization, the entire response data returns null. @requiresScopes error messages include the required and actual scopes.

Authorization controls

Field-level control, from simple to complex

Protect individual fields or entire types with a single directive.

Apply at any level

Declare directives on fields, object types, interfaces, enums, or scalars. A directive on a type protects every field that returns that type. A directive on an interface field protects that interface field only, not the fields of implementing types.

Cross-subgraph propagation

Directives in any subgraph schema propagate to the federated graph during composition. A directive declared in the pricing subgraph enforces the requirement regardless of which subgraph resolves the field.

Partial data for nullable fields

When authorization fails on a nullable field, the field returns null and an error appears in the errors array. When a non-nullable field fails authorization, the entire response data returns null.

Clear error messages

@requiresScopes errors include the required and actual scopes from the token. @authenticated errors state the reason: not authenticated. Clients receive actionable information about what permissions they need.

Add field-level authorization to your schema

Declare @authenticated or @requiresScopes. The router enforces them. No resolver changes required.

FAQ

Authorization directives on Cosmo

Full reference at @authenticated documentation and @requiresScopes documentation.