Getting Started / Setup
Relevant source files
The following files were used as context for generating this wiki page:
@joindeed/prisma-auth provides a declarative authorization layer for Prisma models. It moves security logic from GraphQL resolvers to the Prisma model level to prevent accidental data exposure in deeply nested relations.
This library operates as a set of GraphQL middlewares. It validates access using @Auth annotations in Prisma schema comments and generates Prisma-compatible where and select clauses to enforce these rules at runtime.
Sources: README.md:3-12, src/index.ts:47-51
Initial Installation
Install the package using your preferred package manager.
yarn add @joindeed/prisma-auth
Sources: README.md:62, package.json:1-10
Setup Flow
The following diagram illustrates the high-level steps required to integrate the authorization layer into a project.
This flow ensures that authorization rules are defined once and applied consistently across all data access points.
Step 1: Annotating the Prisma Schema
You define authorization rules using triple-slash comments (///) in your schema.prisma file. The library currently focuses on read operations.
- Model Level: Apply rules to all fields in a model.
- Field Level: Apply rules to specific sensitive fields.
/// @Auth(read: [Owner, Admin])
model Purchase {
id String @id
/// @Auth(read: [Admin])
secret String
}
Sources: README.md:46-60, src/descriptionToRoles.ts:18-28
Step 2: Configuring Role Logic
Define the logic for each role in a Configuration object. Each role requires a matcher for individual records and a queryConstraint for list queries.
Role Components
| Component | Type | Description |
|---|---|---|
matcher | Function | Returns boolean to allow or deny access to a specific record. |
queryConstraint | Function | Returns a Prisma where clause or boolean to filter list results. |
matcherDependenciesSelect | Object/Function | Defines fields required from the database to execute the matcher. |
Sources: src/index.ts:7-11, README.md:66-93
Configuration Example
const config = {
globalRoles: {
Admin: {
matcher: (ctx) => ctx.currentUser?.isAdmin,
queryConstraint: (ctx) => ctx.currentUser?.isAdmin,
},
},
rolesPerType: {
Purchase: {
Owner: {
matcher: (ctx, record) => ctx.currentUser?.id === record.userId,
queryConstraint: (ctx) => ({ userId: ctx.currentUser.id }),
},
},
},
};
Sources: README.md:66-93, src/index.ts:18-35
Step 3: Integrating with GraphQL Middleware
Apply the authorization middlewares to your GraphQL schema using graphql-middleware.
import { applyMiddleware } from 'graphql-middleware';
import { makeAuthorizationMiddlewares } from '@joindeed/prisma-auth';
const schemaWithAuth = applyMiddleware(
schema,
...makeAuthorizationMiddlewares(config)
);
The makeAuthorizationMiddlewares function generates three specific middlewares:
makeFieldConstraintMiddleware: Handles individual field access.makeTypeConstraintMiddleware: Handles 1-to-1 relation access.makeListConstraintMiddleware: Injects thewithAuthhelper into the context.
Sources: src/index.ts:47-51, README.md:126-133
Step 4: Using withAuth in Resolvers
The middleware adds a withAuth function to your GraphQL context. You must wrap Prisma calls with this function to apply the generated where and select constraints.
The withAuth helper ensures that the final Prisma query includes all necessary security filters and field requirements.
Sources: src/makeListConstraintMiddleware.ts:40-62, README.md:97-103
Specialized Usage of withAuth
If the resolver return type differs from the Prisma model, provide the path and type name manually.
// For specific paths in composite types
context.prisma.users.findMany(context.withAuth(query, 'path.to.user', 'UserType'))
// For count or aggregate queries (where only)
context.prisma.users.count(context.withAuth(query, undefined, 'UserType'))
Sources: README.md:105-120, src/makeListConstraintMiddleware.ts:44-53
Summary
Setting up @joindeed/prisma-auth involves annotating the Prisma schema, defining role-based logic in a configuration object, and applying middlewares to the GraphQL server. Developers must then use the context.withAuth utility in resolvers to ensure that Prisma queries respect the defined authorization boundaries. This centralized approach reduces the risk of security vulnerabilities in complex, relational GraphQL APIs.