Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Authentication, authorization, and API security implementation. Use when building user systems, protecting APIs, or implementing access control. Covers OAuth 2.1/OIDC, JWT patterns, sessions, Passkeys/WebAuthn, RBAC/ABAC/ReBAC, policy engines (OPA, Casbin, SpiceDB), managed auth (Clerk, Auth0), self-hosted (Keycloak, Ory), and API security best practices.
.claude/skills/ancoleman-securing-authentication/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 47% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 91% | 0% |
| case-04 | ✗→✓ | ▲ Improved | 86% | 0% |
| case-05 | ✗→✓ | ▲ Improved | 109% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 96% | 0% |
Implement modern authentication, authorization, and API security across Python, Rust, Go, and TypeScript.
Use this skill when:
┌─────────────────────────────────────────────────────────────┐
│ OAuth 2.1 MANDATORY REQUIREMENTS │
│ (RFC 9798 - 2025) │
├─────────────────────────────────────────────────────────────┤
│ │
│ ✅ REQUIRED (Breaking Changes from OAuth 2.0) │
│ ├─ PKCE (Proof Key for Code Exchange) MANDATORY │
│ │ └─ S256 method (SHA-256), minimum entropy 43 chars │
│ ├─ Exact redirect URI matching │
│ │ └─ No wildcard matching, no substring matching │
│ ├─ Authorization code flow ONLY for public clients │
│ │ └─ All other flows require confidential client │
│ └─ TLS 1.2+ required for all endpoints │
│ │
│ ❌ REMOVED (No Longer Supported) │
│ ├─ Implicit grant (security vulnerabilities) │
│ ├─ Resource Owner Password Credentials grant │
│ │ └─ Use OAuth 2.0 Device Flow (RFC 8628) instead │
│ └─ Bearer token in query parameters │
│ └─ Must use Authorization header or POST body │
│ │
└─────────────────────────────────────────────────────────────┘Critical: PKCE is now mandatory for ALL OAuth flows, not just public clients.
NEVER allow alg: none or algorithm switching attacks.
Refresh token rotation: Each refresh generates new access AND refresh tokens, invalidating the old refresh token.
json{ "iss": "https://auth.example.com", "sub": "user-id-123", "aud": "api.example.com", "exp": 1234567890, "iat": 1234567890, "jti": "unique-token-id", "scope": "read:profile write:data" }
Algorithm: Argon2id
Memory cost (m): 64 MB (65536 KiB)
Time cost (t): 3 iterations
Parallelism (p): 4 threads
Salt length: 16 bytes (128 bits)
Target hash time: 150-250msFor concrete implementations, see references/password-hashing.md.
Key Points:
Passkeys provide phishing-resistant, passwordless authentication using FIDO2/WebAuthn.
For implementation guide, see references/passkeys-webauthn.md.
┌─────────────────────────────────────────────────────────────┐
│ Authorization Model Selection │
├─────────────────────────────────────────────────────────────┤
│ │
│ Simple Roles (<20 roles) │
│ └─ RBAC with Casbin (embedded, any language) │
│ Example: Admin, User, Guest │
│ │
│ Complex Attribute Rules │
│ └─ ABAC with OPA or Cerbos │
│ Example: "Allow if user.clearance >= doc.level │
│ AND user.dept == doc.dept" │
│ │
│ Relationship-Based (Multi-Tenant, Collaborative) │
│ └─ ReBAC with SpiceDB (Zanzibar model) │
│ Example: "Can edit if member of doc's workspace │
│ AND workspace.plan includes feature" │
│ Use cases: Notion-like, GitHub-like permissions │
│ │
│ Kubernetes / Infrastructure Policies │
│ └─ OPA (Gatekeeper for admission control) │
│ Example: Enforce pod security policies │
│ │
└─────────────────────────────────────────────────────────────┘For detailed comparison, see references/authorization-patterns.md.
| Use Case | Library | Context7 ID | Trust | Notes | |----------|---------|-------------|-------|-------| | Auth Framework | Auth.js v5 | /websites/authjs_dev | 87.4 | Multi-framework (Next, Svelte, Solid) | | JWT | jose 5.x | - | - | EdDSA, ES256, RS256 support | | Passkeys | @simplewebauthn/server 11.x | - | - | FIDO2 server | | Validation | Zod 3.x | /colinhacks/zod | 90.4 | Schema validation | | Policy Engine | Casbin.js 1.x | - | - | RBAC/ABAC embedded |
| Use Case | Library | Notes | |----------|---------|-------| | Auth Framework | Authlib 1.3+ | OAuth/OIDC client + server | | JWT | joserfc 1.x | Modern, maintained | | Passkeys | py_webauthn 2.x | WebAuthn server | | Password Hashing | argon2-cffi 24.x | OWASP parameters | | Validation | Pydantic 2.x | FastAPI integration | | Policy Engine | PyCasbin 1.x | RBAC/ABAC embedded |
| Use Case | Library | Notes | |----------|---------|-------| | JWT | jsonwebtoken 10.x | EdDSA, ES256, RS256 | | OAuth Client | oauth2 5.x | OAuth 2.1 flows | | Passkeys | webauthn-rs 0.5.x | WebAuthn + attestation | | Password Hashing | argon2 0.5.x | Native Argon2id | | Policy Engine | Casbin-RS 2.x | RBAC/ABAC embedded |
| Use Case | Library | Notes | |----------|---------|-------| | JWT | golang-jwt v5 | Community-maintained | | OAuth Client | go-oidc v3 | OIDC client only | | Passkeys | go-webauthn 0.11.x | Duo-maintained | | Password Hashing | golang.org/x/crypto/argon2 | Standard library | | Policy Engine | Casbin v2 | Original implementation |
| Service | Best For | Key Features | |---------|----------|--------------| | Clerk | Rapid development, startups | Prebuilt UI, Next.js SDK | | Auth0 | Enterprise, established | 25+ social providers, SSO | | WorkOS AuthKit | B2B SaaS, enterprise SSO | SAML/SCIM, admin portal | | Supabase Auth | Postgres users | Built on Postgres, RLS |
For detailed comparison, see references/managed-auth-comparison.md.
| Solution | Language | Use Case | |----------|----------|----------| | Keycloak | Java | Enterprise, on-prem | | Ory | Go | Cloud-native, microservices | | Authentik | Python | Modern, developer-friendly |
For setup guides, see references/self-hosted-auth.md.
typescript// Tiered rate limiting (per IP + per user) const rateLimits = { anonymous: '10 requests/minute', authenticated: '100 requests/minute', premium: '1000 requests/minute', }
Use sliding window algorithm (not fixed window) with Redis.
typescript// Restrictive CORS (production) const corsOptions = { origin: ['https://app.example.com'], credentials: true, maxAge: 86400, // 24 hours allowedHeaders: ['Content-Type', 'Authorization'], methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], } // NEVER use origin: '*' with credentials: true
typescriptconst securityHeaders = { 'Strict-Transport-Security': 'max-age=63072000; includeSubDomains; preload', 'X-Frame-Options': 'DENY', 'X-Content-Type-Options': 'nosniff', 'Referrer-Policy': 'strict-origin-when-cross-origin', 'Permissions-Policy': 'geolocation=(), microphone=(), camera=()', 'Content-Security-Policy': "default-src 'self'; script-src 'self'", }
For complete API security guide, see references/api-security.md.
typescript// middleware.ts import { withAuth } from 'next-auth/middleware' export default withAuth({ callbacks: { authorized: ({ token, req }) => { if (req.nextUrl.pathname.startsWith('/dashboard')) { return !!token } if (req.nextUrl.pathname.startsWith('/admin')) { return token?.role === 'admin' } return true }, }, }) export const config = { matcher: ['/dashboard/:path*', '/admin/:path*'], }
typescriptimport { useSession } from 'next-auth/react' export function AdminPanel() { const { data: session } = useSession() if (session?.user?.role !== 'admin') { return null } return <div>Admin Controls</div> }
See references/oauth21-guide.md for complete implementation.
scripts/generate_jwt_keys.pySee references/jwt-best-practices.md for detailed patterns.
See examples/passkeys-demo/ for runnable implementation.
See references/authorization-patterns.md for detailed comparison.
bashpython scripts/generate_jwt_keys.py --algorithm EdDSA
Generates EdDSA or ES256 key pairs for JWT signing.
bashpython scripts/validate_oauth_config.py --config oauth.json
Validates OAuth 2.1 compliance (PKCE enabled, exact redirect URIs, etc.).
Complete implementation with OAuth providers, credentials, and session management.
Location: examples/authjs-nextjs/
Self-hosted Keycloak with FastAPI integration via OIDC.
Location: examples/keycloak-fastapi/
Runnable passkeys implementation with @simplewebauthn.
Location: examples/passkeys-demo/
references/oauth21-guide.md - OAuth 2.1 implementation guidereferences/jwt-best-practices.md - JWT generation, validation, storagereferences/passkeys-webauthn.md - Passkeys/WebAuthn implementationreferences/authorization-patterns.md - RBAC, ABAC, ReBAC comparisonreferences/password-hashing.md - Argon2id parameters, migration| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 25,035 | 31,102 | +24% | 1 | 1 | 0% | 5,124 | 7,522 | +47% | 0 | 0 | — |
case-02 | fail→pass | 25,038 | 26,244 | +5% | 1 | 1 | 0% | 4,197 | 8,027 | +91% | 0 | 0 | — |
case-03 | pass→pass | 25,642 | 12,329 | -52% | 1 | 1 | 0% | 3,011 | 5,668 | +88% | 0 | 0 | — |
case-04 | fail→pass | 15,597 | 10,464 | -33% | 1 | 1 | 0% | 2,881 | 5,360 | +86% | 0 | 0 | — |
case-05 | fail→pass | 14,012 | 10,258 | -27% | 1 | 1 | 0% | 2,609 | 5,444 | +109% | 0 | 0 | — |
case-06 | pass→pass | 18,847 | 23,181 | +23% | 1 | 1 | 0% | 2,924 | 5,752 | +97% | 0 | 0 | — |
case-07 | pass→pass | 12,906 | 8,769 | -32% | 1 | 1 | 0% | 1,996 | 4,956 | +148% | 0 | 0 | — |
case-08 | fail→pass | 18,192 | 14,238 | -22% | 1 | 1 | 0% | 3,089 | 6,061 | +96% | 0 | 0 | — |
case-09 | pass→pass | 26,905 | 9,518 | -65% | 1 | 1 | 0% | 2,664 | 5,172 | +94% | 0 | 0 | — |
case-10 | pass→pass | 14,308 | 15,903 | +11% | 1 | 1 | 0% | 2,396 | 6,682 | +179% | 0 | 0 | — |
case-11 | pass→pass | 13,660 | 12,291 | -10% | 1 | 1 | 0% | 2,343 | 5,920 | +153% | 0 | 0 | — |
case-12 | fail→fail | 16,390 | 35,777 | +118% | 1 | 1 | 0% | 2,633 | 6,197 | +135% | 0 | 0 | — |
case-13 | pass→pass | 11,393 | 10,771 | -5% | 1 | 1 | 0% | 2,299 | 5,406 | +135% | 0 | 0 | — |
case-14 | fail→pass | 11,126 | 9,727 | -13% | 1 | 1 | 0% | 2,009 | 5,315 | +165% | 0 | 0 | — |
case-15 | fail→pass | 9,160 | 2,610 | -72% | 1 | 1 | 0% | 1,825 | 3,809 | +109% | 0 | 0 | — |
case-16 | fail→pass | 6,348 | 2,402 | -62% | 1 | 1 | 0% | 1,081 | 3,871 | +258% | 0 | 0 | — |
case-17 | pass→pass | 17,226 | 8,293 | -52% | 1 | 1 | 0% | 2,723 | 4,901 | +80% | 0 | 0 | — |
case-18 | fail→fail | 13,323 | 8,733 | -34% | 1 | 1 | 0% | 2,606 | 5,358 | +106% | 0 | 0 | — |
case-19 | pass→pass | 13,811 | 11,308 | -18% | 1 | 1 | 0% | 2,171 | 5,324 | +145% | 0 | 0 | — |
case-20 | fail→pass | 5,133 | 4,143 | -19% | 1 | 1 | 0% | 956 | 4,264 | +346% | 0 | 0 | — |
case-21 | pass→pass | 4,911 | 3,856 | -21% | 1 | 1 | 0% | 751 | 4,110 | +447% | 0 | 0 | — |
case-22 | pass→pass | 6,879 | 6,310 | -8% | 1 | 1 | 0% | 1,183 | 4,400 | +272% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +41 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.