with one click
auth-patterns
Authentication and authorization patterns. JWT, sessions, OAuth 2.0, RBAC, ABAC, refresh tokens, security.
Menu
Authentication and authorization patterns. JWT, sessions, OAuth 2.0, RBAC, ABAC, refresh tokens, security.
Web accessibility (a11y). WCAG 2.1, ARIA, keyboard navigation, screen readers, testing tools.
Analytics and event tracking. Product analytics, Mixpanel, PostHog, Segment, GDPR compliance, event taxonomy.
UI animation patterns. CSS transitions, Framer Motion, GSAP, performance, accessibility.
Background job patterns. Cron jobs, queued jobs, scheduling, BullMQ, pg-boss, Sidekiq patterns.
Caching patterns. HTTP caching, Redis, CDN, browser cache, cache invalidation strategies.
CI/CD pipeline patterns. GitHub Actions, GitLab CI, Docker builds, testing, deployment stages, secrets management.
| name | auth-patterns |
| description | Authentication and authorization patterns. JWT, sessions, OAuth 2.0, RBAC, ABAC, refresh tokens, security. |
Authentication = who are you? Authorization = what can you do?
| Strategy | Best For | Stateless? |
|---|---|---|
| Session + Cookie | Traditional web, SSR | No |
| JWT (access token) | SPAs, mobile, stateless APIs | Yes |
| JWT + Refresh Token | Long-lived sessions, mobile | Yes* |
| OAuth 2.0 (provider) | Third-party login | Yes |
| API Keys | Server-to-server, dev tools | Yes |
| Passkeys (WebAuthn) | Passwordless modern | Yes |
| mTLS | Service-to-service internal | Yes |
Access Token: Short-lived (15min) → sent in Authorization header
Refresh Token: Long-lived (7–30d) → HttpOnly cookie or secure storage
Flow:
Login → [access_token, refresh_token]
Request → Authorization: Bearer {access_token}
Token expires → POST /auth/refresh (with refresh_token)
Logout → invalidate refresh_token in DB
// JWT payload (keep minimal)
{
sub: "user-id",
email: "user@example.com",
role: "admin",
iat: 1704067200,
exp: 1704068100 // 15 min
}
// NEVER include: password, secret data, PII beyond necessary
1. User sends refresh_token
2. Server validates + checks DB (not revoked)
3. Server issues NEW access_token + NEW refresh_token
4. Server revokes OLD refresh_token in DB
5. Return new tokens
Refresh token family:
If old refresh token reused → revoke entire family
(detects token theft)
// Secure cookie setup (Express)
app.use(session({
secret: process.env.SESSION_SECRET,
name: "__sess",
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true, // No JS access
secure: true, // HTTPS only
sameSite: "lax", // CSRF protection
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days
},
store: new RedisStore({ client: redis }), // Not in-memory!
}));
| Flow | Use Case |
|---|---|
| Authorization Code + PKCE | Web apps, mobile (standard) |
| Client Credentials | Server-to-server |
| Device Code | TV, CLI, limited-input devices |
Authorization Code + PKCE:
1. App generates code_verifier + code_challenge
2. Redirect to provider: ?response_type=code&code_challenge=...
3. User authenticates at provider
4. Provider redirects back with code
5. App exchanges code + code_verifier for tokens
6. App receives access_token (+ refresh_token)
// Role definitions
enum Role { VIEWER = "viewer", EDITOR = "editor", ADMIN = "admin" }
// Permission map
const permissions = {
"posts:read": [Role.VIEWER, Role.EDITOR, Role.ADMIN],
"posts:write": [Role.EDITOR, Role.ADMIN],
"posts:delete": [Role.ADMIN],
"users:manage": [Role.ADMIN],
};
function can(user: User, action: string): boolean {
return permissions[action]?.includes(user.role) ?? false;
}
// Middleware
function requirePermission(action: string) {
return (req, res, next) => {
if (!can(req.user, action)) {
return res.status(403).json({ error: "Forbidden" });
}
next();
};
}
// More granular than RBAC
function canEditPost(user: User, post: Post): boolean {
return (
user.id === post.authorId || // Own post
user.role === "admin" || // Admin
(user.role === "editor" && post.orgId === user.orgId) // Same org
);
}
// Hashing (bcrypt / argon2)
import { hash, verify } from "@node-rs/argon2";
// On register
const hashedPassword = await hash(password, {
memoryCost: 19456, // 19 MiB
timeCost: 2,
outputLen: 32,
parallelism: 1,
});
// On login
const valid = await verify(hashedPassword, inputPassword);
// Rules:
// - Min 8 chars, no max < 64
// - Check against HaveIBeenPwned API
// - Allow paste in password fields
// - NEVER log passwords