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

@struktos/auth

v1.0.1

Published

C# Identity-inspired authentication and authorization for Node.js

Readme

@struktos/auth

C# Identity-inspired authentication and authorization for Node.js

npm version License: MIT

🎯 What is this?

@struktos/auth brings C# ASP.NET Identity's powerful authentication and authorization patterns to Node.js, seamlessly integrated with @struktos/core.

Key Features:

  • JWT Authentication - Secure token-based authentication with automatic validation
  • Role-Based Access Control (RBAC) - Simple and powerful role management
  • Claims-Based Authorization - Fine-grained permissions like C# Identity
  • Database-Agnostic - Works with any database through IAuthStore interface
  • Context Integration - Automatic user injection into @struktos/core Context
  • High-Performance Caching - Token and claims caching with CacheManager
  • Account Lockout - Automatic protection against brute-force attacks
  • Full TypeScript Support - Complete type safety with generics

📦 Installation

npm install @struktos/core @struktos/auth jsonwebtoken bcryptjs

🚀 Quick Start

1. Initialize Auth Service

import { AuthService, InMemoryAuthStore } from '@struktos/auth';

const authStore = new InMemoryAuthStore();
const authService = new AuthService(authStore, {
  jwtSecret: 'your-super-secret-key',
  jwtExpiresIn: '1h',
  enableTokenCache: true,
  enableClaimsCache: true
});

2. Add Authentication Middleware

import express from 'express';
import { createStruktosMiddleware } from '@struktos/adapter-express';
import { createAuthenticateMiddleware } from '@struktos/auth';

const app = express();

// Context middleware (required)
app.use(createStruktosMiddleware());

// Authentication middleware
const authenticate = createAuthenticateMiddleware(authService);

// Protected route
app.get('/api/profile', authenticate, (req, res) => {
  res.json({ user: req.user });
});

3. Register and Login

// Register
app.post('/auth/register', async (req, res) => {
  const result = await authService.register({
    username: req.body.username,
    email: req.body.email,
    password: req.body.password
  });
  
  if (result.success) {
    res.json({
      accessToken: result.accessToken,
      refreshToken: result.refreshToken
    });
  } else {
    res.status(400).json({ error: result.error });
  }
});

// Login
app.post('/auth/login', async (req, res) => {
  const result = await authService.login({
    username: req.body.username,
    password: req.body.password
  });
  
  if (result.success) {
    res.json({
      accessToken: result.accessToken,
      user: result.user
    });
  } else {
    res.status(401).json({ error: result.error });
  }
});

🔐 Authorization

Role-Based Authorization

import { requireRoles } from '@struktos/auth';

// Require Admin role
app.get('/api/admin/users', 
  authenticate, 
  requireRoles('Admin'), 
  (req, res) => {
    res.json({ users: [...] });
  }
);

// Require any of multiple roles
app.get('/api/moderation/reports', 
  authenticate,
  requireRoles('Moderator', 'Admin'),
  (req, res) => {
    res.json({ reports: [...] });
  }
);

Claims-Based Authorization

import { requireClaim } from '@struktos/auth';

// Require specific permission claim
app.post('/api/documents', 
  authenticate,
  requireClaim('permission', 'write:documents'),
  (req, res) => {
    res.status(201).json({ document: {...} });
  }
);

// Check for claim type only
app.get('/api/beta-features',
  authenticate,
  requireClaim('feature', 'beta-access'),
  (req, res) => {
    res.json({ features: [...] });
  }
);

Custom Authorization Guards

import { 
  createAuthorizeMiddleware, 
  RoleBasedGuard, 
  ClaimBasedGuard,
  CompositeGuard 
} from '@struktos/auth';

// Create composite guard (AND logic)
const guard = new CompositeGuard([
  new RoleBasedGuard(['Admin']),
  new ClaimBasedGuard('department', 'engineering')
], 'AND');

app.delete('/api/critical-resource/:id',
  authenticate,
  createAuthorizeMiddleware(guard),
  (req, res) => {
    res.json({ deleted: true });
  }
);

📚 Core Concepts

User Model

interface User {
  id: string;
  username: string;
  email: string;
  passwordHash: string;
  roles?: string[];
  claims?: Claim[];
  emailConfirmed?: boolean;
  twoFactorEnabled?: boolean;
  lockoutEnd?: Date | null;
  lockoutEnabled?: boolean;
  accessFailedCount?: number;
}

Roles

// Add role to user
await authStore.addUserToRole(userId, 'Admin');

// Check if user has role
const isAdmin = await authStore.isUserInRole(userId, 'Admin');

// Get all user roles
const roles = await authStore.getUserRoles(userId);

Claims

// Add claim to user
await authStore.addUserClaim(userId, {
  type: 'permission',
  value: 'write:documents'
});

// Check if user has claim
const hasClaim = await authStore.hasUserClaim(
  userId, 
  'permission', 
  'write:documents'
);

// Get all user claims
const claims = await authStore.getUserClaims(userId);

🗄️ Database Integration

Implement IAuthStore for your database:

import { IAuthStore, User } from '@struktos/auth';
import { PrismaClient } from '@prisma/client';

class PrismaAuthStore implements IAuthStore<User> {
  constructor(private prisma: PrismaClient) {}
  
  async findUserById(userId: string): Promise<User | null> {
    return await this.prisma.user.findUnique({
      where: { id: userId },
      include: { roles: true, claims: true }
    });
  }
  
  async findUserByUsername(username: string): Promise<User | null> {
    return await this.prisma.user.findUnique({
      where: { username },
      include: { roles: true, claims: true }
    });
  }
  
  // ... implement other methods
}

// Use with AuthService
const authStore = new PrismaAuthStore(prisma);
const authService = new AuthService(authStore, options);

⚡ Performance Features

Token Caching

const authService = new AuthService(authStore, {
  jwtSecret: 'secret',
  enableTokenCache: true,
  tokenCacheTTL: 30 * 60 * 1000  // 30 minutes
});

Claims Caching

const authService = new AuthService(authStore, {
  jwtSecret: 'secret',
  enableClaimsCache: true,
  claimsCacheTTL: 15 * 60 * 1000  // 15 minutes
});

🔒 Security Features

Account Lockout

const authService = new AuthService(authStore, {
  jwtSecret: 'secret',
  maxAccessAttempts: 5,        // Lock after 5 failed attempts
  lockoutDuration: 15          // Lock for 15 minutes
});

Password Hashing

Automatic bcrypt hashing with configurable rounds:

const authService = new AuthService(authStore, {
  jwtSecret: 'secret',
  bcryptRounds: 12  // More rounds = more security, slower
});

Password Change

const success = await authService.changePassword(
  userId,
  currentPassword,
  newPassword
);

🔗 Context Integration

User automatically injected into @struktos/core Context:

import { RequestContext } from '@struktos/core';

async function someBusinessLogic() {
  const ctx = RequestContext.current();
  const userId = ctx?.get('userId');
  const user = ctx?.get('user');
  
  console.log(`Processing request for user: ${userId}`);
}

📖 API Reference

AuthService

class AuthService<TUser extends User> {
  // Registration
  register(data: RegistrationData): Promise<AuthenticationResult>
  
  // Authentication
  login(credentials: LoginCredentials): Promise<AuthenticationResult>
  validateToken(token: string): Promise<TUser | null>
  
  // Context
  getCurrentUser(): TUser | undefined
  getCurrentUserId(): string | undefined
  
  // Password
  changePassword(userId, currentPassword, newPassword): Promise<boolean>
}

Middleware

// Authentication
createAuthenticateMiddleware(authService)
createOptionalAuthMiddleware(authService)

// Authorization
requireRoles(...roles: string[])
requireClaim(type: string, value?: string)
createAuthorizeMiddleware(guard: IAuthGuard)

Guards

// Built-in guards
new RoleBasedGuard(['Admin', 'Moderator'])
new ClaimBasedGuard('permission', 'write:documents')
new ResourceBasedGuard()
new CompositeGuard([guard1, guard2], 'AND' | 'OR')

🧪 Testing

import { InMemoryAuthStore, AuthService } from '@struktos/auth';

describe('Authentication', () => {
  let authStore: InMemoryAuthStore;
  let authService: AuthService;
  
  beforeEach(() => {
    authStore = new InMemoryAuthStore();
    authService = new AuthService(authStore, {
      jwtSecret: 'test-secret'
    });
  });
  
  it('should register user', async () => {
    const result = await authService.register({
      username: 'test',
      email: '[email protected]',
      password: 'password123'
    });
    
    expect(result.success).toBe(true);
    expect(result.accessToken).toBeDefined();
  });
});

📊 Architecture

HTTP Request with JWT
    ↓
createAuthenticateMiddleware
    ↓
Extract & Validate Token
    ↓
AuthService.validateToken()
    ↓
Check Cache → If miss → Verify JWT → Load User from Store
    ↓
Inject User into Context
    ↓
[Your Route Handlers]
    ↓
Authorization Guards (if configured)
    ↓
Check Roles/Claims
    ↓
Grant/Deny Access

🎯 Use Cases

Basic Authentication

// Registration and login with JWT tokens
const result = await authService.login(credentials);
// User automatically in Context for all subsequent operations

Enterprise RBAC

// Hierarchical role system
await authStore.addUserToRole(userId, 'Admin');
app.get('/admin/*', authenticate, requireRoles('Admin'), ...);

Fine-Grained Permissions

// Permission-based access control
await authStore.addUserClaim(userId, {
  type: 'permission',
  value: 'read:sensitive-data'
});

Multi-Tenant Applications

// Tenant-specific claims
await authStore.addUserClaim(userId, {
  type: 'tenant',
  value: 'acme-corp'
});

🤝 Related Packages

📄 License

MIT © Struktos.js Team

🔗 Links


Built with ❤️ for enterprise Node.js security