UNPKG

saget-auth-middleware

Version:

A comprehensive authentication middleware for Node.js applications with SSO integration, JWT validation, and role-based access control

372 lines (300 loc) 9.36 kB
import fs from 'fs'; import path from 'path'; import chalk from 'chalk'; export async function generateJSMiddleware(outputDir, config) { const { framework } = config; if (framework === 'next') { generateNextJSMiddleware(outputDir); } else if (framework === 'express') { generateExpressJSMiddleware(outputDir); } // Generate common utilities generateUtilities(outputDir); generateReadme(outputDir, config); } function generateNextJSMiddleware(outputDir) { const middlewareContent = `import { middleware as sagetMiddleware, configureMiddleware } from 'saget-auth-middleware'; // Configure the middleware with your settings const authConfig = { // Public paths that don't require authentication publicPaths: [ '/', '/login', '/register', '/api/health', '/favicon.ico', '/_next/static', '/_next/image' ], // Protected API routes protectedPaths: [ '/api/protected', '/dashboard', '/profile' ], // SSO Configuration (from environment variables) sso: { baseUrl: process.env.SSO_BASE_URL, clientId: process.env.SSO_CLIENT_ID, clientSecret: process.env.SSO_CLIENT_SECRET, redirectUri: process.env.SSO_REDIRECT_URI, scope: process.env.SSO_SCOPE || 'openid profile email', responseType: process.env.SSO_RESPONSE_TYPE || 'code', grantType: process.env.SSO_GRANT_TYPE || 'authorization_code' }, // Optional: Custom configuration tokenRefreshThreshold: 300, // Refresh token 5 minutes before expiry enableLogging: process.env.NODE_ENV === 'development', // Role-based access control (optional) rbac: { enabled: true, roles: { admin: ['/admin', '/api/admin'], user: ['/dashboard', '/profile'], guest: ['/'] } } }; // Configure and export the middleware export const middleware = configureMiddleware(authConfig); // Specify which paths should be processed by the middleware export const config = { matcher: [ /* * Match all request paths except for the ones starting with: * - api/auth (authentication endpoints) * - _next/static (static files) * - _next/image (image optimization files) * - favicon.ico (favicon file) */ '/((?!api/auth|_next/static|_next/image|favicon.ico).*)', ], }; `; const filePath = path.join(outputDir, 'middleware.js'); fs.writeFileSync(filePath, middlewareContent); console.log(chalk.green('✅ Created Next.js middleware.js')); } function generateExpressJSMiddleware(outputDir) { const middlewareContent = `import { configureMiddleware } from 'saget-auth-middleware'; // Configure the middleware with your settings const authConfig = { // Public paths that don't require authentication publicPaths: [ '/', '/login', '/register', '/api/health', '/favicon.ico' ], // Protected API routes protectedPaths: [ '/api/protected', '/dashboard', '/profile' ], // SSO Configuration (from environment variables) sso: { baseUrl: process.env.SSO_BASE_URL, clientId: process.env.SSO_CLIENT_ID, clientSecret: process.env.SSO_CLIENT_SECRET, redirectUri: process.env.SSO_REDIRECT_URI, scope: process.env.SSO_SCOPE || 'openid profile email', responseType: process.env.SSO_RESPONSE_TYPE || 'code', grantType: process.env.SSO_GRANT_TYPE || 'authorization_code' }, // Optional: Custom configuration tokenRefreshThreshold: 300, // Refresh token 5 minutes before expiry enableLogging: process.env.NODE_ENV === 'development', // Role-based access control (optional) rbac: { enabled: true, roles: { admin: ['/admin', '/api/admin'], user: ['/dashboard', '/profile'], guest: ['/'] } } }; // Create the configured middleware export const authMiddleware = configureMiddleware(authConfig); // Example Express.js setup export function setupAuth(app) { // Apply authentication middleware to all routes app.use(authMiddleware); // Example protected route app.get('/api/protected', (req, res) => { // User is authenticated at this point const user = req.user; res.json({ message: 'This is a protected route', user: user }); }); // Example admin-only route app.get('/api/admin', (req, res) => { // User is authenticated and has admin role const user = req.user; res.json({ message: 'Admin access granted', user: user }); }); } `; const filePath = path.join(outputDir, 'auth-middleware.js'); fs.writeFileSync(filePath, middlewareContent); console.log(chalk.green('✅ Created Express.js auth-middleware.js')); // Create Express setup example const setupContent = `import express from 'express'; import { setupAuth } from './auth-middleware.js'; const app = express(); // Setup authentication middleware setupAuth(app); // Your other routes here app.get('/', (req, res) => { res.json({ message: 'Welcome to your authenticated app!' }); }); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(\`Server running on port \${PORT}\`); }); `; const setupPath = path.join(outputDir, 'app-example.js'); fs.writeFileSync(setupPath, setupContent); console.log(chalk.green('✅ Created Express.js app-example.js')); } function generateUtilities(outputDir) { const utilsContent = `// Authentication utilities for client-side usage /** * Check if user is authenticated * @returns {boolean} */ export function isAuthenticated() { if (typeof window === 'undefined') return false; const token = localStorage.getItem('access_token'); if (!token) return false; try { const payload = JSON.parse(atob(token.split('.')[1])); return payload.exp * 1000 > Date.now(); } catch { return false; } } /** * Get current user from token * @returns {object|null} */ export function getCurrentUser() { if (typeof window === 'undefined') return null; const token = localStorage.getItem('access_token'); if (!token) return null; try { const payload = JSON.parse(atob(token.split('.')[1])); return payload.user || null; } catch { return null; } } /** * Logout user */ export function logout() { if (typeof window === 'undefined') return; localStorage.removeItem('access_token'); localStorage.removeItem('refresh_token'); window.location.href = '/login'; } /** * Get authentication headers for API calls * @returns {object} */ export function getAuthHeaders() { if (typeof window === 'undefined') return {}; const token = localStorage.getItem('access_token'); if (!token) return {}; return { 'Authorization': \`Bearer \${token}\` }; } `; const utilsPath = path.join(outputDir, 'auth-utils.js'); fs.writeFileSync(utilsPath, utilsContent); console.log(chalk.green('✅ Created auth-utils.js')); } function generateReadme(outputDir, config) { const readmeContent = `# SAGET Auth Middleware Generated authentication middleware for your ${config.framework === 'next' ? 'Next.js' : 'Express.js'} project. ## Setup 1. Install the middleware package: \`\`\`bash npm install saget-auth-middleware \`\`\` 2. Configure your environment variables in \`.env\`: \`\`\`env SSO_BASE_URL=https://your-sso-server.com SSO_CLIENT_ID=your-client-id SSO_CLIENT_SECRET=your-client-secret SSO_REDIRECT_URI=http://localhost:3000/auth/callback \`\`\` ${config.framework === 'next' ? ` ## Next.js Usage The middleware is automatically configured in \`middleware.js\`. It will: - Protect all routes except those in \`publicPaths\` - Handle authentication redirects - Manage token refresh automatically - Provide user context in your pages ### Using in Pages/Components \`\`\`javascript import { getCurrentUser, isAuthenticated } from './middleware/auth-utils.js'; export default function Dashboard() { const user = getCurrentUser(); if (!isAuthenticated()) { return <div>Please log in</div>; } return <div>Welcome, {user.name}!</div>; } \`\`\` ` : ` ## Express.js Usage Import and use the middleware in your Express app: \`\`\`javascript import express from 'express'; import { setupAuth } from './middleware/auth-middleware.js'; const app = express(); // Setup authentication setupAuth(app); // Your routes here app.listen(3000); \`\`\` ### Manual Setup \`\`\`javascript import { authMiddleware } from './middleware/auth-middleware.js'; app.use(authMiddleware); \`\`\` `} ## Configuration You can customize the middleware by editing the configuration object in the generated files: - \`publicPaths\`: Routes that don't require authentication - \`protectedPaths\`: Routes that require authentication - \`rbac\`: Role-based access control settings - \`tokenRefreshThreshold\`: When to refresh tokens (seconds before expiry) ## Features - ✅ JWT token validation - ✅ Automatic token refresh - ✅ Role-based access control (RBAC) - ✅ Configurable public/protected paths - ✅ SSO integration - ✅ Development logging - ✅ Client-side utilities ## Documentation For more information, visit: https://github.com/your-org/saget-auth-middleware `; const readmePath = path.join(outputDir, 'README.md'); fs.writeFileSync(readmePath, readmeContent); console.log(chalk.green('✅ Created README.md')); } // Default export for easier importing export default { generate: generateJSMiddleware };