The Middleware Pipeline
Relevant source files
The following files were used as context for generating this wiki page:
The Middleware Pipeline provides a declarative authorization layer for Prisma models within a GraphQL environment. It intercepts GraphQL execution to enforce access control rules defined directly in the Prisma schema via triple-slash comments (/// @Auth). By operating at the Prisma model level rather than the resolver level, it prevents accidental data exposure through deep relations.
The pipeline consists of three primary middleware components: field constraints, type constraints, and list constraints. These components collaborate to filter query results, restrict individual field access, and automatically inject necessary Prisma select and where clauses.
Sources: README.md:3-15, src/index.ts:46-50
Architecture and Core Components
The pipeline initializes via the makeAuthorizationMiddlewares function, which returns an array of three specialized GraphQL middlewares. These middlewares are typically applied to the GraphQL schema using graphql-middleware.
Sources: src/index.ts:46-50, README.md:104-110
Configuration Structure
The pipeline requires a Configuration object to map the declarative roles found in Prisma comments to executable JavaScript logic.
| Property | Type | Description |
|---|---|---|
rolesPerType | RolesPerType | Specific role matchers and constraints for a given Prisma model. |
globalRoles | Record<string, Role> | Fallback role matchers applied across all models. |
defaultFields | `Record<string, object | function>` |
Sources: src/index.ts:18-36
Middleware Functionality
Field Constraint Middleware
The makeFieldConstraintMiddleware enforces authorization on individual fields. It retrieves the @Auth description from the field definition in the GraphQL schema. If roles are specified, the middleware executes the corresponding matcher function. If no role is granted, it uses patchResponse to return a safe default (e.g., null or []) instead of the actual data.
Sources: src/makeFieldConstraintMiddleware.ts:18-50
Type Constraint Middleware
The makeTypeConstraintMiddleware secures 1-to-1 relations. It extracts the type name of the returned object and checks the model-level @Auth annotations. This ensures that even if a field itself isn't restricted, the underlying record must meet the model's access requirements.
Sources: src/makeTypeConstraintMiddleware.ts:31-70
List Constraint Middleware
The makeListConstraintMiddleware handles list queries and nested relations. It injects a withAuth helper into the GraphQL context. This helper automatically merges Prisma where constraints and select requirements into user-provided Prisma queries.
Sources: src/makeListConstraintMiddleware.ts:30-50
Data Flow and Filtering Logic
The pipeline relies on getListWhereConstrains to convert role definitions into Prisma-compatible query filters.
Query Constraint Resolution
When generating a where clause, the system iterates through all roles defined for a type:
- It looks for a
queryConstraintinrolesPerType, falling back toglobalRoles. - If the constraint returns
true, it applies analwaysTrueCondition. - If it returns an object, that object is added to an
ORarray. - The final constraints are wrapped in an
ANDblock to prevent user input from bypassing security filters. - If no roles are satisfied, it applies an
alwaysFalseCondition(filtering by a non-existent IDffffffffffffffffffffffff).
Sources: src/getListWhereConstrains.ts:10-25, src/getListWhereConstrains.ts:48-85
The PrismaSelect Plugin
The PrismaSelect class (forked from prisma-tools) is responsible for translating GraphQL info into Prisma select blocks. The pipeline enhances this by overlaying security requirements:
- Dependency Selection: If a
matcherrequires specific fields to evaluate access (e.g., anownerId),getMatcherDependenciesSelectensures those fields are included in the Prisma fetch, even if the client didn't request them. - Recursive Filtering: It traverses the GraphQL selection set and applies type-level filters to nested relations.
Sources: src/select.ts:192-230, src/getMatcherDependenciesSelect.ts:12-32
Role Description Parsing
The system uses a PEG.js-generated parser to interpret Prisma comments. The descriptionToRoles function extracts the action (e.g., read) and the associated roles with their optional arguments.
// Example input: "@Auth(read: [Owner(privileges: [admin])])"
// Resulting structure:
{
read: [
{ name: 'Owner', args: { privileges: ['admin'] } }
]
}
Sources: src/descriptionToRoles.ts:20-30, src/generated/parser.ts:500-550
Conclusion
The Middleware Pipeline automates the enforcement of security boundaries in Prisma-based GraphQL APIs. By combining runtime matching for individual records and query-level filtering for lists, it ensures that data access remains consistent with the declarative rules defined in the database schema. This centralized approach reduces the risk of security regressions when exposing complex data relations.