--- description: Generate authentication boilerplate with JWT, OAuth, and session support shortcut: as category: backend difficulty: intermediate estimated_time: 5-10 minutes --- # Auth Setup Generates complete authentication boilerplate including JWT, OAuth (Google/GitHub), session management, and password reset flows. ## What This Command Does **Generated Auth System:** - JWT authentication with refresh tokens - OAuth2 (Google, GitHub, Facebook) - Password hashing (bcrypt) - Email verification - Password reset flow - Session management - Rate limiting on auth endpoints - Authentication middleware **Output:** Complete authentication system ready for production **Time:** 5-10 minutes --- ## Usage ```bash # Generate full auth system /auth-setup jwt # Shortcut /as oauth --providers google,github # With specific features /as jwt --features email-verification,password-reset,2fa ``` --- ## Example Output ### **JWT Authentication** **auth.service.ts:** ```typescript import bcrypt from 'bcrypt' import jwt from 'jsonwebtoken' import { User } from './models/User' export class AuthService { async register(email: string, password: string, name: string) { // Check if user exists const existing = await User.findOne({ email }) if (existing) { throw new Error('Email already registered') } // Hash password const hashedPassword = await bcrypt.hash(password, 12) // Create user const user = await User.create({ email, password: hashedPassword, name, emailVerified: false }) // Generate verification token const verificationToken = this.generateToken({ userId: user.id, type: 'verify' }, '24h') // Send verification email (implement sendEmail) await this.sendVerificationEmail(email, verificationToken) // Generate auth tokens const accessToken = this.generateAccessToken(user) const refreshToken = this.generateRefreshToken(user) return { user: { id: user.id, email: user.email, name: user.name }, accessToken, refreshToken } } async login(email: string, password: string) { const user = await User.findOne({ email }) if (!user) { throw new Error('Invalid credentials') } const validPassword = await bcrypt.compare(password, user.password) if (!validPassword) { throw new Error('Invalid credentials') } if (!user.emailVerified) { throw new Error('Please verify your email') } const accessToken = this.generateAccessToken(user) const refreshToken = this.generateRefreshToken(user) return { user: { id: user.id, email: user.email, name: user.name }, accessToken, refreshToken } } async refreshToken(refreshToken: string) { try { const decoded = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET!) as any const user = await User.findById(decoded.userId) if (!user) { throw new Error('User not found') } const accessToken = this.generateAccessToken(user) return { accessToken } } catch (error) { throw new Error('Invalid refresh token') } } async verifyEmail(token: string) { const decoded = jwt.verify(token, process.env.JWT_SECRET!) as any if (decoded.type !== 'verify') { throw new Error('Invalid token type') } await User.findByIdAndUpdate(decoded.userId, { emailVerified: true }) return { message: 'Email verified successfully' } } async requestPasswordReset(email: string) { const user = await User.findOne({ email }) if (!user) { // Don't reveal if user exists return { message: 'If email exists, reset link sent' } } const resetToken = this.generateToken({ userId: user.id, type: 'reset' }, '1h') await this.sendPasswordResetEmail(email, resetToken) return { message: 'If email exists, reset link sent' } } async resetPassword(token: string, newPassword: string) { const decoded = jwt.verify(token, process.env.JWT_SECRET!) as any if (decoded.type !== 'reset') { throw new Error('Invalid token type') } const hashedPassword = await bcrypt.hash(newPassword, 12) await User.findByIdAndUpdate(decoded.userId, { password: hashedPassword }) return { message: 'Password reset successfully' } } private generateAccessToken(user: any) { return jwt.sign( { userId: user.id, email: user.email }, process.env.JWT_SECRET!, { expiresIn: '15m' } ) } private generateRefreshToken(user: any) { return jwt.sign( { userId: user.id }, process.env.JWT_REFRESH_SECRET!, { expiresIn: '7d' } ) } private generateToken(payload: any, expiresIn: string) { return jwt.sign(payload, process.env.JWT_SECRET!, { expiresIn }) } private async sendVerificationEmail(email: string, token: string) { // Implement with SendGrid, Resend, etc. } private async sendPasswordResetEmail(email: string, token: string) { // Implement with SendGrid, Resend, etc. } } ``` ### **OAuth2 Setup (Google)** **oauth.controller.ts:** ```typescript import { OAuth2Client } from 'google-auth-library' const googleClient = new OAuth2Client( process.env.GOOGLE_CLIENT_ID, process.env.GOOGLE_CLIENT_SECRET, process.env.GOOGLE_REDIRECT_URI ) export class OAuthController { async googleLogin(req: Request, res: Response) { const authUrl = googleClient.generateAuthUrl({ access_type: 'offline', scope: ['profile', 'email'] }) res.redirect(authUrl) } async googleCallback(req: Request, res: Response) { const { code } = req.query const { tokens } = await googleClient.getToken(code as string) googleClient.setCredentials(tokens) const ticket = await googleClient.verifyIdToken({ idToken: tokens.id_token!, audience: process.env.GOOGLE_CLIENT_ID }) const payload = ticket.getPayload() if (!payload) { throw new Error('Invalid token') } // Find or create user let user = await User.findOne({ email: payload.email }) if (!user) { user = await User.create({ email: payload.email, name: payload.name, avatar: payload.picture, emailVerified: true, provider: 'google', providerId: payload.sub }) } // Generate tokens const accessToken = generateAccessToken(user) const refreshToken = generateRefreshToken(user) // Redirect with tokens res.redirect(`/auth/success?token=${accessToken}&refresh=${refreshToken}`) } } ``` ### **Authentication Middleware** **auth.middleware.ts:** ```typescript import { Request, Response, NextFunction } from 'express' import jwt from 'jsonwebtoken' declare global { namespace Express { interface Request { user?: { userId: string email: string } } } } export async function authenticate(req: Request, res: Response, next: NextFunction) { try { const authHeader = req.headers.authorization if (!authHeader?.startsWith('Bearer ')) { return res.status(401).json({ error: 'No token provided' }) } const token = authHeader.split(' ')[1] const decoded = jwt.verify(token, process.env.JWT_SECRET!) as any req.user = { userId: decoded.userId, email: decoded.email } next() } catch (error) { if (error instanceof jwt.TokenExpiredError) { return res.status(401).json({ error: 'Token expired' }) } return res.status(401).json({ error: 'Invalid token' }) } } export function authorize(...roles: string[]) { return async (req: Request, res: Response, next: NextFunction) => { if (!req.user) { return res.status(401).json({ error: 'Not authenticated' }) } const user = await User.findById(req.user.userId) if (!user || !roles.includes(user.role)) { return res.status(403).json({ error: 'Insufficient permissions' }) } next() } } ``` ### **Rate Limiting** ```typescript import rateLimit from 'express-rate-limit' export const authLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 5, // 5 requests per window message: 'Too many login attempts, please try again later', standardHeaders: true, legacyHeaders: false }) // Usage app.post('/api/auth/login', authLimiter, authController.login) ``` --- ## Environment Variables ```bash # JWT JWT_SECRET=your-super-secret-key-min-32-chars JWT_REFRESH_SECRET=your-refresh-secret-key JWT_EXPIRES_IN=15m JWT_REFRESH_EXPIRES_IN=7d # OAuth - Google GOOGLE_CLIENT_ID=your-client-id.apps.googleusercontent.com GOOGLE_CLIENT_SECRET=your-client-secret GOOGLE_REDIRECT_URI=http://localhost:3000/api/auth/google/callback # OAuth - GitHub GITHUB_CLIENT_ID=your-github-client-id GITHUB_CLIENT_SECRET=your-github-client-secret GITHUB_REDIRECT_URI=http://localhost:3000/api/auth/github/callback # Email SMTP_HOST=smtp.sendgrid.net SMTP_PORT=587 SMTP_USER=apikey SMTP_PASSWORD=your-sendgrid-api-key FROM_EMAIL=[email protected] ``` --- ## API Routes ```typescript // routes/auth.routes.ts import { Router } from 'express' import { AuthController } from '../controllers/auth.controller' import { authenticate } from '../middleware/auth.middleware' import { authLimiter } from '../middleware/rate-limit' const router = Router() const authController = new AuthController() // Registration & Login router.post('/register', authController.register) router.post('/login', authLimiter, authController.login) router.post('/refresh', authController.refreshToken) router.post('/logout', authenticate, authController.logout) // Email Verification router.post('/verify-email', authController.verifyEmail) router.post('/resend-verification', authController.resendVerification) // Password Reset router.post('/forgot-password', authLimiter, authController.forgotPassword) router.post('/reset-password', authController.resetPassword) // OAuth router.get('/google', authController.googleLogin) router.get('/google/callback', authController.googleCallback) router.get('/github', authController.githubLogin) router.get('/github/callback', authController.githubCallback) // Profile router.get('/me', authenticate, authController.getProfile) router.patch('/me', authenticate, authController.updateProfile) router.post('/change-password', authenticate, authController.changePassword) export default router ``` --- ## Related Commands - `/env-config-setup` - Generate environment config - `/express-api-scaffold` - Generate Express API - `/fastapi-scaffold` - Generate FastAPI --- **Secure authentication. Easy integration. Production-ready.**