Fastify Auth Prisma Plugin
Fastify Auth Prisma is a Fastify plugin that integrates with Prisma to provide a simple and secure authentication middleware solution. It handles token-based authentication, allowing developers to protect routes and manage user sessions by leveraging Prisma for database interactions. The current stable version is 1.2.444, indicating active development within the 1.x release line. While a specific release cadence isn't stated, the version numbering suggests frequent updates. Key differentiators include its direct integration with Prisma, simplifying the data layer for authentication, and its focus on being a Fastify-native solution for performance and developer experience within the Fastify ecosystem. It provides mechanisms for defining public routes and validating connected users using a Prisma client and JWT secrets.
Common errors
-
Property 'connectedUser' does not exist on type 'FastifyRequest<RouteGenericInterface, RawServerDefault, RawRequestDefaultExpression, RouteShorthandOptions<RawServerDefault>, ContextConfigDefault>'
cause Missing TypeScript declaration merging for the `FastifyRequest` interface.fixAdd `declare module 'fastify' { interface FastifyRequest { connectedUser?: User; } }` to your project's global declaration file or a relevant TypeScript file. -
TypeError: Cannot read properties of undefined (reading 'register')
cause Attempting to register the plugin before the Fastify instance is fully initialized or when `server` is not a valid Fastify instance.fixEnsure `fastify()` is called correctly and `server.register` is invoked within an `async` function with `await` if using top-level await or inside a setup function. -
FastifyError: FST_ERR_MISSING_SECRET: Missing secret
cause The `secret` option was not provided or was an empty string during plugin registration.fixProvide a non-empty string for the `secret` option when registering `fastifyAuthPrismaPlugin`, ideally from `process.env`.
Warnings
- breaking The `declare module 'fastify'` block for `connectedUser` is essential. Failing to include it will result in TypeScript errors when attempting to access `request.connectedUser` within route handlers.
- gotcha The `secret` option for `fastifyAuthPrismaPlugin` is critical for JWT security. Using a hardcoded or easily guessable secret in production can lead to severe security vulnerabilities. It is strongly recommended to use a robust, externally managed secret.
- gotcha Proper Prisma schema setup is crucial for this plugin. The `Token` and `User` models, along with their relations, must match the structure expected by the plugin for correct authentication flow.
- gotcha The `unify-fastify` plugin is registered in the example setup. If your application does not use or register `unify-fastify`, you might encounter unexpected behavior or errors if `fastify-auth-prisma` has a hard dependency or expects its functionalities.
Install
-
npm install fastify-auth-prisma -
yarn add fastify-auth-prisma -
pnpm add fastify-auth-prisma
Imports
- fastifyAuthPrismaPlugin
const fastifyAuthPrismaPlugin = require('fastify-auth-prisma').fastifyAuthPrismaPlugin;import { fastifyAuthPrismaPlugin } from 'fastify-auth-prisma'; - createUserToken
import { createUserToken } from 'fastify-auth-prisma'; - User
import { User } from '@prisma/client';
Quickstart
import fastify from 'fastify';
import { PrismaClient, User } from '@prisma/client';
import unifyFastifyPlugin from 'unify-fastify';
import { fastifyAuthPrismaPlugin } from 'fastify-auth-prisma';
const prisma = new PrismaClient();
const server = fastify({
logger: true
});
declare module 'fastify' {
interface FastifyRequest {
connectedUser?: User;
}
}
async function startServer() {
await server.register(unifyFastifyPlugin);
await server.register(fastifyAuthPrismaPlugin, {
config: [{ url: '/public/*', method: 'GET' }],
prisma,
secret: process.env.JWT_ACCESS_SECRET ?? 'supersecretjwtkey',
userValidation: async (user: User) => {
if (!user.id) {
throw new Error('User not found or invalid.');
}
// Add custom validation logic here, e.g., check if user is banned
}
});
server.get('/public/hello', async (request, reply) => {
return { message: 'Hello, public world!' };
});
server.get('/protected/hello', async (request, reply) => {
if (!request.connectedUser) {
reply.code(401).send({ message: 'Unauthorized' });
return;
}
return { message: `Hello, ${request.connectedUser.id}! You are connected.` };
});
try {
await server.listen({ port: 3000 });
server.log.info(`Server listening on http://localhost:3000`);
} catch (err) {
server.log.error(err);
process.exit(1);
}
}
startServer();