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 🙏

© 2026 – Pkg Stats / Ryan Hefner

nest-authify

v1.1.0

Published

Complete authentication and authorization package for NestJS - Monolith and Microservices ready with OAuth, JWT, Redis sessions

Readme

🔐 nest-authify

Complete, production-ready authentication and authorization package for NestJS applications. Supports monolithic and microservices architectures with OAuth, JWT, Redis sessions, and more.

npm version License: MIT

✨ Features

  • 🔑 Multiple Authentication Strategies: Local (username/password), JWT, OAuth (Google, Facebook, GitHub)
  • 🏢 Flexible Architecture: Works in monolithic and microservices setups
  • 🔄 Session Management: Optional Redis-backed sessions with revocation support
  • 🎯 Easy to Use: Unified @Auth() decorator for authentication and authorization
  • 🛡️ Type-Safe: Full TypeScript support with comprehensive types
  • 🔧 Extensible: Base classes for custom implementations
  • 📦 Plug & Play: Default implementations for quick setup
  • 🚀 Production Ready: Built-in guards, decorators, and best practices
  • 💾 Flexible Storage: Memory or Redis session storage
  • 📝 Swagger Integration: Automatic API documentation
  • 🎨 Customizable: Custom hash functions, repositories, and services

📦 Installation

npm install nest-authify
# or
yarn add nest-authify
# or
pnpm add nest-authify

Required Peer Dependencies

npm install @nestjs/common @nestjs/core @nestjs/jwt @nestjs/passport @nestjs/config passport passport-jwt passport-local bcrypt joi uuid

Optional Dependencies

For Redis sessions:

npm install ioredis

For OAuth support:

# Google
npm install passport-google-oauth20

# Facebook
npm install passport-facebook

# GitHub
npm install passport-github2

🚀 Quick Start

1. Basic Setup (Normal Mode)

// app.module.ts
import { Module } from '@nestjs/common';
import { AuthModule } from 'nest-authify';
import { UserRepository } from './repositories/user.repository';

@Module({
  imports: [
    AuthModule.forRoot({
      mode: 'normal', // Para aplicaciones monolíticas
      jwtSecret: process.env.JWT_SECRET,
      jwtExpiresIn: '60m',
      refreshExpiresIn: '7d',
      authRepository: UserRepository,
      strategies: {
        local: true,
        jwt: true,
      },
    }),
  ],
})
export class AppModule {}

2. Implement Auth Repository

// user.repository.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { IAuthRepository } from 'nest-authify';
import { User } from './entities/user.entity';

@Injectable()
export class UserRepository implements IAuthRepository {
  constructor(
    @InjectRepository(User)
    private userRepo: Repository<User>,
  ) {}

  async findUserByUsername(username: string) {
    return this.userRepo.findOne({
      where: [{ username }, { email: username }],
    });
  }

  async findUserById(id: string) {
    return this.userRepo.findOne({ where: { id } });
  }

  async findUserByProviderId(provider: string, providerId: string) {
    return this.userRepo.findOne({ where: { provider, providerId } });
  }

  async createUser(data: any) {
    const user = this.userRepo.create(data);
    return this.userRepo.save(user);
  }

  async updateUser(id: string, data: any) {
    await this.userRepo.update(id, data);
    return this.findUserById(id);
  }
}

3. Use Built-in Controllers

The package provides ready-to-use controllers:

// No need to create controllers!
// These endpoints are automatically available:

// POST /auth/register
// POST /auth/login
// GET  /auth/profile
// POST /auth/refresh
// POST /auth/logout
// POST /auth/logout-all
// GET  /auth/verify
// POST /auth/change-password

4. Use @Auth() Decorator

// users.controller.ts
import { Controller, Get } from '@nestjs/common';
import { Auth, CurrentUser } from 'nest-authify';

@Controller('users')
export class UsersController {
  // Public route
  @Auth({ public: true })
  @Get('public')
  getPublic() {
    return 'This is public';
  }

  // Authenticated users only
  @Auth()
  @Get('profile')
  getProfile(@CurrentUser() user: any) {
    return user;
  }

  // Admin only
  @Auth({ roles: ['admin'] })
  @Get('admin')
  adminOnly() {
    return 'Admin only content';
  }

  // Multiple roles
  @Auth({ roles: ['admin', 'moderator'] })
  @Get('moderation')
  moderation() {
    return 'Moderation panel';
  }

  // Permissions-based
  @Auth({ permissions: ['posts:delete'] })
  @Delete('posts/:id')
  deletePost() {
    return 'Post deleted';
  }
}

📖 Configuration Options

AuthModuleOptions

interface AuthModuleOptions {
  // Modo de operación
  mode: 'normal' | 'server' | 'client';

  // Configuración JWT
  jwtSecret: string;
  jwtExpiresIn?: string; // default: '60m'
  refreshExpiresIn?: string; // default: '7d'

  // Session Store (opcional)
  sessionStore?: {
    type: 'memory' | 'redis';
    redis?: {
      host: string;
      port: number;
      password?: string;
      db?: number;
      keyPrefix?: string;
    };
  };

  // Servicios personalizados
  authService?: Type<any>; // Debe extender BaseAuthService
  authRepository?: Type<any>; // Debe implementar IAuthRepository

  // Hash personalizado
  hashCallback?: (password: string) => Promise<string>;
  hashVerifyCallback?: (password: string, hash: string) => Promise<boolean>;

  // OAuth
  google?: {
    clientId: string;
    clientSecret: string;
    callbackUrl?: string;
    scope?: string[];
  };
  facebook?: {
    clientId: string;
    clientSecret: string;
    callbackUrl?: string;
    scope?: string[];
  };
  github?: {
    clientId: string;
    clientSecret: string;
    callbackUrl?: string;
    scope?: string[];
  };

  // Estrategias
  strategies?: {
    local?: boolean;
    jwt?: boolean;
    google?: boolean;
    facebook?: boolean;
    github?: boolean;
  };

  // Controladores
  enableControllers?: boolean; // default: true
  controllersPrefix?: string; // default: 'auth'
  enableSwagger?: boolean; // default: true
}

🔧 Advanced Usage

Custom Hash Function

import * as argon2 from 'argon2';

AuthModule.forRoot({
  // ... otras opciones
  hashCallback: async (password: string) => {
    return argon2.hash(password);
  },
  hashVerifyCallback: async (password: string, hash: string) => {
    return argon2.verify(hash, password);
  },
}),

Redis Session Store

AuthModule.forRoot({
  mode: 'normal',
  jwtSecret: process.env.JWT_SECRET,
  authRepository: UserRepository,
  sessionStore: {
    type: 'redis',
    redis: {
      host: 'localhost',
      port: 6379,
      password: process.env.REDIS_PASSWORD,
      keyPrefix: 'auth:',
    },
  },
  strategies: {
    local: true,
    jwt: true,
  },
}),

OAuth Configuration

AuthModule.forRoot({
  mode: 'normal',
  jwtSecret: process.env.JWT_SECRET,
  authRepository: UserRepository,
  google: {
    clientId: process.env.GOOGLE_CLIENT_ID,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    callbackUrl: 'http://localhost:3000/auth/google/callback',
  },
  facebook: {
    clientId: process.env.FACEBOOK_APP_ID,
    clientSecret: process.env.FACEBOOK_APP_SECRET,
    callbackUrl: 'http://localhost:3000/auth/facebook/callback',
  },
  github: {
    clientId: process.env.GITHUB_CLIENT_ID,
    clientSecret: process.env.GITHUB_CLIENT_SECRET,
    callbackUrl: 'http://localhost:3000/auth/github/callback',
  },
  strategies: {
    local: true,
    jwt: true,
    google: true,
    facebook: true,
    github: true,
  },
}),

OAuth endpoints are automatically available:

  • GET /auth/google - Inicia flujo OAuth
  • GET /auth/google/callback - Callback de Google
  • GET /auth/facebook - Inicia flujo OAuth
  • GET /auth/facebook/callback - Callback de Facebook
  • GET /auth/github - Inicia flujo OAuth
  • GET /auth/github/callback - Callback de GitHub

Custom Auth Service

import { Injectable } from '@nestjs/common';
import { BaseAuthService } from 'nest-authify';

@Injectable()
export class CustomAuthService extends BaseAuthService {
  // Override para añadir logging
  async createSession(user: any, options?: any) {
    console.log(`User login: ${user.id}`);
    return super.createSession(user, options);
  }

  // Implementación requerida
  protected async getUserById(userId: string) {
    return this.repository.findUserById(userId);
  }

  // Métodos personalizados
  async sendWelcomeEmail(userId: string) {
    // Tu lógica aquí
  }
}

// Usar en el módulo
AuthModule.forRoot({
  // ... otras opciones
  authService: CustomAuthService,
}),

Extending AuthSession

// Extender la interfaz AuthSession
declare module 'nest-authify' {
  interface AuthSession {
    ipAddress?: string;
    userAgent?: string;
    deviceId?: string;
  }
}

// Usar en el servicio
const session = await this.authService.createSession(user, {
  metadata: {
    ipAddress: req.ip,
    userAgent: req.headers['user-agent'],
    deviceId: req.headers['x-device-id'],
  },
});

🏗️ Architecture Modes

Normal Mode (Monolithic)

Complete authentication in a single application.

AuthModule.forRoot({
  mode: 'normal',
  jwtSecret: process.env.JWT_SECRET,
  authRepository: UserRepository,
  strategies: { local: true, jwt: true },
})

Server Mode (Microservice Auth Server)

Dedicated authentication microservice.

// auth-service/app.module.ts
AuthModule.forRoot({
  mode: 'server',
  jwtSecret: process.env.JWT_SECRET,
  authRepository: UserRepository,
  strategies: { local: true, jwt: true },
})

Client Mode (Microservice Client)

Services that consume authentication.

// orders-service/app.module.ts
AuthModule.forRoot({
  mode: 'client',
  jwtSecret: process.env.JWT_SECRET, // Same secret as auth server
  strategies: { jwt: true }, // Only JWT validation needed
})

🎯 Decorators

@Auth()

Unified decorator for authentication and authorization.

// Public route
@Auth({ public: true })
@Get('public')
getPublic() {}

// Requires authentication
@Auth()
@Get('protected')
getProtected() {}

// Requires specific roles
@Auth({ roles: ['admin'] })
@Get('admin')
adminOnly() {}

// Requires permissions
@Auth({ permissions: ['posts:write'] })
@Post('posts')
createPost() {}

// Combined with custom guards
@Auth({ 
  roles: ['admin'], 
  permissions: ['users:delete'],
  guards: [ThrottlerGuard]
})
@Delete('users/:id')
deleteUser() {}

@CurrentUser()

Extracts user from request.

@Get('profile')
getProfile(@CurrentUser() user: any) {
  return user;
}

// Extract specific property
@Get('id')
getUserId(@CurrentUser('id') userId: string) {
  return { userId };
}

@SessionId()

Extracts session ID from JWT.

@Post('logout')
async logout(@SessionId() sessionId: string) {
  await this.authService.revokeSession(sessionId);
}

Other Decorators

@IpAddress() // Get client IP
@UserAgent() // Get User-Agent
@GetRequest() // Get full request object

🛡️ Guards

All guards are exported and can be used manually:

import { 
  JwtAuthGuard, 
  RolesGuard, 
  LocalAuthGuard,
  GoogleAuthGuard,
  FacebookAuthGuard,
  GithubAuthGuard,
  PermissionsGuard 
} from 'nest-authify';

@UseGuards(JwtAuthGuard, RolesGuard)
@Get('protected')
protectedRoute() {}

📝 Environment Variables

Create a .env file:

# JWT Configuration
JWT_SECRET=your-super-secret-jwt-key
JWT_EXPIRES_IN=60m
REFRESH_EXPIRES_IN=7d

# Redis (optional)
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=your-redis-password
REDIS_DB=0
REDIS_KEY_PREFIX=auth:

# Google OAuth (optional)
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
GOOGLE_CALLBACK_URL=http://localhost:3000/auth/google/callback

# Facebook OAuth (optional)
FACEBOOK_APP_ID=your-facebook-app-id
FACEBOOK_APP_SECRET=your-facebook-app-secret
FACEBOOK_CALLBACK_URL=http://localhost:3000/auth/facebook/callback

# GitHub OAuth (optional)
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret
GITHUB_CALLBACK_URL=http://localhost:3000/auth/github/callback

# Frontend URL (for OAuth redirects)
FRONTEND_URL=http://localhost:4200

🔌 Async Configuration

For dynamic configuration:

import { ConfigService } from '@nestjs/config';

AuthModule.forRootAsync({
  imports: [ConfigModule],
  useFactory: async (configService: ConfigService) => ({
    mode: 'normal',
    jwtSecret: configService.get('JWT_SECRET'),
    jwtExpiresIn: configService.get('JWT_EXPIRES_IN', '60m'),
    refreshExpiresIn: configService.get('REFRESH_EXPIRES_IN', '7d'),
    authRepository: UserRepository,
    sessionStore: configService.get('REDIS_HOST') ? {
      type: 'redis',
      redis: {
        host: configService.get('REDIS_HOST'),
        port: configService.get('REDIS_PORT'),
        password: configService.get('REDIS_PASSWORD'),
      },
    } : undefined,
    strategies: {
      local: true,
      jwt: true,
      google: !!configService.get('GOOGLE_CLIENT_ID'),
      facebook: !!configService.get('FACEBOOK_APP_ID'),
      github: !!configService.get('GITHUB_CLIENT_ID'),
    },
  }),
  inject: [ConfigService],
}),

📚 API Reference

BaseAuthService

Base service that can be extended:

class BaseAuthService {
  // JWT Methods
  createJwt(user: any, expiresIn?: string, sessionId?: string): Promise<string>
  createRefreshToken(user: any, expiresIn?: string, sessionId?: string): Promise<string>
  verifyToken(token: string): Promise<JwtPayload>
  
  // Session Methods
  createSession(user: any, options?: CreateSessionOptions): Promise<AuthSession>
  refreshAccessToken(refreshToken: string): Promise<{ accessToken: string; expiresIn: number }>
  revokeSession(sessionId: string): Promise<void>
  revokeAllUserSessions(userId: string): Promise<void>
  
  // User Methods
  register(data: RegisterUserDto): Promise<any>
  validateUser(username: string, password: string): Promise<ValidatedUser | null>
  validateOAuthUser(provider: string, providerId: string, profile: any): Promise<any>
  changePassword(userId: string, oldPassword: string, newPassword: string): Promise<void>
  
  // Abstract Methods (must implement)
  protected abstract getUserById(userId: string): Promise<any>
}

IAuthRepository

Interface to implement for your data layer:

interface IAuthRepository {
  findUserByUsername(username: string): Promise<any>
  findUserById(id: string): Promise<any>
  findUserByProviderId(provider: string, providerId: string): Promise<any>
  createUser(data: any): Promise<any>
  updateUser(id: string, data: any): Promise<any>
  deleteUser?(id: string): Promise<void>
  findUsersByRole?(role: string): Promise<any[]>
  findActiveUsers?(): Promise<any[]>
}

ISessionStore

Interface for custom session stores:

interface ISessionStore {
  set(key: string, value: any, ttl?: number): Promise<void>
  get(key: string): Promise<any>
  delete(key: string): Promise<void>
  exists(key: string): Promise<boolean>
  keys(pattern?: string): Promise<string[]>
  clear(): Promise<void>
}

🧪 Testing

Example test setup:

import { Test, TestingModule } from '@nestjs/testing';
import { AuthModule, AUTH_SERVICE } from 'nest-authify';

describe('AuthService', () => {
  let service: any;

  beforeEach(async () => {
    const module: TestingModule = await Test.createTestingModule({
      imports: [
        AuthModule.forRoot({
          mode: 'normal',
          jwtSecret: 'test-secret',
          authRepository: MockUserRepository,
          strategies: { local: true, jwt: true },
        }),
      ],
    }).compile();

    service = module.get(AUTH_SERVICE);
  });

  it('should create a session', async () => {
    const user = { id: '123', roles: ['user'] };
    const session = await service.createSession(user);
    
    expect(session).toHaveProperty('accessToken');
    expect(session).toHaveProperty('refreshToken');
    expect(session.sub).toBe('123');
  });
});

📊 Swagger Integration

The package automatically integrates with Swagger:

import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';

// In main.ts
const config = new DocumentBuilder()
  .setTitle('API Documentation')
  .setDescription('API with nest-authify')
  .setVersion('1.0')
  .addBearerAuth() // Add this for JWT
  .build();

const document = SwaggerModule.createDocument(app, config);
SwaggerModule.setup('api', app, document);

All auth endpoints are automatically documented with:

  • Request/Response DTOs
  • Authentication requirements
  • Error responses
  • Example values

🔒 Security Best Practices

  1. Strong JWT Secrets: Use long, random strings
  2. Short Token Expiration: Keep access tokens short-lived (15-60 minutes)
  3. Refresh Token Rotation: Implement refresh token rotation for better security
  4. HTTPS Only: Always use HTTPS in production
  5. Rate Limiting: Implement rate limiting on auth endpoints
  6. Password Strength: Validate password strength on registration
  7. Session Revocation: Implement session revocation for logout
  8. Audit Logging: Log authentication events

🤝 Contributing

Contributions are welcome! Please follow these steps:

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments

📧 Support

🗺️ Roadmap

  • [ ] Support for more OAuth providers (Apple, LinkedIn, Twitter)
  • [ ] Permission-based authorization system (CASL integration)
  • [ ] Two-Factor Authentication (2FA)
  • [ ] Magic link authentication
  • [ ] WebSocket authentication support
  • [ ] GraphQL integration
  • [ ] Rate limiting integration
  • [ ] Audit logging
  • [ ] Admin dashboard for session management
  • [ ] Multi-tenancy support
  • [ ] Biometric authentication support

Made with ❤️ by UnCompa