npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@ideacrafters/fastify-auth

v0.2.0

Published

Comprehensive authentication plugin for Fastify with multi-guard support and flexible ORM integration

Downloads

6

Readme

@ideacrafters/fastify-auth

Comprehensive authentication plugin for Fastify with multi-guard support and flexible ORM integration. Built on top of @fastify/auth for maximum performance and compatibility.

Features

  • 🔐 Multiple Authentication Guards: JWT, API Key, Credentials, Session, and Custom guards
  • 🎯 Multi-Guard Logic: OR/AND operators for complex authentication flows
  • 🔑 Authorization: Role-based and permission-based access control
  • 🗄️ ORM Agnostic: Adapter pattern for Prisma, TypeORM, Mongoose, and custom adapters
  • High Performance: Built-in caching with LRU cache
  • 📊 Audit Logging: Success/failure hooks for monitoring
  • 🎨 TypeScript: Full type safety and IntelliSense support
  • 🚀 Production Ready: Error handling, security headers, and more

Installation

npm install @ideacrafters/fastify-auth

Peer Dependencies

npm install fastify@^5.0.0

Optional Dependencies (based on your needs)

# For Prisma adapter
npm install @prisma/client prisma

# For password hashing (used by credentials guard)
npm install bcrypt

Quick Start

import Fastify from 'fastify'
import fastifyAuth, { PrismaAdapter } from '@ideacrafters/fastify-auth'
import { PrismaClient } from '@prisma/client'

const fastify = Fastify()
const prisma = new PrismaClient()

// Create adapter
const adapter = new PrismaAdapter(prisma, {
  defaultFields: {
    include: ['id', 'email', 'name', 'role', 'permissions'],
    exclude: ['password']
  }
})

// Register plugin
await fastify.register(fastifyAuth, {
  adapter,
  cache: { enabled: true, ttl: 300000 },
  onAuthSuccess: (user, request) => {
    console.log(`User ${user.id} authenticated`)
  }
})

// Setup guards
fastify.setupAuth({
  guards: {
    jwt: { type: 'jwt' },
    apikey: { type: 'apikey' },
    credentials: { type: 'credentials' }
  }
})

// Protected route
fastify.get('/profile', {
  preHandler: fastify.authenticate('jwt')
}, async (request) => {
  return { user: request.user }
})

Authentication Guards

JWT Authentication

fastify.setupAuth({
  guards: {
    jwt: {
      type: 'jwt',
      options: {
        algorithms: ['HS256', 'RS256'],
        audience: 'your-app',
        issuer: 'auth-server'
      }
    }
  }
})

// Usage
fastify.get('/api/protected', {
  preHandler: fastify.authenticate('jwt')
}, handler)

API Key Authentication

fastify.setupAuth({
  guards: {
    apikey: {
      type: 'apikey',
      options: {
        headerName: 'x-api-key',  // Default
        queryParam: 'api_key',     // Optional fallback
        extractor: (request) => {  // Custom extraction
          return request.headers['custom-header']
        }
      }
    }
  }
})

Credentials Authentication

fastify.setupAuth({
  guards: {
    credentials: {
      type: 'credentials',
      options: {
        usernameField: 'email',    // Default: 'username'
        passwordField: 'password',  // Default: 'password'
        hashPassword: true          // Default: true
      }
    }
  }
})

// Login endpoint
fastify.post('/login', {
  preHandler: fastify.authenticate('credentials')
}, async (request, reply) => {
  const token = await reply.jwtSign({
    sub: request.user.id,
    email: request.user.email
  })
  return { token }
})

Session Authentication

fastify.setupAuth({
  guards: {
    session: {
      type: 'session',
      options: {
        cookieName: 'sessionId',
        maxAge: 86400000  // 24 hours
      }
    }
  }
})

Custom Guards

fastify.setupAuth({
  guards: {
    custom: {
      type: 'custom',
      authenticate: async (request, reply, adapter) => {
        const token = request.headers['x-custom-auth']
        if (!token) return null
        
        const user = await adapter.findUserByCustomField(token)
        return user
      }
    }
  }
})

Multi-Guard Authentication

OR Logic (Default)

Any of the specified guards can succeed:

fastify.get('/api/data', {
  preHandler: fastify.authenticate(['jwt', 'apikey'])
}, handler)

AND Logic

All specified guards must succeed:

fastify.post('/api/secure', {
  preHandler: fastify.authenticate(['jwt', 'apikey'], { operator: 'AND' })
}, handler)

Conditional Authentication

Dynamic guard selection based on request:

fastify.get('/api/flexible', {
  preHandler: fastify.authenticate((req) => 
    req.headers.authorization ? 'jwt' : 'session'
  )
}, handler)

Authorization

Role-Based Access Control

fastify.delete('/admin/users/:id', {
  preHandler: [
    fastify.authenticate('jwt'),
    fastify.authorize('admin', 'role')
  ]
}, handler)

// Multiple roles
fastify.get('/moderator/dashboard', {
  preHandler: [
    fastify.authenticate('jwt'),
    fastify.authorize(['admin', 'moderator'], 'role')
  ]
}, handler)

Permission-Based Access Control

fastify.post('/api/resources', {
  preHandler: [
    fastify.authenticate('jwt'),
    fastify.authorize('create:resources', 'permission')
  ]
}, handler)

Model-Based Access Control

fastify.get('/admin/dashboard', {
  preHandler: [
    fastify.authenticate(['client', 'admin']),
    fastify.authorize('admin', 'usermodel')
  ]
}, handler)

