Design and implement authentication and authorization systems. Use when setting up user login, JWT tokens, OAuth, session management, or role-based access control. Handles password security, token management, SSO integration.
90
88%
Does it follow best practices?
Impact
97%
1.19xAverage score across 3 eval scenarios
Passed
No known issues
Lists specific situations where this skill should be triggered:
The required and optional input information to collect from the user:
Build a user authentication system:
- Auth method: JWT
- Framework: Express.js + TypeScript
- Database: PostgreSQL
- MFA: Google Authenticator support
- Social login: Google, GitHub
- Refresh Token: enabledSpecifies the step-by-step task sequence to follow precisely.
Design the database schema for users and authentication.
Tasks:
Example (PostgreSQL):
CREATE TABLE users (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255), -- NULL if OAuth only
role VARCHAR(50) DEFAULT 'user',
is_verified BOOLEAN DEFAULT false,
mfa_secret VARCHAR(255),
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE TABLE refresh_tokens (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
token VARCHAR(500) UNIQUE NOT NULL,
expires_at TIMESTAMP NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_refresh_tokens_user_id ON refresh_tokens(user_id);Implement password hashing and verification logic.
Tasks:
Decision Criteria:
Example (Node.js + TypeScript):
import bcrypt from 'bcrypt';
const SALT_ROUNDS = 12;
export async function hashPassword(password: string): Promise<string> {
// Validate password strength
if (password.length < 8) {
throw new Error('Password must be at least 8 characters');
}
const hasUpperCase = /[A-Z]/.test(password);
const hasLowerCase = /[a-z]/.test(password);
const hasNumber = /\d/.test(password);
const hasSpecial = /[!@#$%^&*(),.?":{}|<>]/.test(password);
if (!hasUpperCase || !hasLowerCase || !hasNumber || !hasSpecial) {
throw new Error('Password must contain uppercase, lowercase, number, and special character');
}
return await bcrypt.hash(password, SALT_ROUNDS);
}
export async function verifyPassword(password: string, hash: string): Promise<boolean> {
return await bcrypt.compare(password, hash);
}Implement a token system for JWT-based authentication.
Tasks:
Example (Node.js):
import jwt from 'jsonwebtoken';
const ACCESS_TOKEN_SECRET = process.env.ACCESS_TOKEN_SECRET!;
const REFRESH_TOKEN_SECRET = process.env.REFRESH_TOKEN_SECRET!;
const ACCESS_TOKEN_EXPIRY = '15m';
const REFRESH_TOKEN_EXPIRY = '7d';
interface TokenPayload {
userId: string;
email: string;
role: string;
}
export function generateAccessToken(payload: TokenPayload): string {
return jwt.sign(payload, ACCESS_TOKEN_SECRET, {
expiresIn: ACCESS_TOKEN_EXPIRY,
issuer: 'your-app-name',
audience: 'your-app-users'
});
}
export function generateRefreshToken(payload: TokenPayload): string {
return jwt.sign(payload, REFRESH_TOKEN_SECRET, {
expiresIn: REFRESH_TOKEN_EXPIRY,
issuer: 'your-app-name',
audience: 'your-app-users'
});
}
export function verifyAccessToken(token: string): TokenPayload {
return jwt.verify(token, ACCESS_TOKEN_SECRET, {
issuer: 'your-app-name',
audience: 'your-app-users'
}) as TokenPayload;
}
export function verifyRefreshToken(token: string): TokenPayload {
return jwt.verify(token, REFRESH_TOKEN_SECRET, {
issuer: 'your-app-name',
audience: 'your-app-users'
}) as TokenPayload;
}Write authentication middleware to protect API requests.
Checklist:
Example (Express.js):
import { Request, Response, NextFunction } from 'express';
import { verifyAccessToken } from './jwt';
export interface AuthRequest extends Request {
user?: {
userId: string;
email: string;
role: string;
};
}
export function authenticateToken(req: AuthRequest, res: Response, next: NextFunction) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
if (!token) {
return res.status(401).json({ error: 'Access token required' });
}
try {
const payload = verifyAccessToken(token);
req.user = payload;
next();
} catch (error) {
if (error.name === 'TokenExpiredError') {
return res.status(401).json({ error: 'Token expired' });
}
return res.status(403).json({ error: 'Invalid token' });
}
}
// Role-based authorization middleware
export function requireRole(...roles: string[]) {
return (req: AuthRequest, res: Response, next: NextFunction) => {
if (!req.user) {
return res.status(401).json({ error: 'Authentication required' });
}
if (!roles.includes(req.user.role)) {
return res.status(403).json({ error: 'Insufficient permissions' });
}
next();
};
}Write APIs for registration, login, token refresh, etc.
Tasks:
Example:
import express from 'express';
import { hashPassword, verifyPassword } from './password';
import { generateAccessToken, generateRefreshToken, verifyRefreshToken } from './jwt';
import { authenticateToken } from './middleware';
const router = express.Router();
// Registration
router.post('/register', async (req, res) => {
try {
const { email, password } = req.body;
// Check for duplicate email
const existingUser = await db.user.findUnique({ where: { email } });
if (existingUser) {
return res.status(409).json({ error: 'Email already exists' });
}
// Hash the password
const passwordHash = await hashPassword(password);
// Create the user
const user = await db.user.create({
data: { email, password_hash: passwordHash, role: 'user' }
});
// Generate tokens
const accessToken = generateAccessToken({
userId: user.id,
email: user.email,
role: user.role
});
const refreshToken = generateRefreshToken({
userId: user.id,
email: user.email,
role: user.role
});
// Store Refresh token in DB
await db.refreshToken.create({
data: {
user_id: user.id,
token: refreshToken,
expires_at: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000) // 7 days
}
});
res.status(201).json({
user: { id: user.id, email: user.email, role: user.role },
accessToken,
refreshToken
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Login
router.post('/login', async (req, res) => {
try {
const { email, password } = req.body;
// Find the user
const user = await db.user.findUnique({ where: { email } });
if (!user || !user.password_hash) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Verify the password
const isValid = await verifyPassword(password, user.password_hash);
if (!isValid) {
return res.status(401).json({ error: 'Invalid credentials' });
}
// Generate tokens
const accessToken = generateAccessToken({
userId: user.id,
email: user.email,
role: user.role
});
const refreshToken = generateRefreshToken({
userId: user.id,
email: user.email,
role: user.role
});
// Store Refresh token
await db.refreshToken.create({
data: {
user_id: user.id,
token: refreshToken,
expires_at: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
}
});
res.json({
user: { id: user.id, email: user.email, role: user.role },
accessToken,
refreshToken
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Token refresh
router.post('/refresh', async (req, res) => {
try {
const { refreshToken } = req.body;
if (!refreshToken) {
return res.status(401).json({ error: 'Refresh token required' });
}
// Verify Refresh token
const payload = verifyRefreshToken(refreshToken);
// Check token in DB
const storedToken = await db.refreshToken.findUnique({
where: { token: refreshToken }
});
if (!storedToken || storedToken.expires_at < new Date()) {
return res.status(403).json({ error: 'Invalid or expired refresh token' });
}
// Generate new Access token
const accessToken = generateAccessToken({
userId: payload.userId,
email: payload.email,
role: payload.role
});
res.json({ accessToken });
} catch (error) {
res.status(403).json({ error: 'Invalid refresh token' });
}
});
// Current user info
router.get('/me', authenticateToken, async (req: AuthRequest, res) => {
try {
const user = await db.user.findUnique({
where: { id: req.user!.userId },
select: { id: true, email: true, role: true, created_at: true }
});
res.json({ user });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
export default router;Defines the exact format that deliverables should follow.
Project directory/
├── src/
│ ├── auth/
│ │ ├── password.ts # password hashing/verification
│ │ ├── jwt.ts # JWT token generation/verification
│ │ ├── middleware.ts # authentication middleware
│ │ └── routes.ts # authentication API endpoints
│ ├── models/
│ │ └── User.ts # user model
│ └── database/
│ └── schema.sql # database schema
├── .env.example # environment variable template
└── README.md # authentication system documentation# JWT Secrets (MUST change in production)
ACCESS_TOKEN_SECRET=your-access-token-secret-min-32-characters
REFRESH_TOKEN_SECRET=your-refresh-token-secret-min-32-characters
# Database
DATABASE_URL=postgresql://user:password@localhost:5432/myapp
# OAuth (Optional)
GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secretSpecifies mandatory rules and prohibited actions.
Password Security: Never store passwords in plaintext
Environment Variable Management: Manage all secret keys via environment variables
Token Expiry: Access Tokens should be short-lived (15 min), Refresh Tokens appropriately longer (7 days)
Plaintext Passwords: Never store passwords in plaintext or print them to logs
Hardcoding JWT SECRET: Do not write SECRET keys directly in code
Sensitive Data in Tokens: Do not include passwords, card numbers, or other sensitive data in JWT payloads
Demonstrates how to apply the skill through real-world use cases.
Situation: Adding JWT-based user authentication to a Node.js Express app
User Request:
Add JWT authentication to an Express.js app using PostgreSQL,
with access token expiry of 15 minutes and refresh token expiry of 7 days.Skill Application Process:
Install packages:
npm install jsonwebtoken bcrypt pg
npm install --save-dev @types/jsonwebtoken @types/bcryptCreate the database schema (use the SQL above)
Set environment variables:
ACCESS_TOKEN_SECRET=$(openssl rand -base64 32)
REFRESH_TOKEN_SECRET=$(openssl rand -base64 32)Implement auth modules (use the code examples above)
Connect API routes:
import authRoutes from './auth/routes';
app.use('/api/auth', authRoutes);Final Result: JWT-based authentication system complete, registration/login/token-refresh APIs working
Situation: A permission system that distinguishes administrators from regular users
User Request:
Create an API accessible only to administrators.
Regular users should receive a 403 error.Final Result:
// Admin-only API
router.delete('/users/:id',
authenticateToken, // verify authentication
requireRole('admin'), // verify role
async (req, res) => {
// user deletion logic
await db.user.delete({ where: { id: req.params.id } });
res.json({ message: 'User deleted' });
}
);
// Usage example
// Regular user (role: 'user') request → 403 Forbidden
// Admin (role: 'admin') request → 200 OKRecommendations for using this skill effectively.
Password Rotation Policy: Recommend periodic password changes
Multi-Factor Authentication (MFA): Apply 2FA to important accounts
Audit Logging: Log all authentication events
Common problems and their solutions.
Symptom:
Cause: The SECRET keys for Access Token and Refresh Token are different, but the same key is being used to verify both.
Solution:
ACCESS_TOKEN_SECRET, REFRESH_TOKEN_SECRETdotenv)Symptom: "CORS policy" error in the browser console
Cause: Missing CORS configuration on the Express server
Solution:
import cors from 'cors';
app.use(cors({
origin: process.env.FRONTEND_URL || 'http://localhost:3000',
credentials: true
}));Symptom: Users are frequently logged out
Cause: Refresh Token is not properly managed in the DB
Solution:
#authentication #authorization #JWT #OAuth #security #backend
c033769
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.