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

@re-auth/http-adapters

v1.0.0-alpha.33

Published

HTTP protocol adapters for ReAuth - framework-agnostic integration with Express, Fastify, and Hono

Downloads

93

Readme

@re-auth/http-adapters-v2

V2 HTTP protocol adapters for ReAuth - framework-agnostic integration with Express, Fastify, and Hono.

Features

  • 🚀 Framework Agnostic: Support for Express, Fastify, and Hono
  • 🔒 Security First: Built-in CORS, rate limiting, and security headers
  • 🛡️ Type Safe: Full TypeScript integration with V2 engine types
  • 🔌 Plugin Aware: Automatically discovers and exposes V2 plugin endpoints
  • 👤 User Access: Easy current user retrieval with middleware and utilities
  • 📊 Introspection: Built-in API documentation and health checks
  • Performance: Optimized for high-throughput scenarios

Installation

npm install @re-auth/http-adapters-v2
# or
pnpm add @re-auth/http-adapters-v2
# or
yarn add @re-auth/http-adapters-v2

Quick Start

Express.js

import express from 'express';
import { ReAuthEngineV2 } from '@re-auth/reauth';
import { createExpressAdapter } from '@re-auth/http-adapters-v2';
import { createDefaultLogger } from '@re-auth/logger';

const app = express();

// Create logger instance
const logger = createDefaultLogger({
  prefix: 'MyApp',
  enabledTags: ['auth', 'session', 'http']
});

const engine = new ReAuthEngineV2({
  /* config */,
  logger: logger  // Required logger instance
});

// Create adapter with device info extraction
const adapter = createExpressAdapter({
  engine,
  basePath: '/api/auth',
  cors: {
    origin: ['https://app.example.com'],
    credentials: true
  },
  rateLimit: {
    windowMs: 15 * 60 * 1000,
    max: 100
  }
}, false, async (req) => {
  // Extract device information for enhanced security
  return {
    ip: req.ip || req.connection.remoteAddress,
    userAgent: req.get('User-Agent'),
    fingerprint: req.get('X-Request-ID'),
    geoLocation: req.get('CF-IPCountry'),
    deviceType: req.get('CF-Device-Type'),
    sessionId: req.session?.id,
  };
});

app.use('/api/auth', adapter.createRouter());

// Enable user population on all requests (optional)
app.use(adapter.createUserMiddleware());

app.listen(3000);

Fastify

import Fastify from 'fastify';
import { ReAuthEngineV2 } from '@re-auth/reauth';
import { createFastifyAdapter } from '@re-auth/http-adapters-v2';

const fastify = Fastify();
const engine = new ReAuthEngineV2({
  /* config */
});

// Create adapter with device info extraction
const adapter = createFastifyAdapter(
  {
    engine,
    basePath: '/api/auth',
  },
  async (request) => {
    // Extract device information for enhanced security
    return {
      ip: request.ip,
      userAgent: request.headers['user-agent'],
      fingerprint: request.headers['x-request-id'],
      geoLocation: request.headers['cf-ipcountry'],
      deviceType: request.headers['cf-device-type'],
    };
  },
);

fastify.register(adapter.createPlugin());

// Enable user population on all requests (optional)
fastify.register(adapter.createUserPlugin());

fastify.listen({ port: 3000 });

Hono

import { Hono } from 'hono';
import { ReAuthEngineV2 } from '@re-auth/reauth';
import { createHonoAdapter } from '@re-auth/http-adapters-v2';
import { createDefaultLogger } from '@re-auth/logger';

const app = new Hono();

// Create logger instance
const logger = createDefaultLogger({
  prefix: 'MyApp',
  enabledTags: ['auth', 'session', 'http']
});

const engine = new ReAuthEngineV2({
  /* config */,
  logger: logger  // Required logger instance
});

// Create adapter with device info extraction
const adapter = createHonoAdapter({
  engine,
  basePath: '/api/auth'
}, async (c) => {
  // Extract device information for enhanced security
  return {
    ip: c.env?.CF_CONNECTING_IP || c.req.header('x-forwarded-for'),
    userAgent: c.req.header('user-agent'),
    fingerprint: c.req.header('cf-ray'),
    country: c.req.header('cf-ipcountry'),
    deviceType: c.req.header('cf-device-type'),
    timezone: c.req.header('cf-timezone'),
  };
});

adapter.registerRoutes(app, '/api/auth');

// Enable user population on all requests (optional)
app.use('*', adapter.createUserMiddleware());

// or use a standalone app
// const authApp = adapter.createApp();
// app.route('/api/auth', authApp);

Device Info Extraction

Device information extraction is a core security feature that allows you to capture and analyze request metadata for enhanced authentication, fraud prevention, and analytics. All adapters support customizable device info extraction through their constructor parameters.

Why Device Info Matters

Device information enables:

  • Geographic Analysis: Track user locations and detect suspicious access patterns
  • Device Fingerprinting: Identify and validate trusted devices
  • Security Monitoring: Detect unusual access patterns or potential breaches
  • Analytics: Gather insights about user behavior and platform usage
  • Compliance: Meet regulatory requirements for access logging

Express.js Example

const adapter = createExpressAdapter(config, false, async (req) => {
  return {
    ip: req.ip || req.connection.remoteAddress,
    userAgent: req.get('User-Agent'),
    fingerprint: req.get('X-Request-ID'),
    geoLocation: req.get('CF-IPCountry'),
    deviceType: req.get('CF-Device-Type'),
    sessionId: req.session?.id,
    browserFingerprint: req.get('X-Browser-Fingerprint'),
  };
});

Fastify Example

const adapter = createFastifyAdapter(config, async (request) => {
  return {
    ip: request.ip,
    userAgent: request.headers['user-agent'],
    fingerprint: request.headers['x-request-id'],
    geoLocation: request.headers['cf-ipcountry'],
    deviceType: request.headers['cf-device-type'],
    timezone: request.headers['cf-timezone'],
  };
});

Hono Example

const adapter = createHonoAdapter(config, async (c) => {
  return {
    ip: c.env?.CF_CONNECTING_IP || c.req.header('x-forwarded-for'),
    userAgent: c.req.header('user-agent'),
    fingerprint: c.req.header('cf-ray'),
    country: c.req.header('cf-ipcountry'),
    deviceType: c.req.header('cf-device-type'),
    timezone: c.req.header('cf-timezone'),
    datacenter: c.req.header('cf-ray')?.split('-')[0],
  };
});

Advanced Device Info

For comprehensive device analysis, you can extract extensive metadata:

const deviceInfoExtractor = async (request) => {
  // Framework-specific extraction logic
  const basicInfo = extractBasicInfo(request);

  // Additional processing
  const enhancedInfo = await enrichDeviceInfo(basicInfo);

  // Database lookups, external API calls, etc.
  const riskScore = await calculateRiskScore(enhancedInfo);

  return {
    ...enhancedInfo,
    riskScore,
    trustLevel: riskScore < 0.3 ? 'high' : riskScore < 0.7 ? 'medium' : 'low',
    lastSeen: new Date().toISOString(),
  };
};

Best Practices

  1. Privacy Compliance: Ensure device info collection complies with privacy regulations (GDPR, CCPA, etc.)
  2. Minimal Collection: Only collect what's necessary for your security and analytics needs
  3. Secure Storage: Handle sensitive device data appropriately
  4. Performance: Keep device info extraction fast to avoid impacting response times
  5. Error Handling: Gracefully handle extraction failures

Full Examples

Complete examples with detailed configurations are available in the examples/ directory:

  • Express Example - Full Express.js integration with middleware, security, and error handling
  • Fastify Example - High-performance Fastify setup with schema validation
  • Hono Example - Edge-optimized Hono deployment for serverless environments

Getting Current User

The V2 HTTP adapters provide multiple ways to access the current authenticated user in your route handlers.

Method 1: Using User Middleware (Recommended)

Automatically populate user information on all requests:

Express.js

// Add user middleware globally
app.use(adapter.createUserMiddleware());

// Access user in any route handler
app.get('/api/profile', (req, res) => {
  if (!req.user) {
    return res.status(401).json({ error: 'Authentication required' });
  }

  res.json({
    message: 'Profile data',
    user: req.user.subject,
    sessionValid: req.user.valid,
  });
});

Fastify

// Register user plugin globally
fastify.register(adapter.createUserPlugin());

// Access user in any route handler
fastify.get('/api/profile', async (request, reply) => {
  const user = (request as any).user;

  if (!user) {
    return reply.status(401).send({ error: 'Authentication required' });
  }

  return {
    message: 'Profile data',
    user: user.subject,
    sessionValid: user.valid,
  };
});

Hono

// Add user middleware globally
app.use('*', adapter.createUserMiddleware());

// Access user in any route handler
app.get('/api/profile', (c) => {
  const user = c.get('user');

  if (!user) {
    return c.json({ error: 'Authentication required' }, 401);
  }

  return c.json({
    message: 'Profile data',
    user: user.subject,
    sessionValid: user.valid,
  });
});

Method 2: Manual User Lookup

Check for current user when needed:

// Express
app.get('/api/dashboard', async (req, res) => {
  const user = await adapter.getCurrentUser(req);

  if (!user) {
    return res.status(401).json({ error: 'Authentication required' });
  }

  res.json({ user: user.subject });
});

// Fastify
fastify.get('/api/dashboard', async (request, reply) => {
  const user = await adapter.getCurrentUser(request);

  if (!user) {
    return reply.status(401).send({ error: 'Authentication required' });
  }

  return { user: user.subject };
});

// Hono
app.get('/api/dashboard', async (c) => {
  const user = await adapter.getCurrentUser(c);

  if (!user) {
    return c.json({ error: 'Authentication required' }, 401);
  }

  return c.json({ user: user.subject });
});

Method 3: Optional Authentication

Handle routes that work with or without authentication:

app.get('/api/content', async (req, res) => {
  const user = await adapter.getCurrentUser(req);

  res.json({
    message: 'Content data',
    isAuthenticated: !!user,
    user: user?.subject || null,
    content: user ? 'Premium content' : 'Public content',
  });
});

AuthenticatedUser Type

The user object contains:

interface AuthenticatedUser {
  subject: any; // The authenticated user data from the session
  token: string; // The session token
  valid: boolean; // Whether the session is valid
  metadata?: {
    // Optional session metadata
    expiresAt?: string;
    createdAt?: string;
    lastAccessed?: string;
    [key: string]: any;
  };
}

Session Token Sources

The adapters automatically check for session tokens in:

  1. Authorization header: Bearer <token>
  2. Cookies: reauth-session=<token>
  3. Request body: { "token": "<token>" }

📝 Logging

HTTP adapters provide comprehensive logging for all HTTP operations, authentication flows, and middleware execution. All adapters require a logger instance to be passed to the ReAuth engine.

Logger Setup

import { createDefaultLogger } from '@re-auth/logger';

// Create logger with HTTP-specific tags
const logger = createDefaultLogger({
  prefix: 'MyApp',
  prefixEnv: 'REAUTH_',
  enabledTags: ['auth', 'session', 'http'],
  timestampFormat: 'human',
  emojis: true
});

// Pass to ReAuth engine
const engine = new ReAuthEngine({
  /* config */,
  logger: logger  // Required
});

HTTP-Specific Log Tags

  • http - HTTP adapter operations (requests, responses, middleware)
  • request - Incoming HTTP requests
  • response - HTTP responses and status codes
  • middleware - Middleware execution and authentication checks
  • error - HTTP errors and exception handling

Environment Variable Control

# Enable HTTP and authentication logging
REAUTH_DEBUG=http,auth,session

# Enable all logging
REAUTH_DEBUG=*

# Production logging (JSON format)
NODE_ENV=production

Log Examples

// Development output
[10:30:00am 15 Jan 2024] [MyApp] [http] ℹ️ POST /api/auth/login
[10:30:01am 15 Jan 2024] [MyApp] [auth] ✅ User authentication successful
[10:30:01am 15 Jan 2024] [MyApp] [http] ✅ 200 OK response

// Production output (JSON)
{"level":"info","tags":["http"],"message":"POST /api/auth/login","timestamp":"2024-01-15T10:30:00.000Z","prefix":"MyApp"}
{"level":"info","tags":["auth"],"message":"User authentication successful","timestamp":"2024-01-15T10:30:01.000Z","prefix":"MyApp"}

Configuration

Basic Configuration

import { createHttpAdapterV2 } from '@re-auth/http-adapters-v2';

const adapter = createHttpAdapterV2({
  engine: reAuthEngine,
  framework: 'express', // 'express' | 'fastify' | 'hono'
  basePath: '/api/v2',
  cors: {
    origin: ['https://app.example.com'],
    credentials: true,
    allowedHeaders: ['Content-Type', 'Authorization'],
    methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
  },
  rateLimit: {
    windowMs: 15 * 60 * 1000, // 15 minutes
    max: 100, // requests per window
    message: 'Too many requests, please try again later.',
  },
  security: {
    helmet: true, // Enable security headers
    csrf: false, // Disable CSRF (for API-only usage)
    sanitizeInput: true,
    sanitizeOutput: false,
  },
  validation: {
    validateInput: true,
    maxPayloadSize: 1024 * 1024, // 1MB
    allowedFields: [], // Empty = allow all
    sanitizeFields: ['email', 'username', 'name'],
  },
});

Advanced Configuration

const adapter = createExpressAdapter({
  engine: reAuthEngine,
  basePath: '/auth',
  cors: {
    origin: (origin, callback) => {
      // Custom origin validation
      const allowedOrigins = ['https://app.example.com', 'https://admin.example.com'];
      if (!origin || allowedOrigins.includes(origin)) {
        callback(null, true);
      } else {
        callback(new Error('Not allowed by CORS'));
      }
    },
    credentials: true,
  },
  rateLimit: {
    windowMs: 15 * 60 * 1000,
    max: (req) => (req.user?.isPremium ? 1000 : 100), // Dynamic limits
    keyGenerator: (req) => `${req.ip}:${req.headers['user-agent']}`,
    skipSuccessfulRequests: true,
  },
  security: {
    helmet: {
      contentSecurityPolicy: {
        directives: {
          defaultSrc: ["'self'"],
          styleSrc: ["'self'", "'unsafe-inline'"],
        },
      },
    },
  },
});

API Endpoints

Authentication Steps

Execute plugin-specific authentication steps:

POST /auth/:plugin/:step
GET /auth/:plugin/:step
PUT /auth/:plugin/:step
PATCH /auth/:plugin/:step
DELETE /auth/:plugin/:step

Example:

curl -X POST http://localhost:3000/api/auth/email-password/login \
  -H "Content-Type: application/json" \
  -d '{"email": "[email protected]", "password": "secret"}'

Session Management

GET /session      # Check session validity
POST /session     # Create new session
DELETE /session   # Destroy current session

Plugin Introspection

GET /plugins           # List all plugins
GET /plugins/:plugin   # Get plugin details

System

GET /introspection  # Full API introspection
GET /health        # Health check

Response Format

All endpoints return a consistent response format:

{
  success: boolean;
  data?: any;
  error?: {
    code: string;
    message: string;
    details?: any;
  };
  meta: {
    timestamp: string;
    requestId?: string;
  };
}

Success Response

{
  "success": true,
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "subject": {
      "id": "user123",
      "email": "[email protected]"
    }
  },
  "meta": {
    "timestamp": "2024-01-01T00:00:00.000Z"
  }
}

Error Response

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid email format",
    "details": {
      "field": "email",
      "value": "invalid-email"
    }
  },
  "meta": {
    "timestamp": "2024-01-01T00:00:00.000Z"
  }
}

Security Features

CORS

cors: {
  origin: ['https://app.example.com'],
  credentials: true,
  allowedHeaders: ['Content-Type', 'Authorization'],
  methods: ['GET', 'POST', 'PUT', 'DELETE']
}

Rate Limiting

rateLimit: {
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 100, // requests per window
  keyGenerator: (req) => req.ip,
  skipSuccessfulRequests: false
}

Security Headers

security: {
  helmet: true, // Enables:
  // - X-Content-Type-Options: nosniff
  // - X-Frame-Options: DENY
  // - X-XSS-Protection: 1; mode=block
  // - Referrer-Policy: strict-origin-when-cross-origin
  // - Strict-Transport-Security (HTTPS only)
}

Input Validation

validation: {
  validateInput: true,
  maxPayloadSize: 1024 * 1024, // 1MB
  sanitizeFields: ['email', 'username', 'name'],
  allowedFields: [] // Empty = allow all
}

Error Handling

The adapter provides comprehensive error handling with specific error types:

import { HttpAdapterError, ValidationError, AuthenticationError, AuthorizationError, NotFoundError, RateLimitError } from '@re-auth/http-adapters-v2';

// Custom error handling
app.use((err, req, res, next) => {
  if (err instanceof ValidationError) {
    res.status(400).json({
      success: false,
      error: {
        code: err.code,
        message: err.message,
        details: err.details,
      },
    });
  }
  // ... handle other error types
});

Migration from V1

The V2 adapter is designed to work alongside V1 adapters. Key differences:

  1. Engine Integration: Uses ReAuthEngineV2 instead of ReAuthEngine
  2. Plugin Discovery: Automatically discovers V2 plugins and their steps
  3. Type Safety: Enhanced TypeScript integration
  4. Response Format: Consistent JSON response format
  5. Security: Built-in security features

Migration Steps

  1. Install the V2 adapter package
  2. Update your engine to ReAuthEngineV2
  3. Replace V1 adapter imports with V2 equivalents
  4. Update configuration format
  5. Test endpoints and response formats

License

MIT