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
JavaScript
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
};