@re-auth/http-adapters
Version:
HTTP adapters for ReAuth authentication framework
309 lines • 12.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.createBasicFastifyAdapter = createBasicFastifyAdapter;
exports.createOAuthFastifyAdapter = createOAuthFastifyAdapter;
exports.createMultiTenantFastifyAdapter = createMultiTenantFastifyAdapter;
exports.createProductionFastifyAdapter = createProductionFastifyAdapter;
exports.createReAuthFastifyPlugin = createReAuthFastifyPlugin;
exports.createCompleteFastifyApp = createCompleteFastifyApp;
const fastify_adapter_v2_1 = require("./fastify-adapter-v2");
/**
* Basic Fastify adapter usage with V2 factory pattern
*/
async function createBasicFastifyAdapter(fastify, reAuthEngine) {
const config = {
basePath: '/auth',
cookieName: 'session_token',
cookieOptions: {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
maxAge: 60 * 60 * 24 * 7, // 7 days
},
};
// Using the convenience wrapper class
const adapter = (0, fastify_adapter_v2_1.createFastifyAdapter)(fastify, reAuthEngine, config);
// Add custom routes
adapter.addRoute('GET', '/health', async (request, reply) => {
return reply.send({ status: 'ok' });
});
// Add protected route
adapter.addRoute('GET', '/profile', async (request, reply) => {
const user = request.user;
return reply.send({ user });
}, { requireAuth: true });
return adapter;
}
/**
* Advanced Fastify adapter with context rules for OAuth
*/
async function createOAuthFastifyAdapter(fastify, reAuthEngine) {
const config = {
basePath: '/auth',
cookieName: 'session_token',
contextRules: [
// OAuth state and redirect handling
fastify_adapter_v2_1.OAuth2ContextRules.callback('oauth-github'),
fastify_adapter_v2_1.OAuth2ContextRules.start('oauth-github'),
fastify_adapter_v2_1.OAuth2ContextRules.callback('oauth-google'),
fastify_adapter_v2_1.OAuth2ContextRules.start('oauth-google'),
// Custom context rule for API keys
(0, fastify_adapter_v2_1.createContextRule)('api-auth', {
stepName: 'verify-key',
extractHeaders: ['x-api-key'],
extractCookies: ['refresh_token'],
setCookies: ['new_refresh_token'],
transformInput: (key, value, request) => {
if (key === 'x-api-key') {
// Validate API key format
return value.startsWith('ak_') ? value : null;
}
return value;
},
}),
],
// Custom routes for OAuth flows
customRoutes: [
(0, fastify_adapter_v2_1.createCustomRoute)('GET', '/auth/callback', async (request, reply) => {
const code = request.query.code;
const state = request.query.state;
if (!code || !state) {
return reply.status(400).send({ error: 'Missing code or state' });
}
// Handle OAuth callback
return reply.send({ success: true, redirectTo: '/dashboard' });
}),
],
};
// Using the factory function directly
const frameworkAdapter = new fastify_adapter_v2_1.FastifyFrameworkAdapter(fastify);
const createAdapter = (0, fastify_adapter_v2_1.createFastifyAdapterV2)(fastify, frameworkAdapter);
createAdapter(reAuthEngine, config);
return fastify;
}
/**
* Multi-tenant Fastify adapter with tenant-specific context
*/
async function createMultiTenantFastifyAdapter(fastify, reAuthEngine) {
const config = {
basePath: '/api/v1/auth',
contextRules: [
// Extract tenant information from headers and subdomains
(0, fastify_adapter_v2_1.createContextRule)('*', {
// Apply to all plugins
extractHeaders: {
'x-tenant-id': 'tenantId',
'x-workspace': 'workspaceId',
},
extractCookies: ['tenant_preference'],
setCookies: ['tenant_session'],
transformInput: (key, value, request) => {
if (key === 'tenantId') {
// Extract tenant from subdomain if not in header
if (!value) {
const host = request.headers.host;
const subdomain = host?.split('.')[0];
return subdomain !== 'www' ? subdomain : null;
}
}
return value;
},
transformOutput: (key, value, result, request) => {
if (key === 'tenant_session') {
// Set secure cookie options for tenant session
return {
value: value,
domain: `.${request.headers.host?.split('.').slice(-2).join('.')}`,
httpOnly: true,
secure: true,
};
}
return value;
},
}),
],
};
const adapter = (0, fastify_adapter_v2_1.createFastifyAdapter)(fastify, reAuthEngine, config);
// Add tenant-aware hook
fastify.addHook('onRequest', async (request, reply) => {
const tenantId = request.headers['x-tenant-id'] || request.headers.host?.split('.')[0];
if (tenantId) {
request.tenantId = tenantId;
}
});
// Add tenant-specific routes
adapter.addRoute('GET', '/tenant/info', async (request, reply) => {
const tenantId = request.tenantId;
const user = request.user;
return reply.send({
tenant: tenantId,
user: user?.id,
authenticated: request.isAuthenticated,
});
});
return adapter;
}
/**
* Production-ready Fastify adapter with comprehensive configuration
*/
async function createProductionFastifyAdapter(fastify, reAuthEngine) {
const config = {
basePath: '/auth',
cookieName: 'secure_session',
cookieOptions: {
httpOnly: true,
secure: true,
sameSite: 'strict',
maxAge: 60 * 60 * 24 * 30, // 30 days
},
// Auto-introspection configuration
autoIntrospection: {
enabled: true,
includePlugins: ['email-password', 'oauth-google', 'oauth-github'],
excludeSteps: ['admin.ban-user'], // Exclude sensitive admin steps
pathGenerator: (pluginName, stepName, basePath) => {
// Custom path generation for better API structure
if (pluginName.startsWith('oauth-')) {
const provider = pluginName.replace('oauth-', '');
return `${basePath}/oauth/${provider}/${stepName}`;
}
return `${basePath}/${pluginName}/${stepName}`;
},
},
// Comprehensive context rules
contextRules: [
// OAuth flows
fastify_adapter_v2_1.OAuth2ContextRules.callback('oauth-github'),
fastify_adapter_v2_1.OAuth2ContextRules.start('oauth-github'),
fastify_adapter_v2_1.OAuth2ContextRules.callback('oauth-google'),
fastify_adapter_v2_1.OAuth2ContextRules.start('oauth-google'),
// Security headers and CSRF protection
(0, fastify_adapter_v2_1.createContextRule)('*', {
extractHeaders: {
'x-csrf-token': 'csrfToken',
'x-forwarded-for': 'clientIp',
'user-agent': 'userAgent',
},
setHeaders: {
'x-content-type-options': 'nosniff',
'x-frame-options': 'DENY',
'x-xss-protection': '1; mode=block',
},
}),
],
// Route overrides for custom behavior
routeOverrides: [
(0, fastify_adapter_v2_1.createRouteOverride)('email-password', 'register', {
middleware: [
// Add rate limiting middleware
async (request, reply) => {
// Rate limiting logic here
},
],
}),
],
// Custom routes
customRoutes: [
(0, fastify_adapter_v2_1.createCustomRoute)('GET', '/auth/status', async (request, reply) => {
return reply.send({
authenticated: request.isAuthenticated,
user: request.user?.id || null,
timestamp: new Date().toISOString(),
});
}),
(0, fastify_adapter_v2_1.createCustomRoute)('POST', '/auth/logout', async (request, reply) => {
// Clear all auth cookies
reply.clearCookie('secure_session');
return reply.send({
success: true,
message: 'Logged out successfully',
});
}),
],
// Global middleware (using Fastify hooks)
globalMiddleware: [
// CORS middleware
async (request, reply) => {
reply.header('Access-Control-Allow-Origin', process.env.FRONTEND_URL || '*');
reply.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
reply.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, X-CSRF-Token');
reply.header('Access-Control-Allow-Credentials', 'true');
if (request.method === 'OPTIONS') {
return reply.status(204).send();
}
},
],
// Custom error handler
errorHandler: (error, context) => {
console.error('ReAuth Error:', error);
return context.status(500).send({
success: false,
message: process.env.NODE_ENV === 'production'
? 'An error occurred'
: error.message,
timestamp: new Date().toISOString(),
});
},
};
const adapter = (0, fastify_adapter_v2_1.createFastifyAdapter)(fastify, reAuthEngine, config);
// Add protection middleware for admin routes
const adminProtection = adapter.protect({
roles: ['admin', 'super_admin'],
authorize: async (user, request, reply) => {
// Additional authorization logic
const adminKey = request.headers['x-admin-key'];
return adminKey === process.env.ADMIN_SECRET_KEY;
},
});
// Add admin routes with protection
adapter.addRoute('GET', '/admin/users', async (request, reply) => {
// Admin-only user management
return reply.send({ users: [] });
}, {
middleware: [adminProtection],
requireAuth: true,
});
return adapter;
}
/**
* Utility function to create a Fastify plugin for ReAuth
*/
async function createReAuthFastifyPlugin(reAuthEngine) {
return fastify_adapter_v2_1.FastifyAdapterV2.createPlugin(reAuthEngine, {
basePath: '/auth',
cookieName: 'auth_token',
autoIntrospection: {
enabled: true,
},
});
}
/**
* Complete example showing how to set up a Fastify server with ReAuth
*/
async function createCompleteFastifyApp(reAuthEngine) {
const fastify = require('fastify')({ logger: true });
// Register cookie support
await fastify.register(require('@fastify/cookie'));
// Register CORS
await fastify.register(require('@fastify/cors'), {
origin: process.env.FRONTEND_URL || true,
credentials: true,
});
// Create and register the auth adapter
const adapter = await createProductionFastifyAdapter(fastify, reAuthEngine);
// Add other application routes
fastify.get('/', async (request, reply) => {
return { message: 'ReAuth Fastify App', version: '1.0.0' };
});
fastify.get('/api/protected', async (request, reply) => {
if (!request.isAuthenticated) {
return reply.status(401).send({ error: 'Unauthorized' });
}
return {
message: 'Protected resource',
userId: request.user.id,
};
});
return fastify;
}
//# sourceMappingURL=example-usage-v2.js.map