Request Helpers

After authentication, the request object is decorated with helpful methods:

fastify.get('/api/check', {
  preHandler: fastify.authenticate('jwt')
}, async (request) => {
  return {
    isAdmin: request.hasRole('admin'),
    canCreate: request.hasPermission('create:resources'),
    hasAnyRole: request.hasAnyRole(['admin', 'moderator']),
    hasAllPerms: request.hasAllPermissions(['read', 'write']),
    userModel: request.isUserModel('admin')
  }
})

Adapters

Prisma Adapter

import { PrismaAdapter } from '@ideacrafters/fastify-auth/adapters'

const adapter = new PrismaAdapter(prismaClient, {
  userModel: 'user',          // Default: 'user'
  sessionModel: 'session',    // Default: 'session'
  apiKeyModel: 'apiKey',      // Default: 'apiKey'
  passwordField: 'password',  // Default: 'password'
  emailField: 'email',        // Default: 'email'
  sessionDuration: 86400      // Default: 24 hours
})

Custom Adapter

Create your own adapter by extending the base class:

import { AbstractAuthAdapter } from '@ideacrafters/fastify-auth/adapters'

class CustomAdapter extends AbstractAuthAdapter {
  async findUserById(id, options) {
    // Your implementation
  }
  
  async findUserByEmail(email, options) {
    // Your implementation
  }
  
  // ... implement other required methods
}

Caching

Configure caching for improved performance:

await fastify.register(fastifyAuth, {
  adapter,
  cache: {
    enabled: true,
    ttl: 300000,        // 5 minutes
    max: 1000,          // Maximum items
    updateAgeOnGet: true // Reset TTL on access
  }
})

Error Handling

Custom error handling:

await fastify.register(fastifyAuth, {
  adapter,
  errorHandler: async (error, request, reply) => {
    if (error.code === 'INVALID_TOKEN') {
      reply.code(401).send({ error: 'Token expired' })
    } else {
      reply.code(500).send({ error: 'Authentication error' })
    }
  }
})

Audit Logging

Monitor authentication events:

await fastify.register(fastifyAuth, {
  adapter,
  onAuthSuccess: async (user, request) => {
    await logService.log('auth.success', {
      userId: user.id,
      ip: request.ip,
      userAgent: request.headers['user-agent']
    })
  },
  onAuthFailure: async (error, request) => {
    await logService.log('auth.failure', {
      error: error.message,
      ip: request.ip
    })
  }
})

TypeScript Support

Full TypeScript support with type augmentation:

declare module 'fastify' {
  interface FastifyRequest {
    user?: {
      id: string
      email: string
      role: string
      permissions: string[]
    }
  }
}

Database Schema Requirements

Minimum Requirements

-- User table
CREATE TABLE users (
  id UUID PRIMARY KEY,
  email VARCHAR(255) UNIQUE,
  password VARCHAR(255),
  isActive BOOLEAN DEFAULT true
);

Recommended Schema

-- User table
CREATE TABLE users (
  id UUID PRIMARY KEY,
  email VARCHAR(255) UNIQUE,
  username VARCHAR(255) UNIQUE,
  password VARCHAR(255),
  role VARCHAR(50),
  permissions TEXT[], -- Array of permissions
  isActive BOOLEAN DEFAULT true,
  createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- Session table
CREATE TABLE sessions (
  id UUID PRIMARY KEY,
  userId UUID REFERENCES users(id),
  token VARCHAR(255) UNIQUE,
  expiresAt TIMESTAMP,
  data JSONB,
  createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- API Key table
CREATE TABLE api_keys (
  id UUID PRIMARY KEY,
  userId UUID REFERENCES users(id),
  key VARCHAR(255) UNIQUE,
  name VARCHAR(255),
  isActive BOOLEAN DEFAULT true,
  createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Examples

Check the examples directory for complete examples:

  • basic-usage.ts - Basic authentication setup
  • multi-guard.ts - Complex authentication flows
  • custom-adapter.ts - Custom adapter implementation
  • authorization.ts - Role and permission-based access control

Performance

  • Built on @fastify/auth for minimal overhead
  • LRU caching reduces database queries
  • Efficient token validation
  • Benchmarks: < 1ms authentication overhead

Security Best Practices

  1. Always use HTTPS in production
  2. Store secrets securely using environment variables
  3. Implement rate limiting to prevent brute force attacks
  4. Use strong JWT secrets (minimum 256 bits)
  5. Enable audit logging for security monitoring
  6. Validate and sanitize all input data
  7. Implement CORS appropriately
  8. Use secure session cookies (httpOnly, secure, sameSite)

API Reference

Plugin Options

| Option | Type | Description | |--------|------|-------------| | adapter | BaseAuthAdapter | Required. Database adapter instance | | guards | Record<string, GuardConfig> | Guard configurations | | cache | CacheOptions | Cache configuration | | defaultGuard | string | Default guard name | | onAuthSuccess | Function | Success callback | | onAuthFailure | Function | Failure callback | | errorHandler | Function | Custom error handler |

Guard Configuration

| Option | Type | Description | |--------|------|-------------| | type | 'jwt' \| 'apikey' \| 'credentials' \| 'session' \| 'custom' | Guard type | | userModel | string | User model name | | options | object | Guard-specific options | | authenticate | Function | Custom authentication function (for custom type) |

Contributing

Contributions are welcome! Please read our Contributing Guide for details.

License

MIT © Idea Crafters

Support