0.1.0-alpha.12 β€’ Published 4 months ago

@re-auth/reauth v0.1.0-alpha.12

Weekly downloads
-
License
-
Repository
github
Last release
4 months ago

πŸ” ReAuth - Modular Authentication System

ReAuth is a flexible, plugin-based authentication system for Node.js applications. It provides a robust framework for handling various authentication methods while maintaining a clean and extensible architecture.

πŸš€ Features

  • Plugin-based Architecture: Easily extendable with custom authentication methods
  • Multiple Authentication Flows: Supports email/password, passwordless, and more
  • TypeScript First: Built with TypeScript for enhanced developer experience
  • Dependency Injection: Powered by Awilix for clean dependency management
  • Session Management: Built-in session handling with token support
  • Extensible: Create custom authentication plugins for any use case

πŸ“¦ Installation

pnpm add @re-auth/reauth
# or
yarn add @re-auth/reauth
# or
npm install @re-auth/reauth

πŸ› οΈ Getting Started

Basic Setup

import { ReAuthEngine, emailPasswordAuth } from '@re-auth/reauth';
import { KnexEntityService, KnexSessionService } from './services';

// Initialize your entity and session services
const entityService = new KnexEntityService(knex);
const sessionService = new KnexSessionService(knex);

// Create an email/password auth plugin
const emailPassword = emailPasswordAuth({
  verifyEmail: true,
  loginOnRegister: true,
  async sendCode(entity, code, email, type) {
    // Implement your email sending logic here
    console.log(`Sending ${type} code ${code} to ${email}`);
  },
});

// Initialize the auth engine
const auth = new ReAuthEngine({
  plugins: [emailPassword],
  entity: entityService,
  session: sessionService,
  sensitiveFields: {
    password: true,
    token: true,
  },
});

πŸ”Œ Built-in Plugins

Email/Password Authentication

import { emailPasswordAuth } from '@re-auth/reauth';

const emailPassword = emailPasswordAuth({
  verifyEmail: true, // Require email verification
  loginOnRegister: true, // Automatically login after registration
  codeType: 'numeric', // Code type for verification/reset ('numeric' | 'alphanumeric' | 'alphabet')
  codeLenght: 6, // Length of the verification code
  resetPasswordCodeExpiresIn: 30 * 60 * 1000, // 30 minutes

  // Required for email verification and password reset
  async sendCode(entity, code, email, type) {
    // Send email with the code
    console.log(`Sending ${type} code ${code} to ${email}`);
  },

  // Optional: Custom code generator
  async generateCode(email, entity) {
    return Math.floor(100000 + Math.random() * 900000); // 6-digit code
  },
});

🧩 Creating Custom Plugins

ReAuth supports two types of plugins:

1. Object-Based Plugin

import { AuthPlugin } from '@re-auth/reauth';

const myPlugin: AuthPlugin = {
  name: 'my-auth-plugin',
  version: '1.0.0',

  steps: [
    {
      name: 'authenticate',
      description: 'Custom authentication step',
      async run(input, { container }) {
        // Your authentication logic here
        return {
          success: true,
          message: 'Authenticated successfully',
          status: 'authenticated',
        };
      },
      inputs: ['username', 'password'],
    },
  ],

  initialize(container) {
    // Initialize your plugin here
  },

  getSensitiveFields() {
    return ['password', 'token'];
  },
};

2. Class-Based Plugin

import { AuthPlugin, AuthStep } from '@re-auth/reauth';

export class MyAuthPlugin implements AuthPlugin {
  name = 'my-auth-plugin';
  version = '1.0.0';
  steps: AuthStep[] = [];

  constructor(private container: any) {
    this.steps = [
      {
        name: 'authenticate',
        description: 'Custom authentication step',
        run: this.authenticate.bind(this),
        inputs: ['username', 'password'],
      },
    ];
  }

  private async authenticate(input: any) {
    // Your authentication logic here
    return {
      success: true,
      message: 'Authenticated successfully',
      status: 'authenticated',
    };
  }

  async initialize() {
    // Initialize your plugin here
  }

  getSensitiveFields() {
    return ['password', 'token'];
  }
}

πŸ“š API Reference

ReAuthEngine

The main authentication engine that manages plugins and authentication flows.

const auth = new ReAuthEngine({
  plugins: AuthPlugin[],      // Array of authentication plugins
  entity: EntityService,     // Entity service implementation
  session: SessionService,   // Session service implementation
  sensitiveFields?: {        // Fields to redact in logs
    [key: string]: boolean;
  };
  authHooks?: AuthHooks[];   // Global authentication hooks
});

Built-in Services

  • EntityService: Manages user entities
  • SessionService: Handles session management
  • KnexEntityService: Knex-based entity service
  • KnexSessionService: Knex-based session service

πŸ“ License

MIT

🧱 Plugin Interface

interface AuthPlugin {
  name: string;
  version: string;
  steps: AuthStep[];
  defaultConfig?: Record<string, any>;
  requiredInput?: RequiredInputShape;
  initialize?(container?: AwilixContainer): void | Promise<void>;
}

πŸͺœ Step Structure

Each step is a discrete auth flow like login, register, etc.

interface AuthStep {
  name: string;
  description: string;
  validationSchema?: ValidationSchema;
  run(input: AuthInput): Promise<any>;
  hooks?: {
    before?: HookFunction[];
    after?: HookFunction[];
    onError?: (error: Error, input: AuthInput) => Promise<void>;
  };
}

πŸ“‘ Validation Schema

type ValidationSchema = Record<string, ((value: any, input: AuthInput) => string | undefined)[]>;

You can also use Standard Schema compliant validators (see Standard Schema Support below).

βœ… Required Input Flags

Defines what the plugin step expects:

interface RequiredInputShape {
  reqBody?: boolean;
  reqQuery?: boolean;
  reqParams?: boolean;
  reqHeaders?: boolean;
  reqMethod?: boolean;
}

πŸͺ Hook Types

type HookFunction = (input: AuthInput, output?: any) => Promise<void>;

🚦Plugin Lifecycle

The lifecycle of a plugin follows these steps:

npm.io

⚠️ Object Plugin Restrictions

  • ❌ Do not use this in run functions or hooks.
  • βœ… Capture context using top-level variables or closures.
  • ⚠️ If plugin requires internal state, switch to class format.

πŸ§ͺ Example Registry

export const authPlugins: AuthPlugin[] = [emailPasswordPlugin, new MagicLinkPlugin(), new OauthPlugin()];

βœ… Summary

Formatthis AllowedLifecycle SupportBest For
Object-based❌ Noβœ… YesLightweight plugins
Class-basedβœ… Yesβœ… YesStateful or complex plugins

πŸ”„ Standard Schema Support

ReAuth supports Standard Schema for validation, allowing you to use any compatible validation library (like Zod, Valibot, ArkType, etc.) with your plugins.

Using Standard Schema in a Plugin

import { type } from 'arktype';
import { createStandardSchemaRule } from '@the-forgebase/reauth/utils';

// Define schemas using ArkType (which implements standard-schema)
const emailSchema = type('string.email');
const passwordSchema = type('string.alphanumeric >= 3');

// Create validation rules using standard-schema
const loginValidation = {
  email: createStandardSchemaRule(emailSchema, 'Please enter a valid email address'),
  password: createStandardSchemaRule(passwordSchema, 'Password must be at least 8 characters'),
};

Direct Validation with Standard Schema

You can also use the standardValidate utility function to validate data directly:

import { standardValidate } from '@the-forgebase/reauth/utils';
import { type } from 'arktype';

const userSchema = type({
  email: 'string.email',
  password: 'string.alphanumeric >= 8',
});

try {
  const validatedUser = await standardValidate(userSchema, userData);
  console.log('Valid user data:', validatedUser);
} catch (error) {
  console.error('Validation failed:', error);
}