Authentication mit Claude Code: JWT, OAuth, Sessions 2026
Authentication falsch implementieren hat fatale Konsequenzen: Session Hijacking, Token-Leaks, Brute-Force-Angriffe. Claude Code kennt die Sicherheits-Best-Practices und implementiert sie korrekt — nicht wie Stack-Overflow-Snippets die 5 Jahre alt sind.
Warum Authentication für KI besonders geeignet ist
Authentication hat etablierte Patterns (OWASP, RFC 6749, NIST SP 800-63). Claude Code kennt sie alle — und warnt aktiv wenn du etwas Unsicheres implementieren willst. Das ist wertvoller als ein Kollege der einfach was zusammenhackt.
Claude Code warnt proaktiv wenn du es bittest unsichere Patterns zu implementieren: MD5 für Passwörter, JWT ohne Expiry, HTTP-Cookies ohne Secure-Flag. Das ist Feature, kein Bug.
JWT Authentication vollständig implementieren
JWT mit Refresh-Token Rotation
# Prompt für komplettes JWT-System:
# "Implementiere JWT-Auth mit:
# - Access Token (15 Min TTL), Refresh Token (7 Tage)
# - Refresh Token Rotation (alter Token wird invalidiert)
# - Token-Blacklist in Redis (für Logout)
# - bcrypt für Passwörter (cost factor 12)"
const jwt = require('jsonwebtoken');
const bcrypt = require('bcrypt');
const crypto = require('crypto');
const redis = require('ioredis');
const BCRYPT_COST = 12; // Nicht weniger!
const ACCESS_TTL = 15 * 60; // 15 Minuten
const REFRESH_TTL = 7 * 24 * 3600; // 7 Tage
class AuthService {
async register(email, password) {
// NIEMALS Plaintext in DB
const passwordHash = await bcrypt.hash(password, BCRYPT_COST);
return await db.users.create({ email, passwordHash });
}
async login(email, password) {
const user = await db.users.findByEmail(email);
// Timing-Attack-sicher: immer vergleichen, auch wenn user nicht existiert
const dummyHash = '$2b$12$invalid.hash.for.timing.attack.prevention';
const valid = await bcrypt.compare(password, user?.passwordHash ?? dummyHash);
if (!user || !valid) throw new Error('Invalid credentials');
return await this.generateTokenPair(user.id);
}
async generateTokenPair(userId) {
const accessToken = jwt.sign(
{ sub: userId },
process.env.JWT_ACCESS_SECRET,
{ expiresIn: ACCESS_TTL }
);
// Refresh Token: zufälliger String (kein JWT — nicht signierbar ohne Lookup)
const refreshToken = crypto.randomBytes(64).toString('hex');
const refreshHash = await bcrypt.hash(refreshToken, 10);
await db.refreshTokens.create({
userId, hash: refreshHash,
expiresAt: new Date(Date.now() + REFRESH_TTL * 1000)
});
return { accessToken, refreshToken };
}
async refresh(oldRefreshToken) {
const tokens = await db.refreshTokens.findValid();
// Token Rotation: altes Token suchen und löschen
for (const stored of tokens) {
if (await bcrypt.compare(oldRefreshToken, stored.hash)) {
await db.refreshTokens.delete(stored.id);
return await this.generateTokenPair(stored.userId);
}
}
throw new Error('Invalid refresh token');
}
async logout(accessToken) {
// Access Token blacklisten bis er abläuft
const decoded = jwt.decode(accessToken);
const ttl = decoded.exp - Math.floor(Date.now() / 1000);
if (ttl > 0) await redis.setex(`blacklist:${accessToken}`, ttl, '1');
}
}
OAuth 2.0 mit Claude Code
Google OAuth Integration
# Prompt:
# "Implementiere Google OAuth 2.0 Login mit Passport.js:
# - Google Strategy, User anlegen falls nicht existiert
# - State-Parameter gegen CSRF
# - Nach OAuth: JWT ausgeben (kein Session-Cookie)"
const passport = require('passport');
const { Strategy: GoogleStrategy } = require('passport-google-oauth20');
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: `${process.env.APP_URL}/auth/google/callback`,
scope: ['email', 'profile']
}, async (accessToken, refreshToken, profile, done) => {
try {
let user = await db.users.findByGoogleId(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
});
}
done(null, user);
} catch (err) { done(err); }
}));
// Routes
app.get('/auth/google',
passport.authenticate('google', { state: crypto.randomBytes(16).toString('hex') })
);
app.get('/auth/google/callback',
passport.authenticate('google', { session: false, failureRedirect: '/login' }),
async (req, res) => {
// JWT ausgeben, kein Cookie
const { accessToken } = await authService.generateTokenPair(req.user.id);
res.redirect(`${process.env.FRONTEND_URL}/auth/callback?token=${accessToken}`);
}
);
Security Checklist für Authentication
- ✓Passwörter: bcrypt mit cost factor ≥12 oder Argon2id. Niemals MD5/SHA1/SHA256 ohne Salt.
- ✓JWT Secrets: Mindestens 256 Bit Entropie. Separate Secrets für Access und Refresh Token.
- ✓Token Storage: AccessToken in Memory (nicht localStorage!), RefreshToken in httpOnly Cookie.
- ✓Timing Attacks: Passwort-Vergleich immer mit bcrypt.compare (constant-time), nie String-Vergleich.
- ✓Rate Limiting: Login-Endpoint: max 5 Versuche/IP/15 Min. Account Lockout nach 10 Fehlversuchen.
- ✗Niemals: Passwörter loggen, in URLs übergeben oder in GET-Parametern senden.
- ✗Niemals: "Remember Me" als unsignierter Cookie mit User-ID.
Claude Code Security-Prompt: Wenn du Auth implementierst, füge immer hinzu: "Prüfe die Implementierung auf OWASP Authentication Cheat Sheet Compliance. Liste Sicherheitsprobleme explizit auf."
Session-Management Alternative
# Wann Sessions statt JWT:
# - Server-Side Rendering (keine SPA)
# - Einfacheres Logout (Session einfach löschen)
# - Weniger Client-Komplexität
const session = require('express-session');
const RedisStore = require('connect-redis');
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 in Prod!
httpOnly: true, // Kein JavaScript-Zugriff
sameSite: 'strict', // CSRF-Schutz
maxAge: 7 * 24 * 60 * 60 * 1000 // 7 Tage
}
}));
Authentication-Modul im Kurs
Im Claude Code Mastery Kurs gibt es ein vollständiges Authentication-Modul: JWT + Refresh-Token-Rotation, OAuth 2.0 (Google, GitHub), Session-Management, 2FA-Implementierung — mit OWASP-geprüftem Code.
14 Tage kostenlos testen →