Comprehensive authentication implementation guidance including JWT best practices, OAuth 2.0/OIDC flows, Passkeys/FIDO2/WebAuthn, MFA patterns, and secure session management. Use when implementing login systems, token-based auth, SSO, passwordless authentication, or reviewing authentication security.
Provides comprehensive guidance for implementing secure authentication systems, including JWT best practices, OAuth 2.0/OIDC flows, Passkeys/FIDO2, MFA, and session management. Use when building login systems, token-based auth, SSO, or reviewing authentication security.
/plugin marketplace add melodic-software/claude-code-plugins/plugin install security@melodic-softwareThis skill is limited to using the following tools:
references/jwt-security.mdreferences/oauth-flows.mdreferences/passkeys-implementation.mdComprehensive guidance for implementing secure authentication systems, covering JWT, OAuth 2.0, OIDC, Passkeys, MFA, and session management.
Use this skill when:
| Method | Best For | Security Level | UX |
|---|---|---|---|
| Passkeys/WebAuthn | Primary auth, passwordless | ★★★★★ | Excellent |
| OAuth 2.0 + PKCE | Third-party login, SPAs | ★★★★☆ | Good |
| JWT + Refresh Tokens | APIs, microservices | ★★★★☆ | Good |
| Session Cookies | Traditional web apps | ★★★☆☆ | Excellent |
| Password + MFA | Legacy systems upgrade | ★★★★☆ | Moderate |
Recommendation: Prefer Passkeys for new applications. Use OAuth 2.0 + PKCE for SPAs. Always add MFA as a second factor.
| Algorithm | Use Case | Recommendation |
|---|---|---|
| RS256 | Public key verification, distributed systems | ✅ Recommended |
| ES256 | Smaller tokens, ECDSA-based | ✅ Recommended |
| HS256 | Simple systems, same-party verification | ⚠️ Use carefully |
| None | Never use | ❌ Prohibited |
// Header
{
"alg": "RS256",
"typ": "JWT",
"kid": "key-id-for-rotation" // Key ID for key rotation
}
// Payload (Claims)
{
"iss": "https://auth.example.com", // Issuer
"sub": "user-123", // Subject (user ID)
"aud": "https://api.example.com", // Audience
"exp": 1735300000, // Expiration (short-lived)
"iat": 1735296400, // Issued at
"jti": "unique-token-id", // JWT ID (for revocation)
"scope": "read write" // Permissions
}
| Token Type | Recommended Lifetime | Storage |
|---|---|---|
| Access Token | 5-15 minutes | Memory only |
| Refresh Token | 7-30 days | Secure HttpOnly cookie or encrypted storage |
| ID Token | Match access token | Memory only |
For detailed JWT security: See JWT Security Reference
| Flow | Use Case | PKCE Required |
|---|---|---|
| Authorization Code + PKCE | SPAs, mobile apps, web apps | ✅ Yes |
| Client Credentials | Service-to-service | N/A |
| Device Authorization | Smart TVs, CLI tools | N/A |
| Deprecated - don't use | N/A | |
| Deprecated - don't use | N/A |
┌──────────┐ ┌───────────────┐
│ Client │ │ Auth Server │
└────┬─────┘ └───────┬───────┘
│ │
│ 1. Generate code_verifier (random) │
│ code_challenge = SHA256(code_verifier) │
│ │
│ 2. Authorization Request ─────────────────>│
│ (response_type=code, code_challenge) │
│ │
│ 3. User authenticates & consents │
│ │
│ 4. <────────── Authorization Code ─────────│
│ │
│ 5. Token Request ─────────────────────────>│
│ (code, code_verifier) │
│ │
│ 6. <────────── Access + Refresh Tokens ────│
└────────────────────────────────────────────┘
For detailed OAuth flows: See OAuth Flows Reference
Passkeys provide phishing-resistant, passwordless authentication using public key cryptography.
// 1. Get challenge from server
const options = await fetch('/api/webauthn/register/options').then(r => r.json());
// 2. Create credential
const credential = await navigator.credentials.create({
publicKey: {
challenge: base64ToBuffer(options.challenge),
rp: { name: "Example App", id: "example.com" },
user: {
id: base64ToBuffer(options.userId),
name: options.username,
displayName: options.displayName
},
pubKeyCredParams: [
{ type: "public-key", alg: -7 }, // ES256
{ type: "public-key", alg: -257 } // RS256
],
authenticatorSelection: {
authenticatorAttachment: "platform", // or "cross-platform"
residentKey: "required", // Discoverable credential
userVerification: "required" // Biometric/PIN required
},
timeout: 60000
}
});
// 3. Send credential to server for storage
await fetch('/api/webauthn/register/verify', {
method: 'POST',
body: JSON.stringify({
id: credential.id,
rawId: bufferToBase64(credential.rawId),
response: {
clientDataJSON: bufferToBase64(credential.response.clientDataJSON),
attestationObject: bufferToBase64(credential.response.attestationObject)
}
})
});
For complete Passkeys implementation: See Passkeys Implementation Guide
| Method | Phishing Resistant | Security | UX |
|---|---|---|---|
| Passkeys/Security Keys | ✅ Yes | ★★★★★ | Good |
| Authenticator App (TOTP) | ❌ No | ★★★★☆ | Good |
| Push Notification | ⚠️ Partial | ★★★★☆ | Excellent |
| SMS OTP | ❌ No | ★★☆☆☆ | Moderate |
| Email OTP | ❌ No | ★★☆☆☆ | Moderate |
using System.Security.Cryptography;
using OtpNet; // Install: Otp.NET package
/// <summary>
/// TOTP (Time-based One-Time Password) service for MFA.
/// </summary>
public sealed class TotpService
{
private const int SecretLength = 20; // 160 bits
/// <summary>
/// Generate a new TOTP secret for user enrollment.
/// </summary>
public static string GenerateSecret()
{
var secretBytes = RandomNumberGenerator.GetBytes(SecretLength);
return Base32Encoding.ToString(secretBytes);
}
/// <summary>
/// Generate provisioning URI for authenticator apps (Google Authenticator, etc.)
/// </summary>
public static string GetProvisioningUri(string secret, string email, string issuer)
{
return $"otpauth://totp/{Uri.EscapeDataString(issuer)}:{Uri.EscapeDataString(email)}" +
$"?secret={secret}&issuer={Uri.EscapeDataString(issuer)}&algorithm=SHA1&digits=6&period=30";
}
/// <summary>
/// Verify TOTP code during login. Allows 1-step time drift.
/// </summary>
public static bool VerifyTotp(string secret, string otp)
{
var secretBytes = Base32Encoding.ToBytes(secret);
var totp = new Totp(secretBytes, step: 30, totpSize: 6);
// VerificationWindow allows for clock drift (1 step = 30 seconds each direction)
return totp.VerifyTotp(otp, out _, VerificationWindow.RfcSpecifiedNetworkDelay);
}
}
// ASP.NET Core cookie configuration
app.UseCookiePolicy(new CookiePolicyOptions
{
HttpOnly = HttpOnlyPolicy.Always, // Prevent JavaScript access (XSS protection)
Secure = CookieSecurePolicy.Always, // HTTPS only
MinimumSameSitePolicy = SameSiteMode.Lax // CSRF protection (or Strict for more security)
});
// Per-cookie configuration
Response.Cookies.Append("session_id", sessionId, new CookieOptions
{
HttpOnly = true, // Prevent JavaScript access
Secure = true, // HTTPS only
SameSite = SameSiteMode.Lax, // CSRF protection
MaxAge = TimeSpan.FromHours(1),
Domain = ".example.com",
Path = "/",
IsEssential = true // Required for GDPR essential cookies
});
using System.Security.Cryptography;
using Konscious.Security.Cryptography; // Install: Konscious.Security.Cryptography.Argon2
/// <summary>
/// Argon2id password hashing service (recommended by OWASP).
/// </summary>
public sealed class PasswordHasher
{
private const int SaltSize = 16;
private const int HashSize = 32;
private const int Iterations = 3; // time_cost
private const int MemorySize = 65536; // 64 MB
private const int Parallelism = 4; // threads
/// <summary>
/// Hash a password using Argon2id.
/// </summary>
public static string HashPassword(string password)
{
var salt = RandomNumberGenerator.GetBytes(SaltSize);
using var argon2 = new Argon2id(System.Text.Encoding.UTF8.GetBytes(password))
{
Salt = salt,
DegreeOfParallelism = Parallelism,
MemorySize = MemorySize,
Iterations = Iterations
};
var hash = argon2.GetBytes(HashSize);
// Combine salt + hash for storage
var combined = new byte[SaltSize + HashSize];
Buffer.BlockCopy(salt, 0, combined, 0, SaltSize);
Buffer.BlockCopy(hash, 0, combined, SaltSize, HashSize);
return Convert.ToBase64String(combined);
}
/// <summary>
/// Verify a password against stored hash.
/// </summary>
public static bool VerifyPassword(string password, string storedHash)
{
var combined = Convert.FromBase64String(storedHash);
if (combined.Length != SaltSize + HashSize) return false;
var salt = combined[..SaltSize];
var expectedHash = combined[SaltSize..];
using var argon2 = new Argon2id(System.Text.Encoding.UTF8.GetBytes(password))
{
Salt = salt,
DegreeOfParallelism = Parallelism,
MemorySize = MemorySize,
Iterations = Iterations
};
var actualHash = argon2.GetBytes(HashSize);
// Timing-safe comparison
return CryptographicOperations.FixedTimeEquals(actualHash, expectedHash);
}
}
| Requirement | Recommendation |
|---|---|
| Minimum length | 12+ characters |
| Maximum length | 128+ characters (prevent DoS) |
| Complexity | No arbitrary rules (allow all characters) |
| Breach check | Check against known breached passwords |
| Rate limiting | 5 attempts, then exponential backoff |
| Account lockout | Temporary lockout (15-30 min) after failures |
What authentication are you implementing?
| Skill | Relationship |
|---|---|
authorization-models | After authentication, apply authorization (RBAC, ABAC) |
cryptography | Underlying crypto for tokens and passwords |
api-security | Securing API endpoints with authentication |
secure-coding | General security patterns |
Last Updated: 2025-12-26
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.