🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@vitra-ai/nestjs-auth

Package Overview
Dependencies
Maintainers
5
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install
Package was removed
Sorry, it seems this package was removed from the registry

@vitra-ai/nestjs-auth

Authentication package with Better Auth integration for NestJS

latest
Source
npmnpm
Version
0.1.0
Version published
Maintainers
5
Created
Source

@vitra-ai/nestjs-auth

Authentication package with Better Auth integration for NestJS applications. Provides a complete authentication solution with support for social providers, email OTP, magic links, and multi-organization support.

Features

  • 🔐 Better Auth Integration: Full Better Auth support with NestJS
  • 👥 Social Authentication: Google OAuth and more
  • 📧 Email OTP & Magic Links: Passwordless authentication
  • 🏢 Organizations: Multi-tenant organization support with roles
  • 🛡️ Guards: Ready-to-use authentication guards (Auth, Admin, Organization)
  • 🔑 Access Control: Role-based and organization-scoped permissions system
  • 📦 Sequelize Models: Pre-configured database models
  • 🎯 Type-safe: Full TypeScript support

Installation

npm install @vitra-ai/nestjs-auth
# or
yarn add @vitra-ai/nestjs-auth
# or
bun add @vitra-ai/nestjs-auth

Peer Dependencies

npm install @nestjs/common @nestjs/core @nestjs/config @nestjs/sequelize better-auth express pg sequelize sequelize-typescript

Quick Start

1. Create Auth Configuration

// src/auth.config.ts
import { createAuth } from '@vitra-ai/nestjs-auth';

export const auth = createAuth({
  baseURL: process.env.BASE_URL || 'http://localhost:3000',
  trustedOrigins: ['http://localhost:3000'],
  secret: process.env.AUTH_SECRET!,
  appName: 'My App',
  database: {
    host: process.env.DB_HOST!,
    user: process.env.DB_USER!,
    password: process.env.DB_PASSWORD!,
    database: process.env.DB_NAME!,
    ssl: {
      rejectUnauthorized: false,
    },
  },
  socialProviders: {
    google: {
      enabled: true,
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
      redirectURI: `${process.env.BASE_URL}/api/auth/callback/google`,
    },
  },
  emailOTP: {
    disableSignUp: true,
    sendVerificationOTP: async ({ email, otp }) => {
      // Send email with OTP
      console.log(`Send OTP ${otp} to ${email}`);
    },
  },
});

2. Set Up Your App Module

import { Module } from '@nestjs/common';
import { SequelizeModule } from '@nestjs/sequelize';
import {
  AuthModule,
  User,
  Session,
  Account,
  Verification,
  Organization,
  Member,
  Invitation,
  OrganizationRole,
} from '@vitra-ai/nestjs-auth';
import { auth } from './auth.config';

@Module({
  imports: [
    SequelizeModule.forRoot({
      // ... your Sequelize config
    }),
    AuthModule.forRoot(auth, {
      imports: [
        SequelizeModule.forFeature([
          User,
          Session,
          Account,
          Verification,
          Organization,
          Member,
          Invitation,
          OrganizationRole,
        ]),
      ],
    }),
  ],
})
export class AppModule {}

3. Use Auth Guard

import { Controller, Get, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@vitra-ai/nestjs-auth';

@Controller('protected')
@UseGuards(AuthGuard)
export class ProtectedController {
  @Get()
  getProtectedData() {
    return { message: 'This is protected!' };
  }
}

API Reference

createAuth(options)

Factory function to create a Better Auth instance with opinionated defaults.

Options:

{
  baseURL: string;              // Base URL of your app
  trustedOrigins: string[];     // CORS allowed origins
  secret: string;               // Auth secret key
  appName: string;              // Application name
  database: {                   // Database configuration
    host: string;
    user: string;
    password: string;
    database: string;
    ssl?: { rejectUnauthorized: boolean };
  };
  socialProviders?: {           // Social auth providers
    google?: {
      enabled: boolean;
      clientId: string;
      clientSecret: string;
      redirectURI: string;
      disableSignUp?: boolean;
      scope?: string[];
    };
  };
  emailOTP?: {                  // Email OTP configuration
    disableSignUp?: boolean;
    sendVerificationOTP: (data) => Promise<void>;
  };
  magicLink?: {                 // Magic link configuration
    sendMagicLink: (data) => Promise<void>;
  };
  additionalUserFields?: Record<string, any>;
  additionalOptions?: BetterAuthOptions;
}

AuthModule

NestJS module for authentication.

Methods:

  • forRoot(auth, options?) - Configure module with auth instance
  • forRootAsync(options) - Configure module asynchronously

AuthGuard

Authentication guard for protecting routes.

Usage:

@UseGuards(AuthGuard)
@Controller('api')
export class ApiController {
  @Get('profile')
  getProfile(@Request() req) {
    return req.user; // User attached by guard
  }
}

AuthService

Service for accessing auth API.

@Injectable()
export class MyService {
  constructor(private authService: AuthService) {}

  async getSession(headers) {
    return this.authService.api.getSession({ headers });
  }
}

Models

Pre-configured Sequelize models:

  • User - User model
  • Session - Session model
  • Account - OAuth account model
  • Verification - Verification token model
  • Organization - Organization model
  • Member - Organization member model
  • Invitation - Organization invitation model
  • OrganizationRole - Organization role model

Environment Variables

# Required
AUTH_SECRET=your-secret-key-min-32-chars
BASE_URL=http://localhost:3000
DB_HOST=localhost
DB_USER=postgres
DB_PASSWORD=password
DB_NAME=myapp

# Optional - Google OAuth
GOOGLE_CLIENT_ID=your-client-id
GOOGLE_CLIENT_SECRET=your-client-secret

Permissions & Access Control

The package includes a built-in role-based access control system powered by Better Auth's admin plugin with access control.

Permissions API

The PermissionsController is automatically included in the AuthModule, so you don't need to add it manually. Once you import AuthModule, the permissions endpoint is available:

GET /api/auth/permissions

Response:

{
  "resources": [
    {
      "resource": "user",
      "actions": ["create", "list", "set-role", "ban", "impersonate", "delete", "set-password"],
      "permissions": ["user:create", "user:list", ...]
    },
    {
      "resource": "project",
      "actions": ["create", "share", "update", "delete"],
      "permissions": ["project:create", "project:share", ...]
    }
  ],
  "flat": ["user:create", "user:list", ..., "project:create", ...]
}

Using the Admin Permission Guard

Protect routes with global admin-level permission checks using the @RequirePermissions decorator:

import { Controller, Get, UseGuards } from '@nestjs/common';
import { AdminPermissionGuard, RequirePermissions } from '@vitra-ai/nestjs-auth';

@Controller('admin')
@UseGuards(AdminPermissionGuard)
export class AdminController {
  @Get('users')
  @RequirePermissions({ user: ['list'] })
  listUsers() {
    // Only users with 'user:list' permission can access
    return this.userService.findAll();
  }

  @Delete('users/:id')
  @RequirePermissions({ user: ['delete'] })
  deleteUser(@Param('id') id: string) {
    // Only users with 'user:delete' permission can access
    return this.userService.delete(id);
  }
}

Using the Organization Permission Guard

Protect routes with organization-scoped permission checks using the OrganizationPermissionGuard. This guard validates that users are members of the organization and have the required permissions within that organization context.

import { Controller, Get, Post, Param, UseGuards } from '@nestjs/common';
import {
  AuthGuard,
  OrganizationPermissionGuard,
  RequireOrgPermissions,
  OrgIdFrom,
} from '@vitra-ai/nestjs-auth';

@Controller('organizations/:orgId/projects')
@UseGuards(AuthGuard, OrganizationPermissionGuard)
export class ProjectController {
  // List projects - requires project:create permission in the organization
  @Get()
  @OrgIdFrom({ type: 'param', key: 'orgId' })
  @RequireOrgPermissions({ permissions: { project: ['create'] } })
  listProjects(@Param('orgId') orgId: string) {
    return this.projectService.findAll(orgId);
  }

  // Create project - requires project:create permission
  @Post()
  @OrgIdFrom({ type: 'param', key: 'orgId' })
  @RequireOrgPermissions({ permissions: { project: ['create'] } })
  createProject(@Param('orgId') orgId: string, @Body() dto: CreateProjectDto) {
    return this.projectService.create(orgId, dto);
  }

  // Delete project - requires owner or admin role
  @Delete(':projectId')
  @OrgIdFrom({ type: 'param', key: 'orgId' })
  @RequireOrgPermissions({ roles: ['owner', 'admin'] })
  deleteProject(@Param('orgId') orgId: string, @Param('projectId') projectId: string) {
    return this.projectService.delete(orgId, projectId);
  }
}

Key differences between guards:

FeatureAdminPermissionGuardOrganizationPermissionGuard
ScopeGlobal/Application-wideOrganization-specific
Membership CheckNoYes
Organization ContextNot requiredRequired
Use CaseAdmin-only featuresOrganization resources

The @OrgIdFrom decorator specifies where to extract the organization ID from:

// From URL parameter
@OrgIdFrom({ type: 'param', key: 'orgId' })

// From request body
@OrgIdFrom({ type: 'body', key: 'organizationId' })

// From query string
@OrgIdFrom({ type: 'query', key: 'org' })

// From HTTP header
@OrgIdFrom({ type: 'header', key: 'x-organization-id' })

For detailed examples and best practices, see ORG_PERMISSION_GUARD.md.

Using Permissions in Services

import { Injectable, ForbiddenException } from '@nestjs/common';
import { roles, type Role } from '@vitra-ai/nestjs-auth';

@Injectable()
export class ProjectService {
  async createProject(userRole: Role) {
    if (!roles[userRole].authorize({ project: ['create'] }).success) {
      throw new ForbiddenException('You do not have permission to create projects');
    }
    
    // Create project logic...
  }
}

Customizing Permissions

You can extend or modify the permissions in your application:

// In your app's permissions.ts
import { createAccessControl } from 'better-auth/plugins/access';
import { defaultStatements } from 'better-auth/plugins/organization/access';

const customStatement = {
  ...defaultStatements,
  project: ['create', 'share', 'update', 'delete'],
  document: ['read', 'write', 'delete'],
  report: ['view', 'generate', 'export'],
} as const;

export const customAc = createAccessControl(customStatement);

export const customAdmin = customAc.newRole({
  organization: ['create', 'update', 'delete'],
  project: ['create', 'update', 'delete'],
  document: ['read', 'write', 'delete'],
  report: ['view', 'generate', 'export'],
});

Available Default Roles

  • admin: Full admin permissions (includes all user/session management from Better Auth admin plugin) + full project access
  • manager: Can create and update projects but cannot delete
  • user: Basic user with minimal permissions

Checking Permissions Server-Side

Use Better Auth's userHasPermission API:

import { AuthService } from '@vitra-ai/nestjs-auth';
import { fromNodeHeaders } from 'better-auth/api';

@Injectable()
export class MyService {
  constructor(private authService: AuthService) {}

  async checkUserPermission(headers: Record<string, string>) {
    const result = await this.authService.api.userHasPermission({
      headers: fromNodeHeaders(headers),
      body: {
        permissions: {
          project: ['create'],
        },
      },
    });

    return result.success;
  }
}

Advanced Usage

Custom Email Sending

createAuth({
  // ... other options
  emailOTP: {
    sendVerificationOTP: async ({ email, otp, type }) => {
      await yourEmailService.send({
        to: email,
        subject: 'Your verification code',
        text: `Your code is: ${otp}`,
      });
    },
  },
  magicLink: {
    sendMagicLink: async ({ email, url, token }) => {
      await yourEmailService.send({
        to: email,
        subject: 'Sign in to your account',
        html: `<a href="${url}">Click here to sign in</a>`,
      });
    },
  },
});

Adding Custom User Fields

createAuth({
  // ... other options
  additionalUserFields: {
    referralCode: {
      type: 'string',
      required: false,
    },
    subscriptionTier: {
      type: 'string',
      required: true,
    },
  },
});

License

MIT

Keywords

nestjs

FAQs

Package last updated on 19 Nov 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts