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

@bastionauth/core

v0.1.7

Published

Shared types, constants, and utilities for BastionAuth

Downloads

956

Readme

@bastionauth/core


📚 Table of Contents


🏰 What is BastionAuth?

BastionAuth is a complete, self-hostable enterprise authentication system that gives you the developer experience of Clerk with full data sovereignty.

Key Features

  • 🔐 Complete Authentication - Email/password, OAuth (Google, GitHub, Microsoft, Apple, LinkedIn), magic links, passkeys
  • 🔑 Multi-Factor Authentication - TOTP, backup codes, WebAuthn support
  • 🏢 Organizations & RBAC - Full multi-tenancy with role-based access control
  • 🎨 Beautiful React Components - Pre-built UI with glass morphism design
  • Next.js Integration - Middleware, server components, API helpers
  • 🔒 Enterprise Security - Argon2id hashing, RS256 JWT, breach detection, audit logging
  • 📊 Admin Dashboard - User management, organization control, webhooks, analytics
  • 🐳 Self-Hosted - Full control over your data, no per-MAU costs, HIPAA/FedRAMP ready

Learn more: https://bastionauth.dev


🎯 When to Use This Package

✅ You SHOULD use @bastionauth/core if you:

  • Are building a custom API client for BastionAuth
  • Need type definitions for your custom integration
  • Are building a backend service that integrates with BastionAuth
  • Want to create a CLI tool for managing BastionAuth
  • Need validation utilities for email, passwords, etc.
  • Are building a non-React frontend (Vue, Angular, Svelte, etc.)
  • Want to build custom authentication UI from scratch
  • Need TypeScript types for API responses

❌ You should NOT use this if you:


📦 Installation

npm install @bastionauth/core

Or using other package managers:

# pnpm
pnpm add @bastionauth/core

# yarn
yarn add @bastionauth/core

# bun
bun add @bastionauth/core

TypeScript Configuration

Ensure your tsconfig.json includes:

{
  "compilerOptions": {
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "esModuleInterop": true
  }
}

📂 What's Included

This package contains NO UI components and NO framework-specific code. It's a pure TypeScript library with:

| Category | What It Includes | |----------|------------------| | Types | User, Session, Organization, Token, MFA, Webhook, Audit Log types | | Validation | Email, password, phone, URL validators | | Constants | Password rules, token config, error codes, event names | | Utilities | Helper functions for data manipulation and validation | | Enums | User roles, session status, organization roles, MFA methods |

Bundle Size: ~15KB (minified) - Minimal footprint!


🔤 Complete Type Reference

User Types

User - Complete User Object

import type { User } from '@bastionauth/core';

const user: User = {
  // Core Identity
  id: 'user_1234567890',
  email: '[email protected]',
  emailVerified: true,
  phone: '+15551234567',
  phoneVerified: false,
  
  // Personal Information
  firstName: 'John',
  lastName: 'Doe',
  username: 'johndoe',
  avatarUrl: 'https://cdn.example.com/avatars/johndoe.jpg',
  
  // Authentication
  passwordHash: null, // Only populated on backend
  mfaEnabled: true,
  
  // Status & Metadata
  status: 'active', // 'active' | 'suspended' | 'banned' | 'deleted'
  role: 'user', // 'user' | 'admin' | 'moderator'
  metadata: {
    source: 'google_oauth',
    lastLoginIp: '192.168.1.1',
    customField: 'custom value'
  },
  
  // Timestamps
  createdAt: new Date('2024-01-01'),
  updatedAt: new Date('2024-01-15'),
  lastActiveAt: new Date('2024-01-15T10:30:00'),
  emailVerifiedAt: new Date('2024-01-01'),
};

PublicUser - Public-Safe User Data

import type { PublicUser } from '@bastionauth/core';

// Safe to expose in public APIs
const publicUser: PublicUser = {
  id: 'user_1234567890',
  firstName: 'John',
  lastName: 'Doe',
  username: 'johndoe',
  avatarUrl: 'https://cdn.example.com/avatars/johndoe.jpg',
  createdAt: new Date('2024-01-01'),
};

// Excludes: email, phone, passwordHash, mfaEnabled, metadata

UserMetadata - Custom User Metadata

import type { UserMetadata } from '@bastionauth/core';

const metadata: UserMetadata = {
  // Completely flexible - add any custom fields
  companyName: 'Acme Corp',
  department: 'Engineering',
  employeeId: 'EMP-12345',
  preferences: {
    theme: 'dark',
    language: 'en-US',
  },
  tags: ['premium', 'beta-tester'],
};

Authentication Types

SignInRequest - Sign-In Payload

import type { SignInRequest } from '@bastionauth/core';

// Email/Password Sign-In
const signInRequest: SignInRequest = {
  email: '[email protected]',
  password: 'SecurePassword123!',
  rememberMe: true, // Optional: extend session duration
  mfaCode: '123456', // Optional: if MFA is enabled
};

SignUpRequest - Registration Payload

import type { SignUpRequest } from '@bastionauth/core';

const signUpRequest: SignUpRequest = {
  email: '[email protected]',
  password: 'SecurePassword123!',
  firstName: 'Jane',
  lastName: 'Smith',
  username: 'janesmith', // Optional
  metadata: { // Optional custom fields
    source: 'landing-page',
    referralCode: 'FRIEND20',
  },
};

TokenPair - Access + Refresh Tokens

import type { TokenPair } from '@bastionauth/core';

const tokens: TokenPair = {
  accessToken: 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...',
  refreshToken: 'rt_a1b2c3d4e5f6g7h8i9j0',
  expiresIn: 900, // 15 minutes in seconds
  tokenType: 'Bearer',
};

AccessTokenPayload - JWT Structure

import type { AccessTokenPayload } from '@bastionauth/core';

const jwtPayload: AccessTokenPayload = {
  sub: 'user_1234567890', // User ID
  email: '[email protected]',
  role: 'user',
  orgId: 'org_abcd1234', // Active organization ID
  orgRole: 'member', // Role in that organization
  sessionId: 'sess_xyz789',
  iat: 1704067200, // Issued at (Unix timestamp)
  exp: 1704067800, // Expires at (Unix timestamp)
};

Session Types

Session - Session Object

import type { Session } from '@bastionauth/core';

const session: Session = {
  id: 'sess_xyz789',
  userId: 'user_1234567890',
  
  // Session Details
  status: 'active', // 'active' | 'expired' | 'revoked'
  ipAddress: '192.168.1.1',
  userAgent: 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)...',
  
  // Timestamps
  createdAt: new Date('2024-01-15T10:00:00'),
  expiresAt: new Date('2024-01-22T10:00:00'),
  lastActivityAt: new Date('2024-01-15T10:30:00'),
};

Organization Types

Organization - Organization Object

import type { Organization } from '@bastionauth/core';

const organization: Organization = {
  id: 'org_abcd1234',
  name: 'Acme Corporation',
  slug: 'acme-corp',
  
  // Branding
  logoUrl: 'https://cdn.example.com/logos/acme.png',
  primaryColor: '#6366f1',
  
  // Settings
  settings: {
    allowSignUps: false,
    requireMfa: true,
    sessionDuration: 86400, // 24 hours
  },
  
  // Metadata
  metadata: {
    industry: 'Technology',
    size: 'enterprise',
  },
  
  // Timestamps
  createdAt: new Date('2023-01-01'),
  updatedAt: new Date('2024-01-15'),
};

OrganizationMembership - User's Membership

import type { OrganizationMembership } from '@bastionauth/core';

const membership: OrganizationMembership = {
  id: 'mem_xyz123',
  userId: 'user_1234567890',
  organizationId: 'org_abcd1234',
  
  // Role & Permissions
  role: 'admin', // 'owner' | 'admin' | 'member' | 'guest'
  permissions: ['users:read', 'users:write', 'settings:read'],
  
  // Timestamps
  joinedAt: new Date('2023-06-15'),
  createdAt: new Date('2023-06-15'),
  updatedAt: new Date('2024-01-15'),
};

OrganizationInvitation - Invitation Object

import type { OrganizationInvitation } from '@bastionauth/core';

const invitation: OrganizationInvitation = {
  id: 'inv_abc123',
  organizationId: 'org_abcd1234',
  
  // Invitation Details
  email: '[email protected]',
  role: 'member',
  invitedBy: 'user_1234567890',
  
  // Status
  status: 'pending', // 'pending' | 'accepted' | 'expired' | 'revoked'
  token: 'inv_token_secure_random_string',
  
  // Timestamps
  createdAt: new Date('2024-01-15'),
  expiresAt: new Date('2024-01-22'),
  acceptedAt: null,
};

MFA Types

MfaMethod - MFA Method Enum

import type { MfaMethod } from '@bastionauth/core';

const method: MfaMethod = 'totp'; // 'totp' | 'sms' | 'email' | 'backup_codes' | 'webauthn'

TOTPSetup - TOTP Setup Response

import type { TOTPSetup } from '@bastionauth/core';

const totpSetup: TOTPSetup = {
  secret: 'JBSWY3DPEHPK3PXP',
  qrCode: 'data:image/png;base64,iVBORw0KGgoAAAANS...',
  backupCodes: [
    '1234-5678',
    '9012-3456',
    '7890-1234',
    '5678-9012',
    '3456-7890',
  ],
};

API Response Types

ApiResponse<T> - Standard API Response

import type { ApiResponse, User } from '@bastionauth/core';

const successResponse: ApiResponse<User> = {
  success: true,
  data: {
    id: 'user_1234567890',
    email: '[email protected]',
    // ... rest of user data
  },
  message: 'User fetched successfully',
};

const errorResponse: ApiResponse<never> = {
  success: false,
  error: {
    code: 'USER_NOT_FOUND',
    message: 'User with ID user_1234567890 not found',
    details: {
      userId: 'user_1234567890',
    },
  },
};

PaginatedResponse<T> - Paginated Lists

import type { PaginatedResponse, User } from '@bastionauth/core';

const paginatedUsers: PaginatedResponse<User> = {
  data: [
    { id: 'user_1', email: '[email protected]', /* ... */ },
    { id: 'user_2', email: '[email protected]', /* ... */ },
    { id: 'user_3', email: '[email protected]', /* ... */ },
  ],
  pagination: {
    page: 1,
    perPage: 10,
    total: 47,
    totalPages: 5,
    hasMore: true,
  },
};

✅ Validation Utilities

Email Validation

import { validateEmail, isValidEmail } from '@bastionauth/core';

// Method 1: Boolean check
if (isValidEmail('[email protected]')) {
  console.log('Valid email!');
}

// Method 2: Detailed validation
const result = validateEmail('invalid-email');
if (!result.valid) {
  console.error('Email validation failed:', result.error);
  // Output: "Email validation failed: Invalid email format"
}

// Examples
isValidEmail('[email protected]');        // ✅ true
isValidEmail('[email protected]'); // ✅ true
isValidEmail('user@');                   // ❌ false
isValidEmail('not-an-email');            // ❌ false

Password Validation

import { validatePassword, PASSWORD_CONFIG } from '@bastionauth/core';

const result = validatePassword('MyPassword123!');

console.log(result);
// {
//   valid: true,
//   strength: 'strong', // 'weak' | 'medium' | 'strong' | 'very_strong'
//   score: 4, // 0-5
//   errors: [],
//   suggestions: []
// }

// Weak password example
const weakResult = validatePassword('12345678');
console.log(weakResult);
// {
//   valid: false,
//   strength: 'weak',
//   score: 1,
//   errors: [
//     'Password must contain at least one uppercase letter',
//     'Password must contain at least one special character'
//   ],
//   suggestions: [
//     'Add uppercase letters',
//     'Include special characters (!@#$%^&*)'
//   ]
// }

// Password configuration
console.log(PASSWORD_CONFIG);
// {
//   MIN_LENGTH: 8,
//   MAX_LENGTH: 128,
//   REQUIRE_UPPERCASE: true,
//   REQUIRE_LOWERCASE: true,
//   REQUIRE_NUMBER: true,
//   REQUIRE_SPECIAL: true,
//   SPECIAL_CHARS: '!@#$%^&*()_+-=[]{}|;:,.<>?'
// }

Phone Validation

import { validatePhone, formatPhone } from '@bastionauth/core';

// Validate phone numbers
const isValid = validatePhone('+15551234567');
console.log(isValid); // true

// Format phone numbers
const formatted = formatPhone('5551234567', 'US');
console.log(formatted); // '+15551234567'

// Supported formats
validatePhone('+15551234567');   // ✅ true (E.164)
validatePhone('555-123-4567');   // ✅ true (US format)
validatePhone('(555) 123-4567'); // ✅ true (US format with parens)
validatePhone('+44 20 7946 0958'); // ✅ true (UK format)

URL Validation

import { validateUrl, isSecureUrl } from '@bastionauth/core';

// Validate URLs
const isValid = validateUrl('https://example.com');
console.log(isValid); // true

// Check if URL is secure (HTTPS)
const isSecure = isSecureUrl('https://example.com');
console.log(isSecure); // true

const notSecure = isSecureUrl('http://example.com');
console.log(notSecure); // false

// Examples
validateUrl('https://example.com');        // ✅ true
validateUrl('http://localhost:3000');      // ✅ true
validateUrl('ftp://files.example.com');    // ✅ true
validateUrl('not-a-url');                  // ❌ false
validateUrl('javascript:alert("xss")');    // ❌ false (security)

📊 Constants & Configuration

Password Configuration

import { PASSWORD_CONFIG } from '@bastionauth/core';

console.log(PASSWORD_CONFIG);
// {
//   MIN_LENGTH: 8,
//   MAX_LENGTH: 128,
//   REQUIRE_UPPERCASE: true,
//   REQUIRE_LOWERCASE: true,
//   REQUIRE_NUMBER: true,
//   REQUIRE_SPECIAL: true,
//   SPECIAL_CHARS: '!@#$%^&*()_+-=[]{}|;:,.<>?',
//   MIN_STRENGTH_SCORE: 3 // Out of 5
// }

Token Configuration

import { TOKEN_CONFIG } from '@bastionauth/core';

console.log(TOKEN_CONFIG);
// {
//   ACCESS_TOKEN_EXPIRY_SECONDS: 900,      // 15 minutes
//   REFRESH_TOKEN_EXPIRY_SECONDS: 604800,  // 7 days
//   VERIFICATION_TOKEN_EXPIRY: 86400,      // 24 hours
//   PASSWORD_RESET_EXPIRY: 3600,           // 1 hour
//   MAGIC_LINK_EXPIRY: 600,                // 10 minutes
//   INVITATION_EXPIRY: 604800,             // 7 days
// }

Session Configuration

import { SESSION_CONFIG } from '@bastionauth/core';

console.log(SESSION_CONFIG);
// {
//   DEFAULT_DURATION: 604800,              // 7 days
//   REMEMBER_ME_DURATION: 2592000,         // 30 days
//   MAX_CONCURRENT_SESSIONS: 5,
//   IDLE_TIMEOUT: 1800,                    // 30 minutes
//   ABSOLUTE_TIMEOUT: 86400,               // 24 hours
// }

Error Codes

import { ERROR_CODES } from '@bastionauth/core';

console.log(ERROR_CODES);
// {
//   // Authentication Errors
//   INVALID_CREDENTIALS: 'invalid_credentials',
//   EMAIL_NOT_VERIFIED: 'email_not_verified',
//   MFA_REQUIRED: 'mfa_required',
//   INVALID_MFA_CODE: 'invalid_mfa_code',
//   
//   // User Errors
//   USER_NOT_FOUND: 'user_not_found',
//   EMAIL_ALREADY_EXISTS: 'email_already_exists',
//   USERNAME_TAKEN: 'username_taken',
//   ACCOUNT_SUSPENDED: 'account_suspended',
//   
//   // Session Errors
//   SESSION_EXPIRED: 'session_expired',
//   INVALID_TOKEN: 'invalid_token',
//   TOKEN_REVOKED: 'token_revoked',
//   
//   // Organization Errors
//   ORG_NOT_FOUND: 'organization_not_found',
//   NOT_ORG_MEMBER: 'not_organization_member',
//   INSUFFICIENT_PERMISSIONS: 'insufficient_permissions',
//   
//   // ... and many more
// }

Webhook Events

import { WEBHOOK_EVENTS } from '@bastionauth/core';

console.log(WEBHOOK_EVENTS);
// {
//   USER_CREATED: 'user.created',
//   USER_UPDATED: 'user.updated',
//   USER_DELETED: 'user.deleted',
//   USER_SIGNED_IN: 'user.signed_in',
//   USER_SIGNED_OUT: 'user.signed_out',
//   
//   SESSION_CREATED: 'session.created',
//   SESSION_EXPIRED: 'session.expired',
//   SESSION_REVOKED: 'session.revoked',
//   
//   ORG_CREATED: 'organization.created',
//   ORG_MEMBER_ADDED: 'organization.member_added',
//   ORG_MEMBER_REMOVED: 'organization.member_removed',
//   
//   // ... and many more
// }

💡 Real-World Examples

Example 1: Custom API Client

Build a type-safe API client for BastionAuth:

import type { 
  User, 
  SignInRequest, 
  TokenPair, 
  ApiResponse 
} from '@bastionauth/core';
import { validateEmail } from '@bastionauth/core';

class BastionAuthClient {
  private apiUrl: string;
  private accessToken: string | null = null;

  constructor(apiUrl: string) {
    this.apiUrl = apiUrl;
  }

  /**
   * Sign in a user
   */
  async signIn(email: string, password: string): Promise<User> {
    // Validate email before sending request
    if (!validateEmail(email).valid) {
      throw new Error('Invalid email format');
    }

    const request: SignInRequest = { email, password };

    const response = await fetch(`${this.apiUrl}/auth/sign-in`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(request),
    });

    const data: ApiResponse<{ user: User; tokens: TokenPair }> = await response.json();

    if (!data.success) {
      throw new Error(data.error?.message || 'Sign-in failed');
    }

    // Store access token
    this.accessToken = data.data.tokens.accessToken;

    return data.data.user;
  }

  /**
   * Get current user
   */
  async getCurrentUser(): Promise<User> {
    if (!this.accessToken) {
      throw new Error('Not authenticated');
    }

    const response = await fetch(`${this.apiUrl}/users/me`, {
      headers: {
        'Authorization': `Bearer ${this.accessToken}`,
      },
    });

    const data: ApiResponse<User> = await response.json();

    if (!data.success) {
      throw new Error(data.error?.message || 'Failed to fetch user');
    }

    return data.data;
  }

  /**
   * Update user profile
   */
  async updateUser(updates: Partial<User>): Promise<User> {
    if (!this.accessToken) {
      throw new Error('Not authenticated');
    }

    const response = await fetch(`${this.apiUrl}/users/me`, {
      method: 'PATCH',
      headers: {
        'Authorization': `Bearer ${this.accessToken}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(updates),
    });

    const data: ApiResponse<User> = await response.json();

    if (!data.success) {
      throw new Error(data.error?.message || 'Update failed');
    }

    return data.data;
  }
}

// Usage
const client = new BastionAuthClient('https://api.bastionauth.dev');

try {
  const user = await client.signIn('[email protected]', 'password123');
  console.log('Signed in:', user.email);

  const updated = await client.updateUser({
    firstName: 'John',
    lastName: 'Doe',
  });
  console.log('Updated user:', updated);
} catch (error) {
  console.error('Error:', error.message);
}

Example 2: Form Validation

Create a sign-up form validator:

import { 
  validateEmail, 
  validatePassword,
  type SignUpRequest 
} from '@bastionauth/core';

interface ValidationErrors {
  email?: string;
  password?: string;
  firstName?: string;
  lastName?: string;
}

function validateSignUpForm(data: SignUpRequest): ValidationErrors {
  const errors: ValidationErrors = {};

  // Validate email
  const emailResult = validateEmail(data.email);
  if (!emailResult.valid) {
    errors.email = emailResult.error;
  }

  // Validate password
  const passwordResult = validatePassword(data.password);
  if (!passwordResult.valid) {
    errors.password = passwordResult.errors[0] || 'Password is too weak';
  }

  // Validate first name
  if (!data.firstName || data.firstName.trim().length < 2) {
    errors.firstName = 'First name must be at least 2 characters';
  }

  // Validate last name
  if (!data.lastName || data.lastName.trim().length < 2) {
    errors.lastName = 'Last name must be at least 2 characters';
  }

  return errors;
}

// Usage
const formData: SignUpRequest = {
  email: '[email protected]',
  password: 'SecurePass123!',
  firstName: 'Jane',
  lastName: 'Smith',
};

const errors = validateSignUpForm(formData);

if (Object.keys(errors).length > 0) {
  console.error('Validation errors:', errors);
} else {
  console.log('Form is valid!');
  // Proceed with sign-up
}

Example 3: CLI Tool

Build a CLI for managing BastionAuth users:

import type { User, PaginatedResponse } from '@bastionauth/core';
import { ERROR_CODES } from '@bastionauth/core';

class BastionCLI {
  private apiKey: string;
  private apiUrl: string;

  constructor(apiKey: string, apiUrl: string) {
    this.apiKey = apiKey;
    this.apiUrl = apiUrl;
  }

  /**
   * List all users with pagination
   */
  async listUsers(page: number = 1, perPage: number = 10): Promise<void> {
    const response = await fetch(
      `${this.apiUrl}/users?page=${page}&perPage=${perPage}`,
      {
        headers: { 'X-API-Key': this.apiKey },
      }
    );

    const data: PaginatedResponse<User> = await response.json();

    console.log('\n📋 Users List\n');
    console.log('─'.repeat(80));

    data.data.forEach((user, index) => {
      console.log(`${index + 1}. ${user.email}`);
      console.log(`   Name: ${user.firstName} ${user.lastName}`);
      console.log(`   ID: ${user.id}`);
      console.log(`   Status: ${user.status}`);
      console.log(`   Joined: ${user.createdAt.toLocaleDateString()}`);
      console.log();
    });

    console.log('─'.repeat(80));
    console.log(`Page ${data.pagination.page} of ${data.pagination.totalPages}`);
    console.log(`Total users: ${data.pagination.total}`);
  }

  /**
   * Create a new user
   */
  async createUser(email: string, firstName: string, lastName: string): Promise<User> {
    const response = await fetch(`${this.apiUrl}/users`, {
      method: 'POST',
      headers: {
        'X-API-Key': this.apiKey,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ email, firstName, lastName }),
    });

    const data = await response.json();

    if (!response.ok) {
      if (data.error?.code === ERROR_CODES.EMAIL_ALREADY_EXISTS) {
        throw new Error(`User with email ${email} already exists`);
      }
      throw new Error(data.error?.message || 'Failed to create user');
    }

    console.log(`✅ Created user: ${email}`);
    return data.data;
  }

  /**
   * Delete a user
   */
  async deleteUser(userId: string): Promise<void> {
    const response = await fetch(`${this.apiUrl}/users/${userId}`, {
      method: 'DELETE',
      headers: { 'X-API-Key': this.apiKey },
    });

    if (!response.ok) {
      const data = await response.json();
      throw new Error(data.error?.message || 'Failed to delete user');
    }

    console.log(`✅ Deleted user: ${userId}`);
  }
}

// Usage
const cli = new BastionCLI('your-api-key', 'https://api.bastionauth.dev');

// List users
await cli.listUsers(1, 10);

// Create user
await cli.createUser('[email protected]', 'John', 'Doe');

// Delete user
await cli.deleteUser('user_1234567890');

Example 4: Backend Integration (Express)

Integrate BastionAuth types into an Express.js backend:

import express, { Request, Response, NextFunction } from 'express';
import type { User, AccessTokenPayload } from '@bastionauth/core';
import { ERROR_CODES } from '@bastionauth/core';
import jwt from 'jsonwebtoken';

// Extend Express Request to include user
declare global {
  namespace Express {
    interface Request {
      user?: User;
      auth?: AccessTokenPayload;
    }
  }
}

const app = express();
app.use(express.json());

/**
 * Authentication middleware
 */
async function authMiddleware(
  req: Request,
  res: Response,
  next: NextFunction
): Promise<void> {
  try {
    const authHeader = req.headers.authorization;

    if (!authHeader || !authHeader.startsWith('Bearer ')) {
      res.status(401).json({
        error: ERROR_CODES.INVALID_TOKEN,
        message: 'Missing or invalid authorization header',
      });
      return;
    }

    const token = authHeader.substring(7); // Remove 'Bearer '

    // Verify JWT
    const payload = jwt.verify(token, process.env.JWT_PUBLIC_KEY!) as AccessTokenPayload;

    // Fetch full user from database
    const user = await fetchUserFromDatabase(payload.sub);

    if (!user) {
      res.status(401).json({
        error: ERROR_CODES.USER_NOT_FOUND,
        message: 'User not found',
      });
      return;
    }

    // Attach to request
    req.user = user;
    req.auth = payload;

    next();
  } catch (error) {
    res.status(401).json({
      error: ERROR_CODES.INVALID_TOKEN,
      message: 'Invalid or expired token',
    });
  }
}

/**
 * Get current user
 */
app.get('/api/me', authMiddleware, async (req: Request, res: Response) => {
  res.json({
    success: true,
    data: req.user,
  });
});

/**
 * Update user profile
 */
app.patch('/api/me', authMiddleware, async (req: Request, res: Response) => {
  const updates: Partial<User> = req.body;

  // Update user in database
  const updatedUser = await updateUserInDatabase(req.auth!.sub, updates);

  res.json({
    success: true,
    data: updatedUser,
  });
});

// Helper functions (implement with your database)
async function fetchUserFromDatabase(userId: string): Promise<User | null> {
  // Implement your database query
  return null;
}

async function updateUserInDatabase(userId: string, updates: Partial<User>): Promise<User> {
  // Implement your database update
  return {} as User;
}

app.listen(3000, () => {
  console.log('Server running on http://localhost:3000');
});

🎯 Use Cases

1. Building a Custom Frontend

If you're building a frontend in Vue, Angular, Svelte, or vanilla JavaScript:

import type { User, SignInRequest } from '@bastionauth/core';
import { validateEmail, validatePassword } from '@bastionauth/core';

// Your custom authentication service
class AuthService {
  async signIn(email: string, password: string): Promise<User> {
    // Validate inputs
    if (!validateEmail(email).valid) {
      throw new Error('Invalid email');
    }

    // Make API call
    const request: SignInRequest = { email, password };
    const response = await fetch('/api/auth/sign-in', {
      method: 'POST',
      body: JSON.stringify(request),
    });

    return response.json();
  }
}

2. Type-Safe Backend

Build a type-safe Node.js/Express/Fastify backend:

import type { User, Organization, Session } from '@bastionauth/core';
import { ERROR_CODES, WEBHOOK_EVENTS } from '@bastionauth/core';

// Your database models will match BastionAuth types
async function createUser(data: Partial<User>): Promise<User> {
  // Type-safe database operations
  const user = await db.users.create(data);
  
  // Emit webhook event
  await emitWebhook(WEBHOOK_EVENTS.USER_CREATED, user);
  
  return user;
}

3. Testing & Mocking

Create type-safe mocks for testing:

import type { User } from '@bastionauth/core';

// Mock user factory
function createMockUser(overrides?: Partial<User>): User {
  return {
    id: 'user_mock_123',
    email: '[email protected]',
    emailVerified: true,
    firstName: 'Test',
    lastName: 'User',
    status: 'active',
    role: 'user',
    createdAt: new Date(),
    updatedAt: new Date(),
    ...overrides,
  };
}

// Use in tests
const testUser = createMockUser({ email: '[email protected]' });

🔧 TypeScript Best Practices

Strict Type Checking

import type { User } from '@bastionauth/core';

// ✅ Good: Type-safe user creation
function createUserProfile(user: User): void {
  console.log(user.email); // TypeScript knows this exists
}

// ❌ Bad: Unsafe any type
function unsafeFunction(user: any): void {
  console.log(user.emial); // Typo won't be caught!
}

Utility Types

import type { User, Organization } from '@bastionauth/core';

// Pick specific fields
type UserSummary = Pick<User, 'id' | 'email' | 'firstName' | 'lastName'>;

// Omit sensitive fields
type SafeUser = Omit<User, 'passwordHash' | 'mfaSecret'>;

// Make all fields optional
type PartialUser = Partial<User>;

// Make all fields required
type CompleteUser = Required<User>;

Type Guards

import type { User, PublicUser } from '@bastionauth/core';

function isFullUser(user: User | PublicUser): user is User {
  return 'email' in user;
}

function displayUser(user: User | PublicUser): void {
  if (isFullUser(user)) {
    console.log(user.email); // TypeScript knows email exists
  } else {
    console.log(user.username); // Only public fields
  }
}

❓ FAQs

Q: Do I need to install @bastionauth/core separately?

A: No, if you're using @bastionauth/react or @bastionauth/nextjs, they automatically include @bastionauth/core as a dependency. Only install it directly if you're building custom integrations.

Q: Can I use this with JavaScript (not TypeScript)?

A: Yes! While the package is written in TypeScript, it works perfectly with JavaScript. You just won't get type checking and autocompletion.

Q: What's the bundle size?

A: Approximately 15KB (minified), 5KB (gzipped). It's a lightweight package with minimal dependencies.

Q: Does this work with Node.js, Deno, and Bun?

A: Yes! The package is compatible with all modern JavaScript runtimes.

Q: Can I extend the types?

A: Yes! You can use TypeScript's module augmentation:

import '@bastionauth/core';

declare module '@bastionauth/core' {
  interface UserMetadata {
    customField: string;
    companyId: string;
  }
}

Q: Are the validation functions customizable?

A: The built-in validators use industry best practices. For custom validation, you can build on top of them or create your own using the provided types.


📦 Related Packages

BastionAuth is split into three packages for maximum flexibility:

| Package | Description | When to Use | |---------|-------------|-------------| | @bastionauth/core | Types, constants, utilities | Custom integrations, backends, CLI tools | | @bastionauth/react | React components & hooks | React apps (Vite, CRA, Remix) | | @bastionauth/nextjs | Next.js integration | Next.js apps (middleware, server components) |

Package Dependency Tree

@bastionauth/nextjs
├── @bastionauth/react
│   └── @bastionauth/core
└── @bastionauth/core

You only install ONE package - npm handles the rest!


📚 Documentation

💰 Pricing

BastionAuth offers self-hosted authentication with transparent pricing:

  • Free Tier: Up to 1,000 monthly active users
  • Pro: $29/month for up to 10,000 users
  • Enterprise: Custom pricing for unlimited users + premium support

View full pricing →

Why Self-Hosted?

  • 📊 No per-user costs at scale - Pay for hosting, not for users
  • 🔐 Complete data ownership - Your data stays on your infrastructure
  • 🌍 GDPR, HIPAA, SOC2 compliance ready - Meet any regulatory requirement
  • 🚀 No vendor lock-in - You control your auth infrastructure

💬 Support

Need help? We're here for you: