Skip to main content

auth-implementation-patterns

Master authentication and authorization patterns including JWT, OAuth2, session management, and RBAC to build secure, scalable access control systems. Use when implementing auth systems, securing APIs, or debugging security issues.

소스 정보

저장소
majiayu000/claude-skill-registry-data
최근 소스 활동
2026년 4월 21일 02:21
감지된 SKILL.md 언어
영어
스타
22
포크
8

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

파일 탐색기
2 개 파일

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
auth-implementation-patterns
description
Master authentication and authorization patterns including JWT, OAuth2, session management, and RBAC to build secure, scalable access control systems. Use when implementing auth systems, securing APIs, or debugging security issues.
# Authentication & Authorization Implementation Patterns Build secure, scalable authentication and authorization systems using industry-standard patterns and modern best practices. ## When to Use This Skill - Implementing user authentication systems - Securing REST or GraphQL APIs - Adding OAuth2/social login - Implementing role-based access control (RBAC) - Designing session management - Migrating authentication systems - Debugging auth issues - Implementing SSO or multi-tenancy ## Core Concepts ### 1. Authentication vs Authorization **Authentication (AuthN)**: Who are you? - Verifying identity (username/password, OAuth, biometrics) - Issuing credentials (sessions, tokens) - Managing login/logout **Authorization (AuthZ)**: What can you do? - Permission checking - Role-based access control (RBAC) - Resource ownership validation - Policy enforcement ### 2. Authentication Strategies **Session-Based:** - Server stores session state - Session ID in cookie - Traditional, simple, stateful **Token-Based (JWT):** - Stateless, self-contained - Scales horizontally - Can store claims **OAuth2/OpenID Connect:** - Delegate authentication - Social login (Google, GitHub) - Enterprise SSO ## JWT Authentication ### Pattern 1: JWT Implementation ```typescript // JWT structure: header.payload.signature import jwt from 'jsonwebtoken' import { Request, Response, NextFunction } from 'express' interface JWTPayload { userId: string email: string role: string iat: number exp: number } // Generate JWT function generateTokens(userId: string, email: string, role: string) { const accessToken = jwt.sign( { userId, email, role }, process.env.JWT_SECRET!, { expiresIn: '15m' } // Short-lived ) const refreshToken = jwt.sign( { userId }, process.env.JWT_REFRESH_SECRET!, { expiresIn: '7d' } // Long-lived ) return { accessToken, refreshToken } } // Verify JWT function verifyToken(token: string): JWTPayload { try { return jwt.verify(token, process.env.JWT_SECRET!) as JWTPayload } catch (error) { if (error instanceof jwt.TokenExpiredError) { throw new Error('Token expired') } if (error instanceof jwt.JsonWebTokenError) { throw new Error('Invalid token') } throw error } } // Middleware function authenticate(req: Request, res: Response, next: NextFunction) { const authHeader = req.headers.authorization if (!authHeader?.startsWith('Bearer ')) { return res.status(401).json({ error: 'No token provided' }) } const token = authHeader.substring(7) try { const payload = verifyToken(token) req.user = payload // Attach user to request next() } catch (error) { return res.status(401).json({ error: 'Invalid token' }) } } // Usage app.get('/api/profile', authenticate, (req, res) => { res.json({ user: req.user }) }) ``` ### Pattern 2: Refresh Token Flow ```typescript interface StoredRefreshToken { token: string userId: string expiresAt: Date createdAt: Date } class RefreshTokenService { // Store refresh token in database async storeRefreshToken(userId: string, refreshToken: string) { const expiresAt = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) await db.refreshTokens.create({ token: await hash(refreshToken), // Hash before storing userId, expiresAt, }) } // Refresh access token async refreshAccessToken(refreshToken: string) { // Verify refresh token let payload try { payload = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET!) as { userId: string } } catch { throw new Error('Invalid refresh token') } // Check if token exists in database const storedToken = await db.refreshTokens.findOne({ where: { token: await hash(refreshToken), userId: payload.userId, expiresAt: { $gt: new Date() }, }, }) if (!storedToken) { throw new Error('Refresh token not found or expired') } // Get user const user = await db.users.findById(payload.userId) if (!user) { throw new Error('User not found') } // Generate new access token const accessToken = jwt.sign({ userId: user.id, email: user.email, role: user.role }, process.env.JWT_SECRET!, { expiresIn: '15m', }) return { accessToken } } // Revoke refresh token (logout) async revokeRefreshToken(refreshToken: string) { await db.refreshTokens.deleteOne({ token: await hash(refreshToken), }) } // Revoke all user tokens (logout all devices) async revokeAllUserTokens(userId: string) { await db.refreshTokens.deleteMany({ userId }) } } // API endpoints app.post('/api/auth/refresh', async (req, res) => { const { refreshToken } = req.body try { const { accessToken } = await refreshTokenService.refreshAccessToken(refreshToken) res.json({ accessToken }) } catch (error) { res.status(401).json({ error: 'Invalid refresh token' }) } }) app.post('/api/auth/logout', authenticate, async (req, res) => { const { refreshToken } = req.body await refreshTokenService.revokeRefreshToken(refreshToken) res.json({ message: 'Logged out successfully' }) }) ``` ## Session-Based Authentication ### Pattern 1: Express Session ```typescript import session from 'express-session' import RedisStore from 'connect-redis' import { createClient } from 'redis' // Setup Redis for session storage const redisClient = createClient({ url: process.env.REDIS_URL, }) await redisClient.connect() app.use( session({ store: new RedisStore({ client: redisClient }), secret: process.env.SESSION_SECRET!, resave: false, saveUninitialized: false, cookie: { secure: process.env.NODE_ENV === 'production', // HTTPS only httpOnly: true, // No JavaScript access maxAge: 24 * 60 * 60 * 1000, // 24 hours sameSite: 'strict', // CSRF protection }, }) ) // Login app.post('/api/auth/login', async (req, res) => { const { email, password } = req.body const user = await db.users.findOne({ email }) if (!user || !(await verifyPassword(password, user.passwordHash))) { return res.status(401).json({ error: 'Invalid credentials' }) } // Store user in session req.session.userId = user.id req.session.role = user.role res.json({ user: { id: user.id, email: user.email, role: user.role } }) }) // Session middleware function requireAuth(req: Request, res: Response, next: NextFunction) { if (!req.session.userId) { return res.status(401).json({ error: 'Not authenticated' }) } next() } // Protected route app.get('/api/profile', requireAuth, async (req, res) => { const user = await db.users.findById(req.session.userId) res.json({ user }) }) // Logout app.post('/api/auth/logout', (req, res) => { req.session.destroy((err) => { if (err) { return res.status(500).json({ error: 'Logout failed' }) } res.clearCookie('connect.sid') res.json({ message: 'Logged out successfully' }) }) }) ``` ## OAuth2 / Social Login ### Pattern 1: OAuth2 with Passport.js ```typescript import passport from 'passport' import { Strategy as GoogleStrategy } from 'passport-google-oauth20' import { Strategy as GitHubStrategy } from 'passport-github2' // Google OAuth passport.use( new GoogleStrategy( { clientID: process.env.GOOGLE_CLIENT_ID!, clientSecret: process.env.GOOGLE_CLIENT_SECRET!, callbackURL: '/api/auth/google/callback', }, async (accessToken, refreshToken, profile, done) => { try { // Find or create user let user = await db.users.findOne({ googleId: profile.id, }) if (!user) { user = await db.users.create({ googleId: profile.id, email: profile.emails?.[0]?.value, name: profile.displayName, avatar: profile.photos?.[0]?.value, }) } return done(null, user) } catch (error) { return done(error, undefined) } } ) ) // Routes app.get( '/api/auth/google', passport.authenticate('google', { scope: ['profile', 'email'], }) ) app.get('/api/auth/google/callback', passport.authenticate('google', { session: false }), (req, res) => { // Generate JWT const tokens = generateTokens(req.user.id, req.user.email, req.user.role) // Redirect to frontend with token res.redirect(`${process.env.FRONTEND_URL}/auth/callback?token=${tokens.accessToken}`) }) ``` ## Authorization Patterns ### Pattern 1: Role-Based Access Control (RBAC) ```typescript enum Role { USER = 'user', MODERATOR = 'moderator', ADMIN = 'admin', } const roleHierarchy: Record<Role, Role[]> = { [Role.ADMIN]: [Role.ADMIN, Role.MODERATOR, Role.USER], [Role.MODERATOR]: [Role.MODERATOR, Role.USER], [Role.USER]: [Role.USER], } function hasRole(userRole: Role, requiredRole: Role): boolean { return roleHierarchy[userRole].includes(requiredRole) } // Middleware function requireRole(...roles: Role[]) { return (req: Request, res: Response, next: NextFunction) => { if (!req.user) { return res.status(401).json({ error: 'Not authenticated' }) } if (!roles.some((role) => hasRole(req.user.role, role))) { return res.status(403).json({ error: 'Insufficient permissions' }) } next() } } // Usage app.delete('/api/users/:id', authenticate, requireRole(Role.ADMIN), async (req, res) => { // Only admins can delete users await db.users.delete(req.params.id) res.json({ message: 'User deleted' }) }) ``` ### Pattern 2: Permission-Based Access Control ```typescript enum Permission { READ_USERS = 'read:users', WRITE_USERS = 'write:users', DELETE_USERS = 'delete:users', READ_POSTS = 'read:posts', WRITE_POSTS = 'write:posts', } const rolePermissions: Record<Role, Permission[]> = { [Role.USER]: [Permission.READ_POSTS, Permission.WRITE_POSTS], [Role.MODERATOR]: [Permission.READ_POSTS, Permission.WRITE_POSTS, Permission.READ_USERS], [Role.ADMIN]: Object.values(Permission), } function hasPermission(userRole: Role, permission: Permission): boolean { return rolePermissions[userRole]?.includes(permission) ?? false } function requirePermission(...permissions: Permission[]) { return (req: Request, res: Response, next: NextFunction) => { if (!req.user) { return res.status(401).json({ error: 'Not authenticated' }) } const hasAllPermissions = permissions.every((permission) => hasPermission(req.user.role, permission)) if (!hasAllPermissions) { return res.status(403).json({ error: 'Insufficient permissions' }) } next() } } // Usage app.get('/api/users', authenticate, requirePermission(Permission.READ_USERS), async (req, res) => { const users = await db.users.findAll() res.json({ users }) }) ``` ### Pattern 3: Resource Ownership ```typescript // Check if user owns resource async function requireOwnership(resourceType: 'post' | 'comment', resourceIdParam: string = 'id') { return async (req: Request, res: Response, next: NextFunction) => { if (!req.user) { return res.status(401).json({ error: 'Not authenticated' }) }
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기