genesis-auth
Adds authentication to a genesis project. The user picks a tier and states requirements; the skill derives the mechanism — never quiz the user on implementation choices like JWT vs cookie — then writes the code directly into the target project.
This skill is a guideline, not a copy job. There is no reference implementation to clone: read the target project's existing code and write auth that matches it.
Tiers
| Tier | Use case | Includes |
|---|---|---|
basic |
Internal tools | Single admin seeded from env var, password login, cookie session in Postgres. No signup, no email. |
standard |
Normal apps | Email+password users, optional Google/Apple SSO, sessions in Postgres, password reset, admin/user roles. |
strict |
Sensitive data | standard + TOTP MFA, rate limiting + lockout, session rotation on privilege change, audit log. Beyond this, recommend an external IdP (Keycloak, Auth0, WorkOS) instead of more homegrown code. |
Question flow
- Read the arguments first.
basic/standard/strictanswers the tier;google/appleanswers SSO. Ask only what is still missing. - Ask remaining questions in ONE AskUserQuestion call, with the recommended option first and marked "(Recommended)":
- Tier:
basic|standard (Recommended)|strict - Clients:
browser only (Recommended)|also mobile/API consumers - SSO providers (multiSelect):
google|apple— an empty selection means no SSO. Omit this question only when the tier is already known to bebasic; if the tier is asked in the same call and the user picksbasic, ignore the SSO answer.
- Tier:
- Derive the mechanism — do not ask about it:
- browser only → cookie (HttpOnly, Secure, SameSite=Lax) + server-side session token in Postgres
- mobile/API consumers → same cookie flow for the web, plus a token path (JWT access + refresh, or API keys for machine consumers)
- Confirm with the derived plan in prose, not more pickers. Example: "basic tier: seeded admin, cookie sessions in Postgres, no SSO — proceed?" If the user overrides a mechanism (e.g. "actually JWT"), honor it.
Implementation rules
- Read the target project before writing anything. Its router, config struct, migration numbering, and package layout decide the shape of the new code. Match them; do not impose a layout from this document.
- Extend the existing users table, don't invent a parallel one. A genesis server already ships
internal/db/migrations/0001_create_users.sqlwithpassword_hashand auser_roleenum. Add columns and new tables (sessions, password resets, SSO identities, MFA secrets) in a new numbered migration. - Follow the established layout for a genesis server:
internal/auth/— password hashing, session/token issue and verify, provider clients. No gin types in here.internal/api/http/handler/auth.go— login, logout, signup, reset endpoints.internal/api/http/dto/auth.go— request/response structs.internal/api/http/middleware/auth.go— session/bearer verification, role checks.internal/db/migrations/NNNN_*.sql— goose-- +goose Up/Downblocks, both directions.internal/db/queries/*.sql— sqlc named queries; runsqlc generateafter editing.
- Wire everything. Register handlers and middleware in
SetupRoute, add any new dependency to theServicesstruct, and construct it inmain.go. Auth code that compiles but is never mounted looks done and isn't. - Config goes through the existing mechanism. Add fields to the config struct in
cmd/<app>/config.go, defaults toapplication.yml, and every new key to.env.exampleusing the.→_upper-case form (auth.session_ttl→AUTH_SESSION_TTL). Never reados.Getenvdirectly. - Use the standard library and existing deps first.
golang.org/x/crypto/bcryptfor passwords,crypto/randfor tokens. Add a dependency only when the tier genuinely needs it (JWT, TOTP), and rungo mod tidy. - Never log or return secrets. No password, hash, session token, or reset token in logs or error responses.
Verification procedure
make buildpasses in the target server.sqlc generateis clean and the generated code is committed.- A migration file exists — up and down — for every new table or column the code queries.
- Every new config key the code reads appears in
.env.exampleandapplication.yml. - For cookie sessions: the cookie is set with
HttpOnly,Secure, andSameSite. - Session tokens are stored hashed, with an expiry column, and logout deletes the row.
Common mistakes to watch for
- Asking mechanism questions. Never ask "JWT or cookie?" — derive it from the Clients answer.
- Re-asking what arguments already answered.
/genesis-auth basicshould ask nothing except the final confirmation. - Copying without wiring. Routes and middleware that are never mounted on the router.
- A second users table. Extend the one the project already has.
- Migrations without a
Downblock, or editing an already-applied migration instead of adding a new one. - Hand-editing
internal/db/sqlc/. It is generated; change the.sqlquery and regenerate.