Skip to content

IdeaCraftersHQ/fastify-auth

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@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

About

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

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors