Skip to main content

create-auth

Scaffold signin and signup authentication endpoints for a project. Use when the user wants to add authentication, create login/register flows, or set up auth from scratch.

来源信息

仓库
himself65/auth-spec
最近来源活动
2026年10月9日 05:23
检测到的 SKILL.md 语言
英语
星标
41
分支
3

安装方式

默认使用会先检查来源的 Prompt;你也可以切换为直接命令,或下载本地副本。

检查来源文件

决定是否安装前,请先阅读 SKILL.md,以及 SkillsMP 当前展示的配套文件。

文件资源管理器
40 个文件

正在显示 SKILL.md

SKILL.md
来源说明 · 只读预览
name
create-auth
description
Scaffold signin and signup authentication endpoints for a project. Use when the user wants to add authentication, create login/register flows, or set up auth from scratch.
# Create Auth You are scaffolding authentication (signin + signup) for the user's project. ## Step 1: Detect Existing Project Context Before asking any questions, scan the user's project to detect their stack: 1. Look for framework config files (e.g., `next.config.*`, `package.json`, `go.mod`, `Cargo.toml`, `pyproject.toml`, `build.gradle*`, `pom.xml`) 2. Look for existing database/ORM setup (e.g., `prisma/schema.prisma`, `drizzle.config.*`, `alembic/`, `diesel.toml`, `ormconfig.*`) 3. Look for existing auth code or dependencies Use what you find to pre-select the best options in the questions below. If the project clearly uses a specific stack, set that as the recommended option. ## Step 2: Gather Context with Interactive Questions Use the `AskUserQuestion` tool to ask the user to make selections. Ask up to 3 questions in a **single** `AskUserQuestion` call so the user can answer everything at once. ### Question 1: Language/Framework Ask "Which language and framework are you using?" with header "Framework". Pick the top 4 most relevant options based on what you detected in the project. If you detected the framework, put it first and mark it "(Recommended)". If you could not detect it, use these defaults: - **Next.js** — "TypeScript, App Router, API routes" - **Express** — "TypeScript/JavaScript, minimal and flexible" - **FastAPI** — "Python, async-first with type hints" - **Go + Chi** — "Go, lightweight and idiomatic" The user can always pick "Other" to specify a different stack. ### Question 2: Database/ORM Ask "Which database and ORM/query layer?" with header "Database". Again, pick the top 4 most relevant options based on the project. If detected, mark it "(Recommended)". Defaults: - **PostgreSQL + Prisma** — "Type-safe ORM with migrations (JS/TS)" - **PostgreSQL + Drizzle** — "Lightweight TypeScript ORM, SQL-like syntax" - **PostgreSQL + SQLAlchemy** — "Full-featured Python ORM" - **SQLite + raw queries** — "Simple, no server needed, good for prototyping" ### Question 3: Session Strategy Ask "How should sessions be managed?" with header "Sessions". - **Database sessions (Recommended)** — "Server-side sessions stored in your database. More secure — sessions can be revoked instantly" - **JWT tokens** — "Stateless tokens signed by the server. Simpler to scale, but harder to revoke" ## Step 3: Ask Which Features to Add After the user answers the stack questions, use `AskUserQuestion` again to ask which additional auth features they want. Use **multiSelect: true** so they can pick multiple features at once. ### Question 1: Authentication Methods Ask "Which authentication methods do you want to add?" with header "Auth methods". Set multiSelect to true. - **Email OTP** — "Passwordless sign-in via one-time codes sent to email" - **Magic Link** — "Passwordless sign-in via emailed links" - **Phone Number** — "SMS-based OTP authentication" - **Passkey** — "WebAuthn/FIDO2 passwordless authentication" ### Question 2: Security Features Ask "Which security features do you want?" with header "Security". Set multiSelect to true. - **Two-Factor Auth (Recommended)** — "TOTP-based second factor with backup codes" - **Captcha** — "Bot protection on sign-up and sign-in (reCAPTCHA, hCaptcha, Turnstile)" - **Password Breach Check** — "Check passwords against the Have I Been Pwned database" - **Rate Limiting** — "Throttle auth endpoints to prevent brute-force attacks (includes KV cache)" ### Question 3: Additional Capabilities Ask "Any additional capabilities?" with header "Extras". Set multiSelect to true. - **Multi-Session** — "Allow multiple concurrent sessions per user" - **Username Auth** — "Sign in with username instead of (or in addition to) email" - **Organization / Teams** — "Multi-tenant support with roles, invitations, and RBAC" - **API Keys** — "Generate API keys for programmatic access" - **MCP Server** — "OAuth 2.1 + discovery endpoints so Model Context Protocol clients (Claude Desktop, mcp-inspector, Cursor) can authenticate. If selected, ask a follow-up: Resource Server only (delegate to an existing IdP) vs Self-hosted Authorization Server (issue your own tokens). See `references/features/mcp-server.md` for the two modes." ## Step 4: Wait for All Answers **Do not write any code until the user has answered all questions.** Once you have their selections, proceed to Step 5. ## Step 5: Generate Auth Generate the core auth (schema + endpoints below) **plus** any selected features. For each selected feature, read the matching reference file from `references/features/` to get the schema additions, endpoint specs, and implementation details. **Dependencies:** - If the user selects **Rate Limiting**, also read `references/features/kv-cache.md` and generate the KV cache module first — rate limiting depends on it. The KV cache is a general-purpose utility that other features can also use, so generate it as a standalone module. - If the user selects **MCP Server** in Mode B (Self-hosted Authorization Server), strongly recommend turning on **Rate Limiting** as well — the public `/oauth/register`, `/oauth/authorize`, and `/oauth/token` endpoints need it. Confirm with the user before generating; if they decline, leave a TODO comment at each endpoint pointing at the rate-limiting feature. | Feature | Reference file | | ------------------ | ---------------------------------------- | | Email OTP | `references/features/email-otp.md` | | Magic Link | `references/features/magic-link.md` | | Phone Number | `references/features/phone-number.md` | | Passkey | `references/features/passkey.md` | | Two-Factor Auth | `references/features/two-factor.md` | | Captcha | `references/features/captcha.md` | | Password Breach | `references/features/password-breach.md` | | Rate Limiting | `references/features/rate-limiting.md` | | KV Cache | `references/features/kv-cache.md` | | Multi-Session | `references/features/multi-session.md` | | Username Auth | `references/features/username.md` | | Organization/Teams | `references/features/organization.md` | | API Keys | `references/features/api-key.md` | | MCP Server | `references/features/mcp-server.md` | ### Core Schema and Endpoints Generate the following core auth using the schema and endpoint specs below. **Adapt everything to the user's language/framework idioms:** - Naming: `email_verified` (snake_case) in Python/Go/Rust, `emailVerified` (camelCase) in JS/TS, `EmailVerified` (PascalCase) in C# - Types: use the language's native types (e.g. `std::string` in C++, `String` in Rust/Java, `string` in Go/TS) - IDs: use idiomatic generation — `uuid.New()` (Go), `Uuid::new_v4()` (Rust), `crypto.randomUUID()` (JS), `uuid4()` (Python), `boost::uuids::random_generator()` (C++), etc. - Password hashing: use the idiomatic library — `bcrypt` (Go/JS/Python), `argon2` (Rust), `libsodium` (C/C++), etc. - Error handling: use the language's conventions (Result types in Rust, error returns in Go, exceptions in Python/Java, etc.) - File structure: follow the project's existing layout and conventions ### Schema Create these tables/models: **User** | Field | Type | Constraints | |----------------|----------|----------------------| | id | string | primary key | | email | string | unique, not null (store the canonical form — see sign-up) | | name | string | nullable | | image | string | nullable | | emailVerified | boolean | default false | | createdAt | datetime | default now | | updatedAt | datetime | auto-update | **Session** | Field | Type | Constraints | |-----------|----------|--------------------------| | id | string | primary key | | userId | string | foreign key -> User, not null | | token | string | unique, not null | | expiresAt | datetime | not null | | ipAddress | string | nullable | | userAgent | string | nullable | | createdAt | datetime | default now | `ipAddress` and `userAgent` power the "signed-in devices" list (see the Multi-Session feature) and security-notification emails. **Account** | Field | Type | Constraints | |--------------|----------|--------------------------| | id | string | primary key | | userId | string | foreign key -> User, not null | | providerId | string | not null (e.g. "credential") | | accountId | string | not null (provider-side user id; = userId for "credential") | | passwordHash | string | nullable | | createdAt | datetime | default now | | updatedAt | datetime | auto-update | Add a unique constraint on `(providerId, accountId)`. Account lookups must always filter by that full tuple — never by `accountId` alone — so that OAuth providers added later cannot collide across ID spaces (see `references/pitfalls/oauth-account-linking.md`). **VerificationToken** | Field | Type | Constraints | |------------|----------|--------------------------| | id | string | primary key | | userId | string | foreign key -> User, not null | | purpose | string | not null (`"verify-email"` or `"password-reset"`) | | email | string | not null (the address the token was issued for, lowercased) | | tokenHash | string | unique, not null (SHA-256 of the raw token) | | expiresAt | datetime | not null | | consumedAt | datetime | nullable (set atomically on use) | | createdAt | datetime | default now | One table serves both flows; `purpose` keeps them apart and MUST be matched at redemption, or a reset link is redeemable as an email confirmation. Store only the hash — the raw token exists solely inside the emailed link. `email` records what the token proves, so a later address change cannot inherit the proof. ### Endpoints **POST /api/auth/sign-up** - Body: `{ email, password, name? }` - Canonicalize the email **before** validating it (NFKC where the stdlib has it, then trim, then lowercase), then validate the canonical string and store exactly that string — see `references/pitfalls/email-case-normalization.md` - Validate the canonical string against a **strict shape**, not a permissive one: a lowercase RFC 5322 dot-atom local part, dot-separated `[a-z0-9-]` domain labels, exactly one `@`, ≤ 254 chars — no quotes, comments, angle brackets, commas, spaces, or non-ASCII (internationalized addresses only if the project deliberately supports them). Anything a mail library could re-parse into a *different* recipient — `a(b)@x`, `"a"@x`, `x<attacker@evil>`, `a,b@x` — is rejected rather than stored. Then validate password length (min 8 chars) - Hash password with a strong algorithm (bcrypt, argon2, or scrypt — use whichever is idiomatic for the language) - Create User + Account (providerId: "credential", accountId: the new user's id) + Session - Record `ipAddress` and `userAgent` on the session (`User-Agent` header; client IP from the trusted proxy header when deployed behind one, otherwise the socket address) - **Only when the insert actually created a user**, issue a `"verify-email"` token and send the confirmation link (see `POST /api/auth/verify-email/send`) — nothing else in a password-only build ever sets `emailVerified`, and an account that never proves an identifier is reaped. The duplicate-email path below creates no user, so it sends nothing and leaks nothing - Return session token and user (without password) - **Email enumeration protection:** If the email already exists, return the same `200 OK` status and same response shape as a successful sign-up — do not return 409 or any error that reveals the email is taken. The response should be indistinguishable from a real sign-up. Implementation: attempt the insert, catch the unique constraint violation, hash the password anyway (to keep timing consistent), and return a fake success with a dummy user ID and token (that won't actually work as a session). This prevents attackers from discovering which emails are registered via the sign-up endpoint. **POST /api/auth/sign-in** - Body: `{ email, password }` - Canonicalize the email through the same helper sign-up uses (NFKC, trim, lowercase) before lookup - Look up user by email, verify password hash - Create new Session (record `ipAddress` and `userAgent` as in sign-up) - Return session token and user (without password) - Return 401 on invalid credentials (generic message, no user enumeration) **GET /api/auth/session** - Read session token from Authorization header (Bearer) or cookie - Look up session, verify not expired - Return user info if valid, 401 if not - Set `Cache-Control: no-store` once at the top of the handler — not at each `return`, and on the 401 as well as the 200. Otherwise the browser disk-caches this GET and keeps replaying "signed in" with the cached profile after the session has expired server-side. **POST /api/auth/sign-out** - Read session token - Delete session from database - Return 200 **POST /api/auth/verify-email/send** - Body: `{ email }` (canonicalize through the sign-up helper before lookup). Sign-up calls this internally on success; the route itself exists for resends - Delete the user's outstanding `"verify-email"` tokens, then issue one: ≥32 bytes crypto-random, store only its SHA-256, `expiresAt` ≤ 24 h - Email the link, built on a **configured** public base URL — never on the request's `Host` / `X-Forwarded-Host`, which the caller controls (reset-link poisoning; see `references/pitfalls/oauth-redirect-request-url.md`). Return 200 **always**, whether or not the address has an account — this endpoint must not reveal which addresses are registered - Rate limit per address and per IP (3 per hour is reasonable) — it sends mail on demand **POST /api/auth/verify-email/confirm** - Body: `{ token }` - Hash the presented token, look up by `tokenHash`, and require `purpose = "verify-email"`, unexpired and unconsumed - **Consume atomically** — one conditional write gated on `consumedAt IS NULL`, affected-rows checked (see `references/pitfalls/single-use-token-race.md`) - Flip `emailVerified` with a conditional write naming the token's `email`: `UPDATE users SET email_verified = true WHERE id = $1 AND email = $2`. Bind the address, and keep the flag itself **out** of this guard — this write records a proof and authorizes nothing destructive (see `references/pitfalls/async-proof-value-binding.md`). Zero rows means the address changed after the link was issued: discard the proof - **Exempt from the credential strip.** This link was issued by the very sign-up that set the password, so it confirms that password rather than adopting a stranger's — unlike a magic link, which anyone may request for any address (see `references/pitfalls/pre-account-hijack-strip.md`) - Return 200 (generic error on an invalid, expired, consumed, or wrong-`purpose` token) **POST /api/auth/password-reset/request** - Body: `{ email }` (canonicalize through the sign-up helper before lookup)
在 GitHub 查看
这个 SKILL.md 很大,SkillsMP 这里只预览前一段内容。 在 GitHub 查看