npm package: @ideacrafters/fastify-auth
Description: Comprehensive authentication plugin for Fastify with multi-guard support and flexible ORM integration
Author: Idea Crafters
Latest version: 0.2.0

# @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

```bash
npm install @ideacrafters/fastify-auth
```

### Peer Dependencies

```bash
npm install fastify@^5.0.0
```

### Optional Dependencies (based on your needs)

```bash
# For Prisma adapter
npm install @prisma/client prisma

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

## Quick Start

```typescript
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

```typescript
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

```typescript
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

```typescript
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

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

### Custom Guards

```typescript
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:

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

### AND Logic

All specified guards must succeed:

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

### Conditional Authentication

Dynamic guard selection based on request:

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

## Authorization

### Role-Based Access Control

```typescript
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

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

### Model-Based Access Control

```typescript
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:

```typescript
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

```typescript
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:

```typescript
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:

```typescript
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:

```typescript
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:

```typescript
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:

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

## Database Schema Requirements

### Minimum Requirements

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

### Recommended Schema

```sql
-- 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](CONTRIBUTING.md) for details.

## License

MIT © [Idea Crafters](https://github.com/IdeaCraftersHQ)

## Support

- 📧 Email: hello@ideacrafters.com
- 🐛 Issues: [GitHub Issues](https://github.com/IdeaCraftersHQ/fastify-auth/issues)
- 💬 Discussions: [GitHub Discussions](https://github.com/IdeaCraftersHQ/fastify-auth/discussions)