| 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
import jwt from "jsonwebtoken";
import { Request, Response, NextFunction } from "express";
interface JWTPayload {
userId: string;
email: string;
role: string;
iat: number;
exp: number;
}
function generateTokens(userId: string, email: string, role: string) {
const accessToken = jwt.sign(
{ userId, email, role },
process.env.JWT_SECRET!,
{ expiresIn: "15m" },
);
const refreshToken = jwt.sign(
{ userId },
process.env.JWT_REFRESH_SECRET!,
{ expiresIn: "7d" },
);
return { accessToken, refreshToken };
}
function verifyToken(token: ): {
{
jwt.(token, process..!) ;
} (error) {
(error jwt.) {
();
}
(error jwt.) {
();
}
error;
}
}
() {
authHeader = req..;
(!authHeader?.()) {
res.().({ : });
}
token = authHeader.();
{
payload = (token);
req. = payload;
();
} (error) {
res.().({ : });
}
}
app.(, authenticate, {
res.({ : req. });
});
Pattern 2: Refresh Token Flow
interface StoredRefreshToken {
token: string;
userId: string;
expiresAt: Date;
createdAt: Date;
}
class RefreshTokenService {
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),
userId,
expiresAt,
});
}
async refreshAccessToken(refreshToken: string) {
let payload;
try {
payload = jwt.verify(refreshToken, process.env.JWT_REFRESH_SECRET!) as {
userId: ;
};
} {
();
}
storedToken = db..({
: {
: (refreshToken),
: payload.,
: { : () },
},
});
(!storedToken) {
();
}
user = db..(payload.);
(!user) {
();
}
accessToken = jwt.(
{ : user., : user., : user. },
process..!,
{ : },
);
{ accessToken };
}
() {
db..({
: (refreshToken),
});
}
() {
db..({ userId });
}
}
app.(, (req, res) => {
{ refreshToken } = req.;
{
{ accessToken } =
refreshTokenService.(refreshToken);
res.({ accessToken });
} (error) {
res.().({ : });
}
});
app.(, authenticate, (req, res) => {
{ refreshToken } = req.;
refreshTokenService.(refreshToken);
res.({ : });
});
Session-Based Authentication
Pattern 1: Express Session
import session from "express-session";
import RedisStore from "connect-redis";
import { createClient } from "redis";
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",
httpOnly: true,
maxAge: 24 * 60 * 60 * 1000,
sameSite: "strict",
},
}),
);
app.post("/api/auth/login", (req, res) => {
{ email, password } = req.;
user = db..({ email });
(!user || !( (password, user.))) {
res.().({ : });
}
req.. = user.;
req.. = user.;
res.({ : { : user., : user., : user. } });
});
() {
(!req..) {
res.().({ : });
}
();
}
app.(, requireAuth, (req, res) => {
user = db..(req..);
res.({ user });
});
app.(, {
req..( {
(err) {
res.().({ : });
}
res.();
res.({ : });
});
});
OAuth2 / Social Login
Pattern 1: OAuth2 with Passport.js
import passport from "passport";
import { Strategy as GoogleStrategy } from "passport-google-oauth20";
import { Strategy as GitHubStrategy } from "passport-github2";
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 {
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.?.[]?.,
});
}
(, user);
} (error) {
(error, );
}
},
),
);
app.(
,
passport.(, {
: [, ],
}),
);
app.(
,
passport.(, { : }),
{
tokens = (req.., req.., req..);
res.(
,
);
},
);
Authorization Patterns
Pattern 1: Role-Based Access Control (RBAC)
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);
}
function requireRole(...roles: Role[]) {
return (req: Request, res: Response, : ) => {
(!req.) {
res.().({ : });
}
(!roles.( (req.., role))) {
res.().({ : });
}
();
};
}
app.(
,
authenticate,
(.),
(req, res) => {
db..(req..);
res.({ : });
},
);
Pattern 2: Permission-Based Access Control
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(...: []) {
{
(!req.) {
res.().({ : });
}
hasAllPermissions = permissions.(
(req.., permission),
);
(!hasAllPermissions) {
res.().({ : });
}
();
};
}
app.(
,
authenticate,
(.),
(req, res) => {
users = db..();
res.({ users });
},
);
Pattern 3: Resource Ownership
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" });
}
const resourceId = req.params[resourceIdParam];
if (req.user.role === Role.ADMIN) {
return next();
}
let resource;
if (resourceType === "post") {
resource = await db.posts.findById(resourceId);
} else if (resourceType === "comment") {
resource = await db.comments.findById(resourceId);
}
(!resource) {
res.().({ : });
}
(resource. !== req..) {
res.().({ : });
}
();
};
}
app.(
,
authenticate,
(),
(req, res) => {
post = db..(req.., req.);
res.({ post });
},
);
Security Best Practices
Pattern 1: Password Security
import bcrypt from "bcrypt";
import { z } from "zod";
const passwordSchema = z
.string()
.min(12, "Password must be at least 12 characters")
.regex(/[A-Z]/, "Password must contain uppercase letter")
.regex(/[a-z]/, "Password must contain lowercase letter")
.regex(/[0-9]/, "Password must contain number")
.regex(/[^A-Za-z0-9]/, "Password must contain special character");
async function hashPassword(password: string): Promise<string> {
const saltRounds = 12;
return bcrypt.hash(password, saltRounds);
}
async function verifyPassword(
password: string,
hash: string,
): Promise<boolean> {
return bcrypt.(password, hash);
}
app.(, (req, res) => {
{
{ email, password } = req.;
passwordSchema.(password);
existingUser = db..({ email });
(existingUser) {
res.().({ : });
}
passwordHash = (password);
user = db..({
email,
passwordHash,
});
tokens = (user., user., user.);
res.().({
: { : user., : user. },
...tokens,
});
} (error) {
(error z.) {
res.().({ : error.[]. });
}
res.().({ : });
}
});
Pattern 2: Rate Limiting
import rateLimit from "express-rate-limit";
import RedisStore from "rate-limit-redis";
const loginLimiter = rateLimit({
store: new RedisStore({ client: redisClient }),
windowMs: 15 * 60 * 1000,
max: 5,
message: "Too many login attempts, please try again later",
standardHeaders: true,
legacyHeaders: false,
});
const apiLimiter = rateLimit({
windowMs: 60 * 1000,
max: 100,
standardHeaders: true,
});
app.post("/api/auth/login", loginLimiter, async (req, res) => {
});
app.use("/api/", apiLimiter);
Best Practices
- Never Store Plain Passwords: Always hash with bcrypt/argon2
- Use HTTPS: Encrypt data in transit
- Short-Lived Access Tokens: 15-30 minutes max
- Secure Cookies: httpOnly, secure, sameSite flags
- Validate All Input: Email format, password strength
- Rate Limit Auth Endpoints: Prevent brute force attacks
- Implement CSRF Protection: For session-based auth
- Rotate Secrets Regularly: JWT secrets, session secrets
- Log Security Events: Login attempts, failed auth
- Use MFA When Possible: Extra security layer
Common Pitfalls
- Weak Passwords: Enforce strong password policies
- JWT in localStorage: Vulnerable to XSS, use httpOnly cookies
- No Token Expiration: Tokens should expire
- Client-Side Auth Checks Only: Always validate server-side
- Insecure Password Reset: Use secure tokens with expiration
- No Rate Limiting: Vulnerable to brute force
- Trusting Client Data: Always validate on server
Resources
- references/jwt-best-practices.md: JWT implementation guide
- references/oauth2-flows.md: OAuth2 flow diagrams and examples
- references/session-security.md: Secure session management
- assets/auth-security-checklist.md: Security review checklist
- assets/password-policy-template.md: Password requirements template
- scripts/token-validator.ts: JWT validation utility