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

@ciscode/authentication-kit

v1.5.4

Published

NestJS auth kit with local + OAuth, JWT, RBAC, password reset.

Downloads

236

Readme

AuthKit (NestJS Auth Package)

A production-ready, comprehensive authentication/authorization kit for NestJS with local auth, OAuth (Google/Microsoft/Facebook), JWT tokens, RBAC, admin user management, email verification, and password reset.

Features

  • Local Authentication: Email + password registration & login
  • OAuth Providers:
    • Google (ID Token validation + Authorization Code exchange)
    • Microsoft (Entra ID with JWKS verification)
    • Facebook (App token validation)
    • Web redirect flow (Passport)
    • Mobile token/code exchange
  • JWT Management:
    • Access tokens (stateless, short-lived)
    • Refresh tokens (long-lived JWTs with automatic invalidation on password change)
    • Email verification tokens (JWT-based links)
    • Password reset tokens (JWT-based links)
  • Email Verification: Required before login
  • Password Reset: JWT-secured reset link
  • Admin User Management: Create, list, ban/unban, delete, assign roles
  • RBAC (Role-Based Access Control):
    • Roles linked to users
    • Permissions linked to roles
    • Roles automatically included in JWT payload (Ids)
    • Fine-grained access control
  • Host App Control: Package uses host app's Mongoose connection (no DB lock-in)

Install

npm i @ciscode/authentication-kit

Host App Setup

1. Environment Variables

# Database
MONGO_URI=mongodb://127.0.0.1:27017/app_db

# JWT Configuration
JWT_SECRET=your_super_secret_key_change_this
JWT_ACCESS_TOKEN_EXPIRES_IN=15m
JWT_REFRESH_SECRET=your_refresh_secret_change_this
JWT_REFRESH_TOKEN_EXPIRES_IN=7d
JWT_EMAIL_SECRET=your_email_secret_change_this
JWT_EMAIL_TOKEN_EXPIRES_IN=1d
JWT_RESET_SECRET=your_reset_secret_change_this
JWT_RESET_TOKEN_EXPIRES_IN=1h

# Email (SMTP)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
[email protected]
SMTP_PASS=your-app-password
SMTP_SECURE=false
[email protected]

# Frontend URL (for email links)
FRONTEND_URL=http://localhost:3000

# Google OAuth
GOOGLE_CLIENT_ID=your-google-client-id.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=your-google-client-secret
GOOGLE_CALLBACK_URL=http://localhost:3000/api/auth/google/callback

# Microsoft/Entra ID OAuth
MICROSOFT_CLIENT_ID=your-microsoft-client-id
MICROSOFT_CLIENT_SECRET=your-microsoft-client-secret
MICROSOFT_CALLBACK_URL=http://localhost:3000/api/auth/microsoft/callback
MICROSOFT_TENANT_ID=common  # Optional, defaults to 'common'

# Facebook OAuth
FB_CLIENT_ID=your-facebook-app-id
FB_CLIENT_SECRET=your-facebook-app-secret
FB_CALLBACK_URL=http://localhost:3000/api/auth/facebook/callback

# Environment
NODE_ENV=development

2. Host app example

import { Module, OnModuleInit } from '@nestjs/common';
import { MongooseModule } from '@nestjs/mongoose';
import { AuthKitModule, SeedService } from '@ciscode/authentication-kit';

@Module({
  imports: [MongooseModule.forRoot(process.env.MONGO_URI), AuthKitModule],
})
export class AppModule implements OnModuleInit {
  constructor(private readonly seed: SeedService) {}

  async onModuleInit() {
    await this.seed.seedDefaults();
  }
}

NOTES:

The AuthKit, by default seeds database with default roles and permissions once the host app is bootstraped (logs are generated for info) Default user role, on first register, is 'user' ... Mongoose needs Id to do this relation (the app MUST seed db from the package before anything)

API Routes

Local Auth Routes

POST   /api/auth/register              | Register new user (public)
POST   /api/auth/verify-email          | Verify email with token (public)
POST   /api/auth/resend-verification   | Resend verification email (public)
POST   /api/auth/login                 | Login with credentials (public)
POST   /api/auth/refresh-token         | Refresh access token (public)
POST   /api/auth/forgot-password       | Request password reset (public)
POST   /api/auth/reset-password        | Reset password with token (public)
GET    /api/auth/me                    | Get current user profile (protected)
DELETE /api/auth/account               | Delete own account (protected)

OAuth Routes - Mobile Exchange (Public)

Exchange OAuth provider tokens for app tokens:

POST /api/auth/oauth/google       { idToken?: string, code?: string }
POST /api/auth/oauth/microsoft    { idToken: string }
POST /api/auth/oauth/facebook     { accessToken: string }

OAuth Routes - Web Redirect (Public)

Passport-based OAuth flow for web browsers:

GET /api/auth/google                    | Google OAuth
GET /api/auth/google/callback           | Google Redirect (After login)
GET /api/auth/microsoft                 | Microsoft OAuth
GET /api/auth/microsoft/callback        | Microsoft Redirect (After login)
GET /api/auth/facebook                  | Facebook OAuth
GET /api/auth/facebook/callback         | Facebook Redirect (After login)

Admin Routes - Users (Protected with @Admin())

POST   /api/admin/users                         |Create user
GET    /api/admin/users?email=...&username=...  |List users (with filters)
PATCH  /api/admin/users/:id/ban                 |Ban user
PATCH  /api/admin/users/:id/unban               |Unban user
PATCH  /api/admin/users/:id/roles               |Update user roles
DELETE /api/admin/users/:id                     |Delete user

Admin Routes - Roles (Protected with @Admin())

POST   /api/admin/roles                    Create role
GET    /api/admin/roles                    List all roles
PUT    /api/admin/roles/:id                Update role name
PUT    /api/admin/roles/:id/permissions    Set role permissions
DELETE /api/admin/roles/:id                Delete role

Admin Routes - Permissions (Protected with @Admin())

POST   /api/admin/permissions              Create permission
GET    /api/admin/permissions              List all permissions
PUT    /api/admin/permissions/:id          Update permission
DELETE /api/admin/permissions/:id          Delete permission

Usage Examples

Register

Request:

POST /api/auth/register
Content-Type: application/json

{
  "fullname": {
    "fname": "Test",
    "lname": "User"
  },
  "username": "custom-username",
  "email": "[email protected]",
  "password": "Pa$$word!",
  "phoneNumber": "+1234567890",
  "avatar": "https://example.com/avatar.jpg",
  "jobTitle": "Software Engineer",
  "company": "Ciscode"
}

Notes:

  • username is now optional. If not provided, it will be auto-generated as fname-lname (e.g., test-user)
  • jobTitle and company are optional profile fields
  • All other fields work as before

Response:

{
  "id": "507f1f77bcf86cd799439011",
  "email": "[email protected]"
}

Login

Request:

POST /api/auth/login
Content-Type: application/json

{
  "email": "[email protected]",
  "password": "Pa$$word!"
}

Response:

{
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Note: refreshToken is also set in httpOnly cookie

Verify Email

Request:

POST /api/auth/verify-email
Content-Type: application/json

{
  "token": "email-verification-token-from-email"
}

Response:

{
  "ok": true
}

Refresh Token

Request (from body):

POST /api/auth/refresh-token
Content-Type: application/json

{
  "refreshToken": "refresh-token-value"
}

OR (from cookie - automatic):

POST /api/auth/refresh-token
Cookie: refreshToken=refresh-token-value

Response:

{
  "accessToken": "new-access-token",
  "refreshToken": "new-refresh-token"
}

OAuth Google (Mobile Exchange)

Request (with ID Token):

POST /api/auth/oauth/google
Content-Type: application/json

{
  "idToken": "google-id-token-from-client"
}

OR (with Authorization Code):

POST /api/auth/oauth/google
Content-Type: application/json

{
  "code": "authorization-code-from-google"
}

Response:

{
  "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Get Current User Profile

Request:

GET /api/auth/me
Authorization: Bearer access-token

Response:

{
  "ok": true,
  "data": {
    "_id": "507f1f77bcf86cd799439011",
    "fullname": {
      "fname": "Test",
      "lname": "User"
    },
    "username": "test-user",
    "email": "[email protected]",
    "avatar": "https://example.com/avatar.jpg",
    "phoneNumber": "+1234567890",
    "jobTitle": "Software Engineer",
    "company": "Ciscode",
    "isVerified": true,
    "isBanned": false,
    "roles": [
      {
        "_id": "507f1f77bcf86cd799439012",
        "name": "user",
        "permissions": [
          {
            "_id": "507f1f77bcf86cd799439013",
            "name": "read:profile"
          }
        ]
      }
    ],
    "createdAt": "2026-01-28T10:00:00.000Z",
    "updatedAt": "2026-01-28T10:00:00.000Z"
  }
}

Note: Sensitive fields like password and passwordChangedAt are automatically excluded from the response.

Delete Account

Request:

DELETE /api/auth/account
Authorization: Bearer access-token

Response:

{
  "ok": true
}

Guards & Decorators

AuthenticateGuard: Protects routes that require authentication. (No Access if not authenticated) Admin Decorator: Restricts routes to admin users only. (No Access if not an admin)

JWT Token Structure

Access Token Payload

{
  "sub": "user-id",
  "roles": ["ids"],
  "iat": 1672531200,
  "exp": 1672531900
}

Refresh Token Payload

{
  "sub": "user-id",
  "purpose": "refresh",
  "iat": 1672531200,
  "exp": 1672617600
}

Security Note: Refresh tokens are automatically invalidated if user changes password. The passwordChangedAt timestamp is checked during token refresh.

Seeding

On app startup via onModuleInit(), the following are created:

Roles:

  • admin - Full permissions
  • user - No default permissions

Permissions:

  • users:manage - Create, list, ban, delete users
  • roles:manage - Create, list, update, delete roles
  • permissions:manage - Create, list, update, delete permissions

All permissions are assigned to the admin role.

User Model

{
  _id: ObjectId,
  fullname: {
    fname: string,
    lname: string
  },
  username: string (unique, 3-30 chars, auto-generated as fname-lname if not provided),
  email: string (unique, validated),
  phoneNumber?: string (unique, 10-14 digits),
  avatar?: string (default: 'default.jpg'),
  jobTitle?: string,
  company?: string,
  password: string (hashed, min 6 chars),
  roles: ObjectId[] (references Role),
  isVerified: boolean (default: false),
  isBanned: boolean (default: false),
  passwordChangedAt: Date,
  createdAt: Date,
  updatedAt: Date
}

Role Model

{
  _id: ObjectId,
  name: string (unique),
  permissions: ObjectId[] (references Permission),
  createdAt: Date,
  updatedAt: Date
}

Permission Model

{
  _id: ObjectId,
  name: string (unique),
  description?: string,
  createdAt: Date,
  updatedAt: Date
}

Important Notes

  • Database: AuthKit does NOT manage MongoDB connection. Your host app must provide the connection via MongooseModule.forRoot().
  • Stateless: JWTs are stateless; refresh tokens are signed JWTs (not stored in DB).
  • Email Verification Required: Users cannot login until they verify their email.
  • Password Changes Invalidate Tokens: All refresh tokens become invalid immediately after password change.
  • OAuth Auto-Registration: Users logging in via OAuth are automatically created with verified status.
  • Cookie + Body Support: Refresh tokens can be passed via httpOnly cookies OR request body.
  • Admin Access: Routes under /api/admin/* require the admin role (enforced by @Admin() decorator).

Error Handling

The package throws errors with descriptive messages. Your host app should catch and format them appropriately:

try {
  await authService.login(dto);
} catch (error) {
  // Possible errors:
  // "Invalid credentials."
  // "Account banned."
  // "Email not verified."
  // "User not found."
  // "JWT_SECRET is not set"
  // etc.
}

Development

npm run build      # Compile TypeScript + alias paths
npm run start      # Run standalone (if applicable)
npm run test       # Run tests (currently no tests defined)

License

MIT

Author

Ciscode


Version: 1.2.0