en un clic
authentication-patterns
// Authentication and authorization patterns including OAuth2, JWT, RBAC, session management, and PKCE flows
// Authentication and authorization patterns including OAuth2, JWT, RBAC, session management, and PKCE flows
Route broad or ambiguous AgentKit SEO work to the right module while keeping context scoped. Use when a request spans multiple surfaces, asks for overall digital-presence strategy, involves provider or install architecture, needs agent-context planning, or the correct platform skill is unclear.
Persistent memory system for Claude Code. Two-layer architecture (hot cache + knowledge wiki), safety hooks, /close-day end-of-day synthesis. Zero external dependencies.
Claude-native deep research using DAG-based query planning, parallel subagent execution, and gap-driven iteration. No external API needed.
Discover, list, create, edit, toggle, copy, move, and delete AI agent skills across 11 tools (Cursor, Claude, Agents, Windsurf, Copilot, Codex, Cline, Aider, Continue, Roo Code, Augment)
Web accessibility patterns for WCAG 2.2 compliance including ARIA, keyboard navigation, screen readers, and testing
AWS cloud patterns for Lambda, ECS, S3, DynamoDB, and Infrastructure as Code with CDK/Terraform
| name | authentication-patterns |
| description | Authentication and authorization patterns including OAuth2, JWT, RBAC, session management, and PKCE flows |
import jwt from "jsonwebtoken";
interface TokenPayload {
sub: string;
email: string;
roles: string[];
}
function generateTokens(user: User) {
const accessToken = jwt.sign(
{ sub: user.id, email: user.email, roles: user.roles },
process.env.JWT_SECRET!,
{ expiresIn: "15m", issuer: "auth-service" }
);
const refreshToken = jwt.sign(
{ sub: user.id, tokenVersion: user.tokenVersion },
process.env.REFRESH_SECRET!,
{ expiresIn: "7d", issuer: "auth-service" }
);
return { accessToken, refreshToken };
}
function verifyAccessToken(token: string): TokenPayload {
return jwt.verify(token, process.env.JWT_SECRET!, {
issuer: "auth-service",
}) as TokenPayload;
}
Short-lived access tokens (15 minutes) with longer-lived refresh tokens (7 days). Store refresh tokens in HTTP-only cookies.
function authenticate(req: Request, res: Response, next: NextFunction) {
const header = req.headers.authorization;
if (!header?.startsWith("Bearer ")) {
return res.status(401).json({ error: "Missing authorization header" });
}
try {
const payload = verifyAccessToken(header.slice(7));
req.user = payload;
next();
} catch (error) {
if (error instanceof jwt.TokenExpiredError) {
return res.status(401).json({ error: "Token expired" });
}
return res.status(401).json({ error: "Invalid token" });
}
}
function authorize(...roles: string[]) {
return (req: Request, res: Response, next: NextFunction) => {
if (!req.user) return res.status(401).json({ error: "Not authenticated" });
if (!roles.some(role => req.user.roles.includes(role))) {
return res.status(403).json({ error: "Insufficient permissions" });
}
next();
};
}
app.get("/admin/users", authenticate, authorize("admin"), listUsers);
import crypto from "crypto";
function generatePKCE() {
const verifier = crypto.randomBytes(32).toString("base64url");
const challenge = crypto
.createHash("sha256")
.update(verifier)
.digest("base64url");
return { verifier, challenge };
}
app.get("/auth/login", (req, res) => {
const { verifier, challenge } = generatePKCE();
req.session.codeVerifier = verifier;
const params = new URLSearchParams({
response_type: "code",
client_id: process.env.OAUTH_CLIENT_ID!,
redirect_uri: `${process.env.APP_URL}/auth/callback`,
scope: "openid profile email",
code_challenge: challenge,
code_challenge_method: "S256",
state: crypto.randomBytes(16).toString("hex"),
});
res.redirect(`${process.env.OAUTH_AUTHORIZE_URL}?${params}`);
});
app.get("/auth/callback", async (req, res) => {
const { code } = req.query;
const tokenResponse = await fetch(process.env.OAUTH_TOKEN_URL!, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
grant_type: "authorization_code",
code: code as string,
redirect_uri: `${process.env.APP_URL}/auth/callback`,
client_id: process.env.OAUTH_CLIENT_ID!,
code_verifier: req.session.codeVerifier,
}),
});
const tokens = await tokenResponse.json();
const userInfo = jwt.decode(tokens.id_token);
req.session.user = { id: userInfo.sub, email: userInfo.email };
res.redirect("/dashboard");
});
interface Permission {
resource: string;
action: "create" | "read" | "update" | "delete";
}
const ROLE_PERMISSIONS: Record<string, Permission[]> = {
viewer: [
{ resource: "posts", action: "read" },
{ resource: "comments", action: "read" },
],
editor: [
{ resource: "posts", action: "create" },
{ resource: "posts", action: "read" },
{ resource: "posts", action: "update" },
{ resource: "comments", action: "create" },
{ resource: "comments", action: "read" },
],
admin: [
{ resource: "*", action: "create" },
{ resource: "*", action: "read" },
{ resource: "*", action: "update" },
{ resource: "*", action: "delete" },
],
};
function hasPermission(roles: string[], resource: string, action: string): boolean {
return roles.some(role =>
ROLE_PERMISSIONS[role]?.some(
p => (p.resource === resource || p.resource === "*") && p.action === action
)
);
}
localStorage (vulnerable to XSS; use HTTP-only cookies)iss, aud, and exp claims on token verification