{"id":49889926,"url":"https://github.com/haxurn/better-middleware","last_synced_at":"2026-05-15T20:11:10.387Z","repository":{"id":308166353,"uuid":"1031861614","full_name":"haxurn/better-middleware","owner":"haxurn","description":"a framework-agnostic authentication middleware for Better Auth that provides robust session validation, intelligent caching, and comprehensive error handling for your backend routes.","archived":false,"fork":false,"pushed_at":"2025-08-04T15:18:27.000Z","size":141,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-13T21:25:22.947Z","etag":null,"topics":["auth","better-auth","middleware","secure-routes","security"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/haxurn.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-04T12:48:56.000Z","updated_at":"2025-08-04T15:18:30.000Z","dependencies_parsed_at":"2025-08-04T17:12:43.433Z","dependency_job_id":null,"html_url":"https://github.com/haxurn/better-middleware","commit_stats":null,"previous_names":["haxurn/better-middleware"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/haxurn/better-middleware","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haxurn%2Fbetter-middleware","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haxurn%2Fbetter-middleware/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haxurn%2Fbetter-middleware/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haxurn%2Fbetter-middleware/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/haxurn","download_url":"https://codeload.github.com/haxurn/better-middleware/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/haxurn%2Fbetter-middleware/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33078277,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-15T20:05:40.333Z","status":"ssl_error","status_checked_at":"2026-05-15T20:05:38.672Z","response_time":103,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["auth","better-auth","middleware","secure-routes","security"],"created_at":"2026-05-15T20:11:09.745Z","updated_at":"2026-05-15T20:11:10.379Z","avatar_url":"https://github.com/haxurn.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Better Middleware\n\n[![npm version](https://badge.fury.io/js/better-middleware.svg)](https://badge.fury.io/js/better-middleware)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![TypeScript](https://img.shields.io/badge/%3C%2F%3E-TypeScript-%230074c1.svg)](http://www.typescriptlang.org/)\n\nA **framework-agnostic** authentication middleware for [Better Auth](https://better-auth.com) that provides robust session validation, intelligent caching, and comprehensive error handling for your backend routes.\n\n## ✨ Features\n\n- 🚀 **Framework Agnostic** - Works with Express, Fastify, Hono, Koa, and any Node.js framework\n- 🔐 **Session Validation** - Automatic Better Auth session verification\n- ⚡ **Intelligent Caching** - LRU cache with configurable TTL for optimal performance\n- 🛡️ **Security First** - Token masking, secure session handling, and comprehensive error management\n- 📝 **Structured Logging** - Built-in logging with customizable levels and output\n- 🎯 **TypeScript Native** - Full type safety and IntelliSense support\n- 🔧 **Highly Configurable** - Extensive customization options for any use case\n- 🎨 **Modern API** - Clean, intuitive API design with async/await support\n- 🧪 **Battle Tested** - 100% test coverage with 113+ comprehensive tests\n\n## 📦 Installation\n\n```bash\nnpm install better-middleware better-auth\n# or\npnpm add better-middleware better-auth\n# or\nyarn add better-middleware better-auth\n```\n\n## 🎯 **Framework Examples**\n\nReady-to-run examples for popular frameworks:\n\n- **[Express.js](./examples/express/)** - Traditional middleware pattern with global extensions\n- **[Fastify](./examples/fastify/)** - High-performance preHandlers with schema validation  \n- **[Hono](./examples/hono/)** - Modern edge-ready framework with context injection\n- **[Next.js](./examples/nextjs/)** - API routes with higher-order functions and interactive UI\n- **[Koa.js](./examples/koa/)** - Elegant async middleware with context-based state\n\nEach example includes:\n- Complete TypeScript setup\n- Authentication flow implementation  \n- Role-based access control\n- Interactive testing capabilities\n- Comprehensive documentation\n\n👉 **[Browse All Examples →](./examples/)**\n\n## 🚀 Quick Start\n\n### Basic Usage\n\n```typescript\nimport { createAuthMiddleware } from 'better-middleware';\nimport type { Request, Response, NextFunction } from 'express';\n\nconst authMiddleware = createAuthMiddleware({\n  baseURL: 'http://localhost:3000',\n  framework: {\n    getHeaders: (req: Request) =\u003e req.headers as Record\u003cstring, string\u003e,\n    getCookies: (req: Request) =\u003e req.cookies,\n    setContext: (req: Request, key: string, value: any) =\u003e {\n      req[key] = value;\n    },\n    createResponse: (req: Request, body: any, status: number) =\u003e ({\n      status,\n      body\n    })\n  }\n});\n\n// Use in your routes\napp.get('/protected', authMiddleware, (req: Request, res: Response) =\u003e {\n  // Access authenticated user\n  console.log(req.user); // Better Auth user object\n  console.log(req.session); // Better Auth session object\n  \n  res.json({ message: 'Hello authenticated user!', user: req.user });\n});\n```\n\n## 🔧 Configuration\n\n### AuthMiddlewareOptions\n\n```typescript\ninterface AuthMiddlewareOptions\u003cTContext\u003e {\n  // Better Auth server URL\n  baseURL: string;\n  \n  // Additional fetch options for Better Auth client\n  fetchOptions?: RequestInit;\n  \n  // Caching configuration\n  cache?: {\n    enabled: boolean;\n    ttl?: number;     // Time to live in seconds (default: 300)\n    max?: number;     // Maximum cache entries (default: 1000)\n  };\n  \n  // Custom error handler\n  onError?: (error: unknown, ctx: TContext) =\u003e AuthResponse | Promise\u003cAuthResponse\u003e;\n  \n  // Custom logger\n  logger?: {\n    info: (message: string, data?: Record\u003cstring, unknown\u003e) =\u003e void;\n    error: (message: string, data?: Record\u003cstring, unknown\u003e) =\u003e void;\n    debug: (message: string, data?: Record\u003cstring, unknown\u003e) =\u003e void;\n  };\n  \n  // Framework adapter\n  framework: {\n    getHeaders: (req: FrameworkRequest) =\u003e Record\u003cstring, string\u003e;\n    getCookies: (req: FrameworkRequest) =\u003e Record\u003cstring, string\u003e;\n    setContext: (ctx: TContext, key: \"user\" | \"session\", value: any) =\u003e void;\n    createResponse: (ctx: TContext, body: unknown, status: number) =\u003e AuthResponse;\n  };\n}\n```\n\n## 🌐 Framework Examples\n\n### Express.js\n\n```typescript\nimport express from 'express';\nimport { createAuthMiddleware } from 'better-middleware';\n\nconst app = express();\n\nconst authMiddleware = createAuthMiddleware({\n  baseURL: process.env.BETTER_AUTH_URL || 'http://localhost:3000',\n  cache: {\n    enabled: true,\n    ttl: 300, // 5 minutes\n    max: 1000\n  },\n  framework: {\n    getHeaders: (req) =\u003e req.headers as Record\u003cstring, string\u003e,\n    getCookies: (req) =\u003e req.cookies || {},\n    setContext: (req, key, value) =\u003e { req[key] = value; },\n    createResponse: (req, body, status) =\u003e ({ status, body })\n  }\n});\n\napp.use('/api/protected', authMiddleware);\n```\n\n### Fastify\n\n```typescript\nimport Fastify from 'fastify';\nimport { createAuthMiddleware } from 'better-middleware';\n\nconst fastify = Fastify();\n\nconst authMiddleware = createAuthMiddleware({\n  baseURL: 'http://localhost:3000',\n  framework: {\n    getHeaders: (request) =\u003e request.headers as Record\u003cstring, string\u003e,\n    getCookies: (request) =\u003e request.cookies || {},\n    setContext: (request, key, value) =\u003e { request[key] = value; },\n    createResponse: (request, body, status) =\u003e ({ status, body })\n  }\n});\n\nfastify.addHook('preHandler', authMiddleware);\n```\n\n### Hono\n\n```typescript\nimport { Hono } from 'hono';\nimport { createAuthMiddleware } from 'better-middleware';\n\nconst app = new Hono();\n\nconst authMiddleware = createAuthMiddleware({\n  baseURL: 'http://localhost:3000',\n  framework: {\n    getHeaders: (c) =\u003e Object.fromEntries(c.req.raw.headers.entries()),\n    getCookies: (c) =\u003e c.req.cookie() || {},\n    setContext: (c, key, value) =\u003e c.set(key, value),\n    createResponse: (c, body, status) =\u003e c.json(body, status)\n  }\n});\n\napp.use('/protected/*', authMiddleware);\n```\n\n### Next.js API Routes\n\n```typescript\nimport { createAuthMiddleware } from 'better-middleware';\nimport type { NextApiRequest, NextApiResponse } from 'next';\n\nconst authMiddleware = createAuthMiddleware({\n  baseURL: process.env.BETTER_AUTH_URL!,\n  framework: {\n    getHeaders: (req) =\u003e req.headers as Record\u003cstring, string\u003e,\n    getCookies: (req) =\u003e req.cookies || {},\n    setContext: (req, key, value) =\u003e { req[key] = value; },\n    createResponse: (req, body, status) =\u003e ({ status, body })\n  }\n});\n\nexport default async function handler(req: NextApiRequest, res: NextApiResponse) {\n  const authResult = await authMiddleware(req, req, async () =\u003e {});\n  if (authResult) {\n    return res.status(authResult.status).json(authResult.body);\n  }\n  \n  // Your protected route logic here\n  res.json({ user: req.user, session: req.session });\n}\n```\n\n## 🗄️ Caching\n\nThe middleware includes intelligent session caching to reduce database queries and improve performance:\n\n```typescript\nconst authMiddleware = createAuthMiddleware({\n  baseURL: 'http://localhost:3000',\n  cache: {\n    enabled: true,\n    ttl: 600,    // 10 minutes\n    max: 5000,   // 5000 entries\n  },\n  // ... other options\n});\n```\n\n### Cache Features\n\n- **LRU (Least Recently Used)** eviction policy\n- **Automatic TTL** expiration\n- **Session token extraction** from multiple cookie formats\n- **Cache hit/miss logging** for monitoring\n- **Memory efficient** with configurable limits\n\n## 🚨 Error Handling\n\n### Default Error Handling\n\nThe middleware provides comprehensive error handling out of the box:\n\n```typescript\n// Automatic error responses for common scenarios\n{\n  \"success\": false,\n  \"message\": \"Invalid or missing session\",\n  \"code\": \"UNAUTHORIZED\"\n}\n```\n\n### Custom Error Handler\n\n```typescript\nconst authMiddleware = createAuthMiddleware({\n  baseURL: 'http://localhost:3000',\n  onError: async (error, ctx) =\u003e {\n    // Log error\n    console.error('Auth error:', error);\n    \n    // Custom error response\n    if (error.code === 'SESSION_EXPIRED') {\n      return {\n        status: 401,\n        body: {\n          error: 'Session expired',\n          redirect: '/login'\n        }\n      };\n    }\n    \n    return {\n      status: 401,\n      body: { error: 'Authentication failed' }\n    };\n  },\n  // ... other options\n});\n```\n\n### Error Codes\n\n| Code | Description |\n|------|-------------|\n| `UNAUTHORIZED` | No valid session found |\n| `SESSION_EXPIRED` | Session has expired |\n| `INVALID_SESSION` | Session format is invalid |\n| `INVALID_CREDENTIALS` | Authentication credentials are invalid |\n\n## 📝 Logging\n\n### Built-in Logging\n\n```typescript\nconst authMiddleware = createAuthMiddleware({\n  baseURL: 'http://localhost:3000',\n  // Uses built-in structured logging\n  framework: { /* ... */ }\n});\n```\n\n### Custom Logger\n\n```typescript\nimport winston from 'winston';\n\nconst logger = winston.createLogger({\n  level: 'info',\n  format: winston.format.json(),\n  transports: [\n    new winston.transports.File({ filename: 'auth.log' })\n  ]\n});\n\nconst authMiddleware = createAuthMiddleware({\n  baseURL: 'http://localhost:3000',\n  logger: {\n    info: (msg, data) =\u003e logger.info(msg, data),\n    error: (msg, data) =\u003e logger.error(msg, data),\n    debug: (msg, data) =\u003e logger.debug(msg, data),\n  },\n  framework: { /* ... */ }\n});\n```\n\n## 📚 API Reference\n\n### Types\n\n```typescript\n// Re-exported from better-middleware\nimport type {\n  AuthContext,\n  AuthMiddlewareOptions,\n  AuthResponse,\n  BetterAuthUser,\n  BetterAuthSession,\n  BetterAuthError,\n  CacheOptions,\n  FrameworkContext,\n  FrameworkRequest,\n} from 'better-middleware';\n```\n\n### Utilities\n\n```typescript\n// Re-exported utilities\nimport {\n  SessionCache,\n  createErrorResponse,\n  createLogger\n} from 'better-middleware';\n\n// SessionCache methods\nconst cache = new SessionCache(1000, 300);\ncache.get(key);           // Get cached session\ncache.set(key, value);    // Cache session\ncache.has(key);           // Check if key exists\ncache.delete(key);        // Remove from cache\ncache.clear();            // Clear all entries\ncache.size();             // Get cache size\n\n// Static method for session token extraction\nSessionCache.extractSessionToken(cookieString);\n```\n\n## 🔍 Advanced Usage\n\n### Multiple Authentication Strategies\n\n```typescript\nconst publicRoutes = ['/health', '/docs'];\nconst adminRoutes = ['/admin'];\n\nconst authMiddleware = createAuthMiddleware({\n  baseURL: 'http://localhost:3000',\n  onError: async (error, ctx) =\u003e {\n    // Different handling for different route types\n    if (ctx.path?.startsWith('/admin')) {\n      return { status: 403, body: { error: 'Admin access required' } };\n    }\n    return { status: 401, body: { error: 'Authentication required' } };\n  },\n  framework: { /* ... */ }\n});\n```\n\n### Session Validation with Roles\n\n```typescript\nfunction requireRole(roles: string[]) {\n  return async (req: Request, res: Response, next: NextFunction) =\u003e {\n    await authMiddleware(req, req, async () =\u003e {});\n    \n    const userRoles = req.user?.roles || [];\n    const hasRequiredRole = roles.some(role =\u003e userRoles.includes(role));\n    \n    if (!hasRequiredRole) {\n      return res.status(403).json({ error: 'Insufficient permissions' });\n    }\n    \n    next();\n  };\n}\n\napp.get('/admin/users', requireRole(['admin']), (req, res) =\u003e {\n  // Admin only route\n});\n```\n\n## 🧪 Testing\n\nThis project includes a comprehensive test suite built with **Vitest** that ensures reliability and maintainability.\n\n### 📊 **Exceptional Test Coverage**\n- **100% Statement Coverage** - Every line of code is tested\n- **98.75% Branch Coverage** - Nearly all code paths covered  \n- **100% Function Coverage** - Every function is tested\n- **100% Line Coverage** - Complete line-by-line testing\n- **113 Total Tests** across 7 test files\n\n### 🚀 **Test Commands**\n```bash\n# Run tests once\npnpm test\n\n# Run tests in watch mode\npnpm test:watch\n\n# Run tests with coverage report\npnpm test:coverage\n\n# Run tests with UI\npnpm test:ui\n```\n\n### 🧪 **Testing Your Integration**\n\n```typescript\nimport { createAuthMiddleware } from 'better-middleware';\nimport { describe, it, expect, vi } from 'vitest';\n\n// Mock framework adapter for testing\nconst mockFramework = {\n  getHeaders: vi.fn(),\n  getCookies: vi.fn(),\n  setContext: vi.fn(),\n  createResponse: vi.fn(),\n};\n\nconst authMiddleware = createAuthMiddleware({\n  baseURL: 'http://localhost:3000',\n  framework: mockFramework\n});\n\n// Test your middleware\ndescribe('Auth Middleware', () =\u003e {\n  it('should authenticate valid sessions', async () =\u003e {\n    mockFramework.getHeaders.mockReturnValue({\n      cookie: 'better-auth.session_token=valid_token'\n    });\n    \n    const result = await authMiddleware(mockReq, mockReq, vi.fn());\n    expect(result).toBeUndefined(); // Success case\n    expect(mockFramework.setContext).toHaveBeenCalled();\n  });\n});\n```\n\n### 🎯 **Test Categories**\n\n- **Core Middleware Tests** (26 tests) - Main functionality, authentication flows, error handling\n- **SessionCache Tests** (20 tests) - LRU cache operations, TTL behavior, token extraction\n- **Error Handling Tests** (12 tests) - Error utilities, response creation, localization\n- **Logger Tests** (21 tests) - Logging functionality, levels, formatting\n- **Type Definition Tests** (20 tests) - TypeScript type correctness and flexibility\n- **Export Tests** (14 tests) - Public API surface and compatibility\n\n## 📋 Requirements\n\n- **Node.js**: \u003e= 18.0.0\n- **Better Auth**: \u003e= 1.3.4\n- **TypeScript**: \u003e= 5.0.0 (for TypeScript projects)\n\n## 🤝 Contributing\n\nWe welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.\n\n1. Fork the repository\n2. Create your feature branch (`git checkout -b feature/amazing-feature`)\n3. Commit your changes (`git commit -m 'Add some amazing feature'`)\n4. Push to the branch (`git push origin feature/amazing-feature`)\n5. Open a Pull Request\n\n### Development Setup\n\n```bash\n# Clone the repository\ngit clone https://github.com/haxurn/better-middleware.git\ncd better-middleware\n\n# Install dependencies\npnpm install\n\n# Run tests\npnpm test\n\n# Run tests with coverage\npnpm test:coverage\n\n# Run linting and formatting\npnpm lint\npnpm format\n\n# Run type checking\npnpm check\n\n# Build the project\npnpm build\n\n# Test framework examples\ncd examples/express \u0026\u0026 npm run dev  # Test Express example\ncd examples/nextjs \u0026\u0026 npm run dev   # Test Next.js example\n```\n\n### 🎨 **Code Quality Standards**\n\nThis project maintains high code quality standards with:\n\n- **Biome** for linting and formatting\n- **TypeScript** for type safety\n- **Vitest** for comprehensive testing\n- **100% test coverage** requirement\n- **Consistent code formatting** across all files\n- **Comprehensive type definitions** for all exports\n\n## 📄 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## 🙏 Acknowledgments\n\n- [Better Auth](https://better-auth.com) - The authentication library this middleware is built for\n- [LRU Cache](https://github.com/isaacs/node-lru-cache) - Efficient caching implementation\n- All contributors who have helped improve this project\n\n## 📞 Support\n\n- 📚 [Documentation](https://github.com/haxurn/better-middleware)\n- 🐛 [Issue Tracker](https://github.com/haxurn/better-middleware/issues)\n- 💬 [Discussions](https://github.com/haxurn/better-middleware/discussions)\n\n---\n\nMade with ❤️ by [haxurn](https://github.com/haxurn)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaxurn%2Fbetter-middleware","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhaxurn%2Fbetter-middleware","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhaxurn%2Fbetter-middleware/lists"}