Skip to content
Development
Skill

/secure-auth

Implement authentication securely — authentication vs authorization, password hashing (argon2id/bcrypt), sessions vs JWT (storage, expiry, refresh, revocation), MFA, OAuth2/OIDC flows, and defenses against credential stuffing, session fixation, and CSRF. Worked examples + a

From plugin
vanara-agents-skills
917 skills54 agents
Install
$ npx -y skills add vanara-agents/skills --skill secure-auth --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/secure-auth

Context preview

The summary Claude sees to decide when to auto-load this skill.

Implement authentication securely — authentication vs authorization, password hashing (argon2id/bcrypt), sessions vs JWT (storage, expiry, refresh, revocation), MFA, OAuth2/OIDC flows, and defenses against credential stuffing, session fixation, and CSRF. Worked examples + a

SKILL.md

secure-auth.SKILL.md
name: secure-auth
description: Implement authentication securely — authentication vs authorization, password hashing (argon2id/bcrypt), sessions vs JWT (storage, expiry, refresh, revocation), MFA, OAuth2/OIDC flows, and defenses against credential stuffing, session fixation, and CSRF. Worked examples + a runnable password-policy check.
type: skill
version: 2.0.0
updated: 2026-06-29

Secure Authentication

Authentication is the front door to your system, and it is the single control attackers probe hardest. The goal of this skill is **not** to teach you to invent a clever scheme — it is to help you assemble well-understood primitives correctly, because almost every real-world breach in this area comes from a broken assembly of good parts, not from cracked cryptography. Heavy detail lives in `references/`; copy-paste material in `examples/`; a runnable policy check in `scripts/`.

Mental model

Three distinct questions get muddled constantly. Keep them separate:

| Question | Concern | Wrong answer looks like | |---|---|---| | Who are you? | **Authentication** (login, password, MFA) | trusting a client-supplied `user_id` | | What may you do? | **Authorization** (roles, ownership, scopes) | checking auth but not ownership (IDOR) | | How do we remember you? | **Session management** (cookies/tokens) | long-lived tokens you can't revoke |

A request can be perfectly *authenticated* and still be an attack if you skip *authorization*. The most common API vulnerability — Broken Object Level Authorization — is exactly this: a logged-in user reads `/accounts/124` when they only own `124`'s neighbor. Always check ownership server-side, never trust an identifier the client could change.

1. Password storage: slow hash, never plaintext

The non-negotiable rule: **never store a recoverable password.** Store a one-way hash produced by a *deliberately slow* algorithm so that a stolen database is expensive to crack offline.

import argon2 from 'argon2';

// Registration / password change — argon2id is the current default recommendation.
const hash = await argon2.hash(password, { type: argon2.argon2id });
// Store `hash` (it embeds the salt + cost params). NEVER store `password`.

// Login — constant-time verify; argon2 reads cost params from the stored hash.
const ok = await argon2.verify(hash, attempt);

Use **argon2id** (preferred) or **bcrypt** (battle-tested, fine if argon2 isn't available). Never use fast general-purpose hashes (`MD5`, `SHA-256`) — a GPU computes billions of those per second, so a leak becomes a mass account takeover within hours. Always salt (argon2/bcrypt do this for you), and validate the password against a policy and a breached-password list *before* hashing — run `scripts/check-password-policy.mjs --selftest` to see the kind of check that belongs at this boundary. The full parameter-tuning guidance is in [references/password-hashing.md](references/password-hashing.md).

2. Sessions vs JWT: how you remember a logged-in user

Two dominant models, with a real trade-off around **revocation**:

  • **Server-side sessions** — a random opaque session ID in an `HttpOnly; Secure; SameSite` cookie; state

lives server-side (DB/Redis). Revocation is trivial: delete the row. This is the safe default for classic web apps.

  • **Stateless JWTs** — a signed token the client carries. Scales without shared session storage, but you

**cannot un-issue a signed token** before it expires. Mitigate with short-lived access tokens (5–15 min) plus a revocable, rotating refresh token kept server-side.

Set-Cookie: session=9f2c...; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=3600

Storage matters enormously: a token in `localStorage` is readable by any XSS payload, so prefer `HttpOnly` cookies (which JavaScript cannot read) over web storage for anything that authenticates a request. The complete comparison — expiry, refresh rotation, reuse detection, and revocation strategies — is in [references/sessions-vs-jwt.md](references/sessions-vs-jwt.md).

3. MFA and step-up

A password alone is a single point of failure against phishing and credential stuffing. Offer a second factor and require it for sensitive actions (password change, payouts):

  • **TOTP** (authenticator app) — good baseline, phishable but cheap.
  • **WebAuthn / passkeys** — phishing-resistant, hardware-backed; prefer where you can.
  • **SMS** — weakest (SIM-swap), use only as a fallback.

Treat MFA as *step-up*: don't force it on every request, escalate it when risk rises.

4. OAuth2 / OIDC: delegated auth done right

When you offload login to a provider (Google, an identity platform), use **OAuth2 Authorization Code flow with PKCE** for web and mobile/SPA clients. Do not use the implicit flow (deprecated) and never the resource-owner password flow for third-party login. OIDC layers an identity `id_token` on top of OAuth2's access token. Validate the `id_token` signature, `iss`, `aud`, and `exp`, and use the `state` parameter to defend against CSRF on the callback. See [references/oauth2-oidc.md](references/oauth2-oidc.md) for the full flow diagrams and validation checklist, and `examples/auth-flow.md` for an annotated walk-through.

5. Account recovery

Recovery flows are a favorite bypass — they are authentication's back door. Make reset tokens **single-use, time-limited (e.g. 15–30 min), and high-entropy**, store only their hash, and invalidate all active sessions on a successful reset. Critically, return the **same response** whether or not the email exists, and keep timing uniform, so the endpoint can't be used to enumerate accounts.

Common pitfalls (failure modes)

  • **Fast/unsalted hashes** (`SHA-256`, `MD5`) — instantly crackable at scale after a DB leak.
  • **JWT you can't revoke** — a long-lived access token stays valid after logout/compromise; keep them short.
  • **Tokens in `localStorage`** — any XSS exfiltrates them; use `HttpOnly` cookies.
  • **Session fixation** — not rotatin
Read more
Ships withvanara-agents-skills

🐒 Free agents, skills & packs for Claude Code One subscription. An army of Claude Code agents. 30 production-grade agents, skills, and packs for Claude Code — free, Apache-2.0, install with one command.

Get the whole plugin

Other skills on vanara-agents-skills.