hatch3r 1.7.0 → 1.7.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -12
- package/agents/hatch3r-a11y-auditor.md +4 -0
- package/agents/hatch3r-architect.md +5 -1
- package/agents/hatch3r-ci-watcher.md +4 -0
- package/agents/hatch3r-context-rules.md +4 -0
- package/agents/hatch3r-creator.md +4 -0
- package/agents/hatch3r-dependency-auditor.md +4 -0
- package/agents/hatch3r-devops.md +4 -0
- package/agents/hatch3r-docs-writer.md +4 -0
- package/agents/hatch3r-fixer.md +5 -1
- package/agents/hatch3r-handoff-loader.md +243 -0
- package/agents/hatch3r-handoff-preparer.md +134 -0
- package/agents/hatch3r-implementer.md +5 -1
- package/agents/hatch3r-learnings-loader.md +4 -0
- package/agents/hatch3r-lint-fixer.md +4 -0
- package/agents/hatch3r-perf-profiler.md +8 -0
- package/agents/hatch3r-researcher.md +5 -1
- package/agents/hatch3r-reviewer.md +92 -0
- package/agents/hatch3r-security-auditor.md +24 -0
- package/agents/hatch3r-test-writer.md +4 -0
- package/agents/modes/requirements-elicitation.md +5 -1
- package/agents/modes/similar-implementation.md +6 -0
- package/agents/modes/user-flows.md +76 -0
- package/agents/shared/quality-charter.md +129 -0
- package/agents/shared/user-question-protocol.md +95 -0
- package/commands/board/shared-azure-devops.md +2 -0
- package/commands/board/shared-github.md +17 -0
- package/commands/board/shared-gitlab.md +4 -0
- package/commands/hatch3r-board-fill.md +2 -1
- package/commands/hatch3r-board-pickup.md +1 -1
- package/commands/hatch3r-board-shared.md +21 -0
- package/commands/hatch3r-create.md +2 -0
- package/commands/hatch3r-handoff.md +126 -0
- package/commands/hatch3r-pr-resolve.md +672 -0
- package/commands/hatch3r-quick-change.md +5 -3
- package/commands/hatch3r-report.md +167 -0
- package/commands/hatch3r-revision.md +1 -1
- package/commands/hatch3r-workflow.md +3 -1
- package/dist/cli/index.js +3144 -979
- package/dist/cli/index.js.map +1 -1
- package/package.json +4 -2
- package/rules/hatch3r-accessibility-standards.md +21 -0
- package/rules/hatch3r-accessibility-standards.mdc +21 -0
- package/rules/hatch3r-agent-orchestration.md +32 -1
- package/rules/hatch3r-agent-orchestration.mdc +32 -1
- package/rules/hatch3r-ai-evals.md +158 -0
- package/rules/hatch3r-ai-evals.mdc +154 -0
- package/rules/hatch3r-ai-ux-patterns.md +131 -0
- package/rules/hatch3r-ai-ux-patterns.mdc +127 -0
- package/rules/hatch3r-api-design.md +67 -9
- package/rules/hatch3r-api-design.mdc +67 -9
- package/rules/hatch3r-api-versioning.md +119 -0
- package/rules/hatch3r-api-versioning.mdc +115 -0
- package/rules/hatch3r-auth-patterns.md +170 -0
- package/rules/hatch3r-auth-patterns.mdc +166 -0
- package/rules/hatch3r-component-conventions.md +30 -0
- package/rules/hatch3r-component-conventions.mdc +30 -0
- package/rules/hatch3r-container-hardening.md +131 -0
- package/rules/hatch3r-container-hardening.mdc +127 -0
- package/rules/hatch3r-contract-testing.md +117 -0
- package/rules/hatch3r-contract-testing.mdc +113 -0
- package/rules/hatch3r-deep-context.md +3 -1
- package/rules/hatch3r-deep-context.mdc +3 -1
- package/rules/hatch3r-dependency-management.md +73 -1
- package/rules/hatch3r-dependency-management.mdc +72 -0
- package/rules/hatch3r-design-system-detection.md +142 -0
- package/rules/hatch3r-design-system-detection.mdc +138 -0
- package/rules/hatch3r-event-schema-evolution.md +90 -0
- package/rules/hatch3r-event-schema-evolution.mdc +86 -0
- package/rules/hatch3r-handoff-readiness.md +45 -0
- package/rules/hatch3r-handoff-readiness.mdc +40 -0
- package/rules/hatch3r-i18n.md +13 -0
- package/rules/hatch3r-i18n.mdc +13 -0
- package/rules/hatch3r-iteration-summary.md +2 -0
- package/rules/hatch3r-iteration-summary.mdc +2 -0
- package/rules/hatch3r-migrations.md +61 -16
- package/rules/hatch3r-migrations.mdc +61 -16
- package/rules/hatch3r-observability-logging.md +1 -1
- package/rules/hatch3r-observability-logging.mdc +1 -1
- package/rules/hatch3r-observability-metrics.md +1 -1
- package/rules/hatch3r-observability-metrics.mdc +1 -1
- package/rules/hatch3r-observability-tracing-detail.md +1 -1
- package/rules/hatch3r-observability-tracing-detail.mdc +1 -1
- package/rules/hatch3r-observability-tracing.md +1 -1
- package/rules/hatch3r-observability-tracing.mdc +1 -1
- package/rules/hatch3r-observability.md +1 -0
- package/rules/hatch3r-observability.mdc +1 -0
- package/rules/hatch3r-operability.md +149 -0
- package/rules/hatch3r-operability.mdc +145 -0
- package/rules/hatch3r-passkey-server.md +181 -0
- package/rules/hatch3r-passkey-server.mdc +177 -0
- package/rules/hatch3r-progressive-delivery.md +120 -0
- package/rules/hatch3r-progressive-delivery.mdc +116 -0
- package/rules/hatch3r-resilience-patterns.md +154 -0
- package/rules/hatch3r-resilience-patterns.mdc +150 -0
- package/rules/hatch3r-secrets-management.md +29 -0
- package/rules/hatch3r-secrets-management.mdc +29 -0
- package/rules/hatch3r-testing.md +139 -43
- package/rules/hatch3r-testing.mdc +139 -43
- package/rules/hatch3r-ux-states-and-flows.md +149 -0
- package/rules/hatch3r-ux-states-and-flows.mdc +145 -0
- package/skills/hatch3r-a11y-audit/SKILL.md +14 -0
- package/skills/hatch3r-ai-feature/SKILL.md +134 -0
- package/skills/hatch3r-api-spec/SKILL.md +5 -0
- package/skills/hatch3r-architecture-review/SKILL.md +14 -0
- package/skills/hatch3r-bug-fix/SKILL.md +5 -0
- package/skills/hatch3r-ci-pipeline/SKILL.md +14 -0
- package/skills/hatch3r-cli-aichat/SKILL.md +84 -0
- package/skills/hatch3r-cli-ast-grep/SKILL.md +85 -0
- package/skills/hatch3r-cli-az-devops/SKILL.md +89 -0
- package/skills/hatch3r-cli-bat/SKILL.md +85 -0
- package/skills/hatch3r-cli-comby/SKILL.md +85 -0
- package/skills/hatch3r-cli-csvkit/SKILL.md +84 -0
- package/skills/hatch3r-cli-delta/SKILL.md +86 -0
- package/skills/hatch3r-cli-difftastic/SKILL.md +84 -0
- package/skills/hatch3r-cli-docker/SKILL.md +89 -0
- package/skills/hatch3r-cli-duckdb/SKILL.md +84 -0
- package/skills/hatch3r-cli-fd/SKILL.md +85 -0
- package/skills/hatch3r-cli-fzf/SKILL.md +84 -0
- package/skills/hatch3r-cli-gh/SKILL.md +90 -0
- package/skills/hatch3r-cli-glab/SKILL.md +89 -0
- package/skills/hatch3r-cli-jq/SKILL.md +85 -0
- package/skills/hatch3r-cli-lazygit/SKILL.md +78 -0
- package/skills/hatch3r-cli-llm/SKILL.md +84 -0
- package/skills/hatch3r-cli-miller/SKILL.md +84 -0
- package/skills/hatch3r-cli-mods/SKILL.md +84 -0
- package/skills/hatch3r-cli-overview/SKILL.md +60 -0
- package/skills/hatch3r-cli-playwright/SKILL.md +89 -0
- package/skills/hatch3r-cli-podman/SKILL.md +84 -0
- package/skills/hatch3r-cli-ripgrep/SKILL.md +85 -0
- package/skills/hatch3r-cli-rtk/SKILL.md +91 -0
- package/skills/hatch3r-cli-sd/SKILL.md +85 -0
- package/skills/hatch3r-cli-stagehand/SKILL.md +79 -0
- package/skills/hatch3r-cli-taplo/SKILL.md +84 -0
- package/skills/hatch3r-cli-xsv/SKILL.md +89 -0
- package/skills/hatch3r-cli-yq/SKILL.md +85 -0
- package/skills/hatch3r-cli-zstd/SKILL.md +85 -0
- package/skills/hatch3r-context-health/SKILL.md +14 -0
- package/skills/hatch3r-cost-tracking/SKILL.md +14 -0
- package/skills/hatch3r-customize/SKILL.md +14 -0
- package/skills/hatch3r-dep-audit/SKILL.md +14 -0
- package/skills/hatch3r-design-system-detect/SKILL.md +162 -0
- package/skills/hatch3r-feature/SKILL.md +2 -0
- package/skills/hatch3r-gh-agentic-workflows/SKILL.md +13 -0
- package/skills/hatch3r-handoff-prepare/SKILL.md +160 -0
- package/skills/hatch3r-handoff-resume/SKILL.md +171 -0
- package/skills/hatch3r-incident-response/SKILL.md +14 -0
- package/skills/hatch3r-issue-workflow/SKILL.md +5 -0
- package/skills/hatch3r-logical-refactor/SKILL.md +14 -0
- package/skills/hatch3r-migration/SKILL.md +14 -0
- package/skills/hatch3r-observability-verify/SKILL.md +133 -0
- package/skills/hatch3r-perf-audit/SKILL.md +14 -0
- package/skills/hatch3r-pr-creation/SKILL.md +14 -0
- package/skills/hatch3r-qa-validation/SKILL.md +18 -0
- package/skills/hatch3r-recipe/SKILL.md +14 -0
- package/skills/hatch3r-refactor/SKILL.md +14 -0
- package/skills/hatch3r-release/SKILL.md +14 -0
- package/skills/hatch3r-reliability-verify/SKILL.md +144 -0
- package/skills/hatch3r-ui-ux-verify/SKILL.md +136 -0
- package/skills/hatch3r-visual-refactor/SKILL.md +15 -1
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: API versioning, deprecation lifecycle, and idempotency — RFC 9457 errors, RFC 9745 Deprecation header, RFC 8594 Sunset, OAuth 2.1, Idempotency-Key, semver vs CalVer for APIs
|
|
3
|
+
globs: ["**/api/**", "**/openapi*", "**/asyncapi*", "**/*.proto", "**/routes/**", "**/handlers/**", "**/controllers/**"]
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
# API Versioning, Deprecation & Idempotency
|
|
7
|
+
|
|
8
|
+
Lifecycle rules for evolving REST, GraphQL, and gRPC contracts without breaking consumers. Pairs with `rules/hatch3r-api-design.md` (shape) and `rules/hatch3r-contract-testing.md` (verification).
|
|
9
|
+
|
|
10
|
+
## Versioning Scheme
|
|
11
|
+
|
|
12
|
+
- **Semver (`v1`, `v2`)** for stable contracts and published SDKs: major version goes in the URL prefix (`/v2/users`) for breaking changes; minor and patch updates are field-level additive and stay within the same major.
|
|
13
|
+
- **CalVer (`2026-05-15`)** for rolling APIs that change frequently (Stripe-style date-based versioning): clients pin a date via `Stripe-Version` / `Api-Version` header; the server transforms newer responses down to the pinned date.
|
|
14
|
+
- Pick one scheme per API and document it in the spec — never mix semver and CalVer in the same surface.
|
|
15
|
+
- Within a major (semver) or pinned date (CalVer), only additive changes ship: new fields, new endpoints, new enum values (when consumers handle `unknown` fallback).
|
|
16
|
+
|
|
17
|
+
## Deprecation Lifecycle (RFC 9745 + RFC 8594)
|
|
18
|
+
|
|
19
|
+
Every retirement passes three stages. Skipping any stage breaks downstream consumers.
|
|
20
|
+
|
|
21
|
+
| Stage | Header(s) | Action |
|
|
22
|
+
|-------|-----------|--------|
|
|
23
|
+
| Announce | `Deprecation: @<unix-ts>` (RFC 9745, Mar 2025 Standards Track) + `Link: <https://docs.example.com/migrate/v2>; rel="deprecation"` | Emit on every deprecated endpoint/field response; log usage by `X-Api-Key` / authenticated identity. |
|
|
24
|
+
| Sunset | `Sunset: <HTTP-date>` (RFC 8594) | Set N months before removal: N=6 public, N=3 partner, N=1 internal. Pair with continued `Deprecation` header. |
|
|
25
|
+
| Remove | HTTP 410 Gone + Problem Details (`type: https://errors.example.com/sunset`, `title: Endpoint removed`) | Only after the sunset date passes AND analytics show <0.1% usage for two consecutive 7-day windows. |
|
|
26
|
+
|
|
27
|
+
- Field-level deprecation: emit `Deprecation` per endpoint that still returns the field; GraphQL uses `@deprecated(reason: "...")`; protobuf uses `[deprecated = true]`.
|
|
28
|
+
- Document the migration in the `Link: ...rel="deprecation"` target — include before/after code samples, fallback strategy, and the removal date.
|
|
29
|
+
|
|
30
|
+
## Idempotency-Key (draft-ietf-httpapi-idempotency-key-header)
|
|
31
|
+
|
|
32
|
+
Every side-effectful endpoint (POST / PATCH / PUT / DELETE that mutates state) accepts an `Idempotency-Key: <client-generated-uuid>` request header.
|
|
33
|
+
|
|
34
|
+
- **Key format:** UUIDv4 or ULID, max 255 chars. Clients generate; servers never accept server-generated keys.
|
|
35
|
+
- **Storage:** server persists `(tenant_id, api_key, idempotency_key, request_body_hash, response_status, response_body)` for 24 hours (configurable per API; Stripe uses 24h, recommended range 24h-7d).
|
|
36
|
+
- **Replay semantics:**
|
|
37
|
+
- Exact replay (same key + same request body hash) -> return the original response (same status, same body, same `Idempotency-Replay: true` header).
|
|
38
|
+
- Conflicting replay (same key + different request body hash) -> 422 with Problem Details `type: https://errors.example.com/idempotency-conflict`.
|
|
39
|
+
- In-flight replay (same key, original still processing) -> 409 Conflict + `Retry-After: <seconds>`.
|
|
40
|
+
- **Scope:** per `(tenant_id, api_key)`, never global. Hashing the body prevents replay-with-mutation attacks.
|
|
41
|
+
|
|
42
|
+
## Rate Limit Headers (draft-ietf-httpapi-ratelimit-headers)
|
|
43
|
+
|
|
44
|
+
Emit structured-field headers on every response (not just 429):
|
|
45
|
+
|
|
46
|
+
| Header | Value | Purpose |
|
|
47
|
+
|--------|-------|---------|
|
|
48
|
+
| `RateLimit-Policy` | `100;w=60` | Quota + window length (seconds). |
|
|
49
|
+
| `RateLimit-Limit` | `100` | Maximum requests in current window. |
|
|
50
|
+
| `RateLimit-Remaining` | `42` | Remaining quota in current window. |
|
|
51
|
+
| `RateLimit-Reset` | `30` | Seconds until the window resets. |
|
|
52
|
+
|
|
53
|
+
- On 429, also include `Retry-After: <seconds>` (RFC 9110).
|
|
54
|
+
- Vendor-specific `X-RateLimit-*` headers may be emitted alongside for backward compatibility, but the IETF draft headers are the floor.
|
|
55
|
+
|
|
56
|
+
## OAuth 2.1 (draft-ietf-oauth-v2-1)
|
|
57
|
+
|
|
58
|
+
- **PKCE mandatory on all clients** (public and confidential) — `code_challenge` + `code_challenge_method=S256`.
|
|
59
|
+
- **Implicit and password (ROPC) grants removed.** Use authorization code + PKCE for interactive; client credentials for server-server; device code for input-constrained.
|
|
60
|
+
- **Exact redirect-URI matching** — no wildcards, no partial paths. Pre-register each callback URL.
|
|
61
|
+
- **Refresh-token rotation with reuse detection** — on every refresh, issue a new refresh token and invalidate the old one. If the old token is presented after rotation, revoke the entire token family (replay attack signal).
|
|
62
|
+
- Access tokens short-lived (5-15 min). Long-lived refresh tokens, sender-constrained (DPoP or mTLS) for public clients.
|
|
63
|
+
- Full auth detail: `rules/hatch3r-auth-patterns.md`.
|
|
64
|
+
|
|
65
|
+
## Resource Indicators (RFC 8707)
|
|
66
|
+
|
|
67
|
+
- Token requests include a `resource=<uri>` parameter naming the protected resource the token will be presented to.
|
|
68
|
+
- Authorization servers bind the token's `aud` claim to the requested resource — prevents audience-confusion attacks across multi-tenant AS deployments.
|
|
69
|
+
- Multi-resource consent flows pass multiple `resource` params; the AS issues separate tokens per audience.
|
|
70
|
+
|
|
71
|
+
## DPoP (RFC 9449)
|
|
72
|
+
|
|
73
|
+
- Sender-constrained access and refresh tokens for browser-resident clients (SPAs) — alternative to mTLS for public clients.
|
|
74
|
+
- Client generates a key pair (non-extractable in the browser via WebCrypto), signs a fresh DPoP JWT per request, sends in `DPoP: <jwt>` header.
|
|
75
|
+
- Server binds the access token's `cnf.jkt` claim (JWK thumbprint) to the client's public key; rejects token presentation from any other key.
|
|
76
|
+
- Recommended floor for any token leaving the first-party boundary (third-party SDK consumers, mobile apps with insecure storage).
|
|
77
|
+
|
|
78
|
+
## Webhook Signing (Standard Webhooks convention)
|
|
79
|
+
|
|
80
|
+
- Headers: `webhook-id` (unique delivery ID), `webhook-timestamp` (unix seconds), `webhook-signature` (`v1,<base64-HMAC-SHA256(<id>.<timestamp>.<body>)>`).
|
|
81
|
+
- HMAC-SHA256 with a per-tenant shared secret, constant-time comparison.
|
|
82
|
+
- Reject deliveries where `|now - webhook-timestamp| > 300` seconds (5-minute replay window).
|
|
83
|
+
- `webhook-id` doubles as the idempotency key on the receiver — cache for >=5 minutes (Redis/SQLite) to dedupe duplicate deliveries.
|
|
84
|
+
- **Key rotation:** signature spec supports comma-separated versions (`v1,sig1 v2,sig2`); receivers accept any valid version during the rollover window.
|
|
85
|
+
- Deliveries that fail signature verification return HTTP 401 + Problem Details `type: https://errors.example.com/invalid-signature`.
|
|
86
|
+
|
|
87
|
+
## Backward Compatibility Policy
|
|
88
|
+
|
|
89
|
+
- **Field additions** are always safe.
|
|
90
|
+
- **Field removal or rename** requires the full RFC 9745 + RFC 8594 lifecycle (Announce -> Sunset -> Remove). Never remove without the lifecycle.
|
|
91
|
+
- **Enum extension** is safe only when consumers handle an `unknown` fallback value. Generated client code (OpenAPI Generator, openapi-typescript) must emit the `unknown` branch.
|
|
92
|
+
- **Nullable transitions** (required -> optional, or non-null -> nullable) require a feature flag and a deprecation window — clients written against the stricter shape will break on `null`.
|
|
93
|
+
- **Type changes** (e.g., `int32` -> `int64` in protobuf, `string` -> `string | null` in OpenAPI) require a new major version unless the wire format is unchanged (protobuf int32->int64 is wire-compatible for small values; document the edge case).
|
|
94
|
+
|
|
95
|
+
## CI Gates
|
|
96
|
+
|
|
97
|
+
Every PR touching an API contract runs the matching diff tool against the last shipped tag. Breaking changes block merge.
|
|
98
|
+
|
|
99
|
+
- `oasdiff breaking` (OpenAPI 3.0 + 3.1, 450+ rules, CNCF Sandbox) — comments on the PR with the breaking-change list.
|
|
100
|
+
- `buf breaking` (Protobuf, default `FILE` rule set) — blocks wire + source incompatibility.
|
|
101
|
+
- `graphql-inspector diff` — blocks GraphQL schema breaking changes.
|
|
102
|
+
|
|
103
|
+
All three integrate with PR comments and fail the build on a breaking exit code. Cross-reference the gate set in `rules/hatch3r-api-design.md` "Breaking-Change CI Gate".
|
|
104
|
+
|
|
105
|
+
## References
|
|
106
|
+
|
|
107
|
+
- RFC 9457 — Problem Details for HTTP APIs (March 2025, obsoletes RFC 7807).
|
|
108
|
+
- RFC 9745 — The Deprecation HTTP Response Header Field (March 2025, Standards Track).
|
|
109
|
+
- RFC 8594 — The Sunset HTTP Response Header Field.
|
|
110
|
+
- RFC 8707 — Resource Indicators for OAuth 2.0.
|
|
111
|
+
- RFC 9449 — OAuth 2.0 Demonstrating Proof of Possession (DPoP).
|
|
112
|
+
- draft-ietf-oauth-v2-1 — The OAuth 2.1 Authorization Framework.
|
|
113
|
+
- draft-ietf-httpapi-idempotency-key-header — The Idempotency-Key HTTP Header Field.
|
|
114
|
+
- draft-ietf-httpapi-ratelimit-headers — RateLimit Header Fields for HTTP.
|
|
115
|
+
- Standard Webhooks — https://github.com/standard-webhooks/standard-webhooks
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: hatch3r-auth-patterns
|
|
3
|
+
type: rule
|
|
4
|
+
description: Authentication and authorization patterns for end-user apps — OAuth 2.1, OIDC, DPoP, JWT rotation, cookie security, RBAC vs ABAC vs ReBAC rubric
|
|
5
|
+
scope: "**/auth/**,**/login/**,**/session/**,**/oauth/**,**/oidc/**,**/jwt/**,**/permissions/**,**/policies/**,**/middleware/**"
|
|
6
|
+
tags: [security, implementation]
|
|
7
|
+
quality_charter: agents/shared/quality-charter.md
|
|
8
|
+
cache_friendly: true
|
|
9
|
+
---
|
|
10
|
+
# Authentication & Authorization Patterns
|
|
11
|
+
|
|
12
|
+
Backend-side identity stack for end-user apps. Pairs with `rules/hatch3r-passkey-server.md` (WebAuthn server ceremony) and the frontend rules `rules/hatch3r-ux-states-and-flows.md` + `rules/hatch3r-ai-ux-patterns.md` (identifier-first login, passkey Conditional UI).
|
|
13
|
+
|
|
14
|
+
## OAuth 2.1 (Name It)
|
|
15
|
+
|
|
16
|
+
Adopt OAuth 2.1 (`draft-ietf-oauth-v2-1`, draft-15 Mar 2026) over OAuth 2.0. Reference RFC 9700 (OAuth Security BCP, Jan 2025) as the operative compliance bar.
|
|
17
|
+
|
|
18
|
+
- PKCE required on every public client (web SPA, mobile, desktop) AND every confidential client.
|
|
19
|
+
- Implicit grant REMOVED. Resource Owner Password Credentials (ROPC) grant REMOVED. Never use either.
|
|
20
|
+
- Exact redirect-URI string matching. No wildcards, no substring match, no prefix match.
|
|
21
|
+
- Refresh-token rotation with reuse detection: on detected reuse, revoke the entire refresh-token family and force re-authentication.
|
|
22
|
+
- Access-token TTL 5-15 min; refresh-token TTL bounded (8-72h sliding for SPAs, longer for native).
|
|
23
|
+
- Authorization Code grant + PKCE is the only public-client grant. Client Credentials for service-to-service.
|
|
24
|
+
|
|
25
|
+
## OIDC ID-Token Validation
|
|
26
|
+
|
|
27
|
+
Every ID token received from an OIDC provider must validate ALL of the following before a session is created:
|
|
28
|
+
|
|
29
|
+
| Check | Rule |
|
|
30
|
+
|-------|------|
|
|
31
|
+
| `iss` | Equal to the expected issuer URL (string match) |
|
|
32
|
+
| `aud` | Contains this client's `client_id` |
|
|
33
|
+
| `azp` | Equals `client_id` when present and when `aud` has multiple values |
|
|
34
|
+
| `exp` | Now < `exp` |
|
|
35
|
+
| `iat` | `now - iat` within tolerable skew (default 5 min) |
|
|
36
|
+
| `auth_time` | Sanity-checked against session policy (max-age, prompt=login) |
|
|
37
|
+
| `nonce` | Equals the nonce generated for this authorization request (replay defense) |
|
|
38
|
+
| Signature | Verified against the issuer's JWKS; `kid` selects the current key |
|
|
39
|
+
|
|
40
|
+
Logout: implement BOTH RP-initiated logout (`end_session_endpoint` per OIDC RP-Initiated Logout 1.0) AND back-channel logout (server-to-server session-invalidation callback) for SSO sessions. ID-token-only state has no server invalidation path — pair with a server-side session record.
|
|
41
|
+
|
|
42
|
+
## DPoP — Sender-Constrained Tokens (RFC 9449)
|
|
43
|
+
|
|
44
|
+
For browser-resident or public-client access tokens, bind tokens to a client-held key with DPoP. Replaces mTLS for clients that cannot manage certificates.
|
|
45
|
+
|
|
46
|
+
- Client generates an ECDSA or RSA keypair, stored non-extractable (WebCrypto `extractable: false`).
|
|
47
|
+
- Every protected request carries a `DPoP` header — a signed JWT with claims `htm` (HTTP method), `htu` (full URL), `iat`, `jti` (replay-cache key), and the public JWK in `jwk` header.
|
|
48
|
+
- Access token contains a `cnf.jkt` claim — SHA-256 JWK thumbprint of the bound key. Server verifies the DPoP-proof JWK thumbprint matches the access token's `cnf.jkt`.
|
|
49
|
+
- Server replay cache stores `jti` for the proof's `iat` window (default 60s skew + 5 min retention).
|
|
50
|
+
- Service-to-service: prefer mTLS (`x5t#S256` cnf claim) where the certificate chain is manageable; DPoP for browser/mobile.
|
|
51
|
+
|
|
52
|
+
## JWT Pitfalls (RFC 8725 BCP)
|
|
53
|
+
|
|
54
|
+
- Reject `alg: none` always. Reject `alg: HS*` when the verification key is public (RS256/ES256 key-confusion attack).
|
|
55
|
+
- Pin the expected `alg` per issuer. Server config names the algorithm — never trust the `alg` header without an allowlist.
|
|
56
|
+
- JWKS endpoint cache TTL 1-24 hours. `kid` selects the current key. Rotation supported by publishing N+1 before retiring N (overlap window >= 2 * cache TTL).
|
|
57
|
+
- Audience binding mandatory. Each service has its own `aud` value and rejects tokens not minted for it.
|
|
58
|
+
- Revocation strategy: short access-TTL + periodic refresh OR introspection (RFC 7662) OR a revocation list for long-TTL tokens. Never assume tokens are revocable without one of these.
|
|
59
|
+
- No PII, no sensitive data in JWT payload. JWT payloads are base64-readable by anyone holding the token.
|
|
60
|
+
|
|
61
|
+
## Cookie Security
|
|
62
|
+
|
|
63
|
+
Every auth-bearing cookie must set:
|
|
64
|
+
|
|
65
|
+
- `__Host-` prefix — implies `Path=/`, `Secure`, no `Domain` attribute. The prefix blocks subdomain shadowing.
|
|
66
|
+
- `HttpOnly` — blocks JS read.
|
|
67
|
+
- `Secure` — TLS-only transmission.
|
|
68
|
+
- `SameSite=Strict` for primary session cookies. Use `Lax` only when cross-site GET reads are required.
|
|
69
|
+
- `SameSite=None` REQUIRES `Partitioned` per CHIPS. Chrome's 2026 enforcement plan treats unpartitioned third-party cookies as deprecated.
|
|
70
|
+
- Short expiry (8-72h sliding); rolling refresh on activity.
|
|
71
|
+
|
|
72
|
+
CSRF defense ordering: `SameSite=Strict` is the primary defense for session cookies. Add a double-submit token (Origin/Cookie pair) for state-changing requests reachable from `SameSite=Lax` cookies. Validate `Origin` and `Sec-Fetch-Site` headers on high-value mutations.
|
|
73
|
+
|
|
74
|
+
## MFA and NIST 800-63B-4 AAL Mapping
|
|
75
|
+
|
|
76
|
+
NIST SP 800-63B-4 (finalized mid-2025) demoted SMS to a restricted authenticator. Email OTP is deprecated. Map operations to AAL:
|
|
77
|
+
|
|
78
|
+
| Level | Authenticators | Use Case |
|
|
79
|
+
|-------|---------------|----------|
|
|
80
|
+
| AAL1 | Single factor — password OR WebAuthn UV | Low-risk reads, public-facing content |
|
|
81
|
+
| AAL2 | Two factor — password + TOTP, OR passkey (WebAuthn) with UV | Account access, settings changes |
|
|
82
|
+
| AAL3 | Hardware-bound multi-factor — WebAuthn UV with hardware-backed key | Admin actions, financial transfers, key rotation |
|
|
83
|
+
|
|
84
|
+
Step-up auth pattern: when a session is AAL1 and a sensitive op is requested (delete account, change email, change password, transfer funds, rotate API key, change billing), re-prompt the user for a fresh authentication. Issue a short-lived step-up token (5-15 min) carrying the AAL upgrade, scoped to the operation.
|
|
85
|
+
|
|
86
|
+
## Authorization Model Rubric
|
|
87
|
+
|
|
88
|
+
Pick the model per app complexity. Document the choice in the project spec.
|
|
89
|
+
|
|
90
|
+
| Model | Use When | Engines |
|
|
91
|
+
|-------|----------|---------|
|
|
92
|
+
| **RBAC** (roles to permissions) | Flat-org tools, role count <20, permissions don't depend on resource attributes | App-layer; CASL; Pundit |
|
|
93
|
+
| **ABAC** (attributes to policy) | Access depends on user/resource attributes — department, region, classification, time-of-day | OPA (Rego), AWS Cedar |
|
|
94
|
+
| **ReBAC** (relationships to permissions) | Collaboration apps with sharing graphs — "user can edit doc if member of folder shared with team" | SpiceDB, OpenFGA, Permify, AuthZed |
|
|
95
|
+
|
|
96
|
+
ReBAC reference: Google Zanzibar paper (USENIX ATC 2019). For new collaboration apps, default to ReBAC over hand-rolled per-resource ACL tables.
|
|
97
|
+
|
|
98
|
+
**AuthZEN Authorization API 1.0** (OIDF Final, Jan 2026) — engine-neutral PEP-to-PDP wire format. Adopt for service architectures where authorization is centralized.
|
|
99
|
+
|
|
100
|
+
## Multi-Tenancy Isolation
|
|
101
|
+
|
|
102
|
+
- Every tenant-scoped table carries a `tenant_id` column.
|
|
103
|
+
- Postgres Row-Level Security policies enforce isolation at the DB layer: `CREATE POLICY tenant_isolation ON {table} USING (tenant_id = current_setting('app.tenant_id')::uuid)`.
|
|
104
|
+
- Per-tenant signing keys for sensitive crypto operations (BYOK pattern for Level 4 data per `rules/hatch3r-data-classification.md`).
|
|
105
|
+
- Cross-tenant access attempts return 404, not 403 — never confirm tenant existence to unauthorized callers.
|
|
106
|
+
- Integration tests assert cross-tenant access returns 404 on every tenant-scoped endpoint.
|
|
107
|
+
|
|
108
|
+
## Token Storage on Client
|
|
109
|
+
|
|
110
|
+
- Web: never `localStorage` or `sessionStorage` for tokens. Use `HttpOnly` `__Host-` cookies for sessions, OR in-memory access token + `HttpOnly` refresh cookie (BFF / silent-refresh pattern).
|
|
111
|
+
- Mobile iOS: Keychain Services with `kSecAttrAccessibleWhenUnlockedThisDeviceOnly`.
|
|
112
|
+
- Mobile Android: EncryptedSharedPreferences backed by Android Keystore.
|
|
113
|
+
- Never log full tokens. Log the `jti` (token ID) only for audit correlation.
|
|
114
|
+
|
|
115
|
+
## Secret Rotation Cadence
|
|
116
|
+
|
|
117
|
+
- Automated via HashiCorp Vault / AWS Secrets Manager / GCP Secret Manager — never manual.
|
|
118
|
+
- Rotation cadence per secret type — see `rules/hatch3r-secrets-management.md`.
|
|
119
|
+
- Zero-downtime rotation pattern: publish N+1, wait >= 2 * cache TTL, switch signing to N+1, retire N after refresh-token max-age.
|
|
120
|
+
|
|
121
|
+
## Auth Provider 2026 Landscape — Roll vs Buy
|
|
122
|
+
|
|
123
|
+
Decision rubric: managed for B2B + SSO/SAML/SCIM requirements; self-host when compliance forbids third-party identity OR when cost crosses break-even at scale.
|
|
124
|
+
|
|
125
|
+
| Provider | Sweet Spot |
|
|
126
|
+
|----------|-----------|
|
|
127
|
+
| Clerk | Best DX for React/Next.js consumer apps |
|
|
128
|
+
| Supabase Auth | Postgres-native + RLS-integrated stacks |
|
|
129
|
+
| WorkOS | Enterprise SSO + SCIM + Directory Sync |
|
|
130
|
+
| Auth0 / Okta | Enterprise B2B with mature compliance |
|
|
131
|
+
| Stytch | Passwordless + WebAuthn focus |
|
|
132
|
+
| Better Auth | OSS framework-agnostic, full control |
|
|
133
|
+
| Auth.js (NextAuth.js) | Next.js with minimal external dependency |
|
|
134
|
+
| FusionAuth / Keycloak / Ory | Self-host with full IdP capability |
|
|
135
|
+
|
|
136
|
+
## API Key Design
|
|
137
|
+
|
|
138
|
+
- Prefix convention for secret-scanner detection (`sk_live_*`, `pk_live_*`).
|
|
139
|
+
- Hash-only storage server-side (Argon2id or SHA-256 with per-key salt); never store plaintext.
|
|
140
|
+
- Per-key scope grants (resource + method allowlist).
|
|
141
|
+
- Per-key rate limit; per-key usage analytics with last-used timestamp.
|
|
142
|
+
- Revocation API; rotate quarterly; never log the full key value.
|
|
143
|
+
- For human users, replace API keys with passkeys + short-lived tokens.
|
|
144
|
+
|
|
145
|
+
## Audit Logging for Auth Events
|
|
146
|
+
|
|
147
|
+
Every auth event logged with `actor` (user_id), `target` (resource_id), `ip`, `user_agent`, `result` (success/failure/code), `timestamp`, and `trace_id` for SIEM correlation. Tamper-resistant append-only store; 1-year retention minimum.
|
|
148
|
+
|
|
149
|
+
Required event set: login success, login failure, MFA challenge issued, MFA verified, MFA failed, password reset requested, password reset completed, email change, role/scope grant, role/scope revoke, token issued, token revoked, session terminated, passkey added, passkey removed, step-up auth challenge, step-up auth verified.
|
|
150
|
+
|
|
151
|
+
## Cross-References
|
|
152
|
+
|
|
153
|
+
- `rules/hatch3r-passkey-server.md` — server-side WebAuthn ceremony (paired companion).
|
|
154
|
+
- `rules/hatch3r-ux-states-and-flows.md` — frontend identifier-first login + Conditional UI.
|
|
155
|
+
- `rules/hatch3r-ai-ux-patterns.md` — frontend WebAuthn UX patterns.
|
|
156
|
+
- `rules/hatch3r-api-versioning.md` — OAuth 2.1 in the API-versioning context.
|
|
157
|
+
- `rules/hatch3r-secrets-management.md` — JWT signing key + OAuth client secret rotation cadence.
|
|
158
|
+
- `rules/hatch3r-data-classification.md` — multi-tenant data isolation + BYOK.
|
|
159
|
+
|
|
160
|
+
## References
|
|
161
|
+
|
|
162
|
+
- RFC 9700 — OAuth 2.0 Security Best Current Practice (Jan 2025).
|
|
163
|
+
- RFC 9449 — OAuth 2.0 Demonstrating Proof of Possession (DPoP).
|
|
164
|
+
- RFC 8725 — JSON Web Token Best Current Practice.
|
|
165
|
+
- `draft-ietf-oauth-v2-1` — The OAuth 2.1 Authorization Framework.
|
|
166
|
+
- OpenID Connect Core 1.0 + RP-Initiated Logout 1.0 + Back-Channel Logout 1.0.
|
|
167
|
+
- NIST SP 800-63B-4 — Digital Identity Guidelines: Authentication and Authenticator Management.
|
|
168
|
+
- FAPI 2.0 Final (Feb 2025) — Financial-grade API profiles.
|
|
169
|
+
- AuthZEN Authorization API 1.0 Final (OpenID Foundation, Jan 2026).
|
|
170
|
+
- Google Zanzibar — Consistent, Global Authorization (USENIX ATC 2019).
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Authentication and authorization patterns for end-user apps — OAuth 2.1, OIDC, DPoP, JWT rotation, cookie security, RBAC vs ABAC vs ReBAC rubric
|
|
3
|
+
globs: ["**/auth/**", "**/login/**", "**/session/**", "**/oauth/**", "**/oidc/**", "**/jwt/**", "**/permissions/**", "**/policies/**", "**/middleware/**"]
|
|
4
|
+
alwaysApply: false
|
|
5
|
+
---
|
|
6
|
+
# Authentication & Authorization Patterns
|
|
7
|
+
|
|
8
|
+
Backend-side identity stack for end-user apps. Pairs with `rules/hatch3r-passkey-server.md` (WebAuthn server ceremony) and the frontend rules `rules/hatch3r-ux-states-and-flows.md` + `rules/hatch3r-ai-ux-patterns.md` (identifier-first login, passkey Conditional UI).
|
|
9
|
+
|
|
10
|
+
## OAuth 2.1 (Name It)
|
|
11
|
+
|
|
12
|
+
Adopt OAuth 2.1 (`draft-ietf-oauth-v2-1`, draft-15 Mar 2026) over OAuth 2.0. Reference RFC 9700 (OAuth Security BCP, Jan 2025) as the operative compliance bar.
|
|
13
|
+
|
|
14
|
+
- PKCE required on every public client (web SPA, mobile, desktop) AND every confidential client.
|
|
15
|
+
- Implicit grant REMOVED. Resource Owner Password Credentials (ROPC) grant REMOVED. Never use either.
|
|
16
|
+
- Exact redirect-URI string matching. No wildcards, no substring match, no prefix match.
|
|
17
|
+
- Refresh-token rotation with reuse detection: on detected reuse, revoke the entire refresh-token family and force re-authentication.
|
|
18
|
+
- Access-token TTL 5-15 min; refresh-token TTL bounded (8-72h sliding for SPAs, longer for native).
|
|
19
|
+
- Authorization Code grant + PKCE is the only public-client grant. Client Credentials for service-to-service.
|
|
20
|
+
|
|
21
|
+
## OIDC ID-Token Validation
|
|
22
|
+
|
|
23
|
+
Every ID token received from an OIDC provider must validate ALL of the following before a session is created:
|
|
24
|
+
|
|
25
|
+
| Check | Rule |
|
|
26
|
+
|-------|------|
|
|
27
|
+
| `iss` | Equal to the expected issuer URL (string match) |
|
|
28
|
+
| `aud` | Contains this client's `client_id` |
|
|
29
|
+
| `azp` | Equals `client_id` when present and when `aud` has multiple values |
|
|
30
|
+
| `exp` | Now < `exp` |
|
|
31
|
+
| `iat` | `now - iat` within tolerable skew (default 5 min) |
|
|
32
|
+
| `auth_time` | Sanity-checked against session policy (max-age, prompt=login) |
|
|
33
|
+
| `nonce` | Equals the nonce generated for this authorization request (replay defense) |
|
|
34
|
+
| Signature | Verified against the issuer's JWKS; `kid` selects the current key |
|
|
35
|
+
|
|
36
|
+
Logout: implement BOTH RP-initiated logout (`end_session_endpoint` per OIDC RP-Initiated Logout 1.0) AND back-channel logout (server-to-server session-invalidation callback) for SSO sessions. ID-token-only state has no server invalidation path — pair with a server-side session record.
|
|
37
|
+
|
|
38
|
+
## DPoP — Sender-Constrained Tokens (RFC 9449)
|
|
39
|
+
|
|
40
|
+
For browser-resident or public-client access tokens, bind tokens to a client-held key with DPoP. Replaces mTLS for clients that cannot manage certificates.
|
|
41
|
+
|
|
42
|
+
- Client generates an ECDSA or RSA keypair, stored non-extractable (WebCrypto `extractable: false`).
|
|
43
|
+
- Every protected request carries a `DPoP` header — a signed JWT with claims `htm` (HTTP method), `htu` (full URL), `iat`, `jti` (replay-cache key), and the public JWK in `jwk` header.
|
|
44
|
+
- Access token contains a `cnf.jkt` claim — SHA-256 JWK thumbprint of the bound key. Server verifies the DPoP-proof JWK thumbprint matches the access token's `cnf.jkt`.
|
|
45
|
+
- Server replay cache stores `jti` for the proof's `iat` window (default 60s skew + 5 min retention).
|
|
46
|
+
- Service-to-service: prefer mTLS (`x5t#S256` cnf claim) where the certificate chain is manageable; DPoP for browser/mobile.
|
|
47
|
+
|
|
48
|
+
## JWT Pitfalls (RFC 8725 BCP)
|
|
49
|
+
|
|
50
|
+
- Reject `alg: none` always. Reject `alg: HS*` when the verification key is public (RS256/ES256 key-confusion attack).
|
|
51
|
+
- Pin the expected `alg` per issuer. Server config names the algorithm — never trust the `alg` header without an allowlist.
|
|
52
|
+
- JWKS endpoint cache TTL 1-24 hours. `kid` selects the current key. Rotation supported by publishing N+1 before retiring N (overlap window >= 2 * cache TTL).
|
|
53
|
+
- Audience binding mandatory. Each service has its own `aud` value and rejects tokens not minted for it.
|
|
54
|
+
- Revocation strategy: short access-TTL + periodic refresh OR introspection (RFC 7662) OR a revocation list for long-TTL tokens. Never assume tokens are revocable without one of these.
|
|
55
|
+
- No PII, no sensitive data in JWT payload. JWT payloads are base64-readable by anyone holding the token.
|
|
56
|
+
|
|
57
|
+
## Cookie Security
|
|
58
|
+
|
|
59
|
+
Every auth-bearing cookie must set:
|
|
60
|
+
|
|
61
|
+
- `__Host-` prefix — implies `Path=/`, `Secure`, no `Domain` attribute. The prefix blocks subdomain shadowing.
|
|
62
|
+
- `HttpOnly` — blocks JS read.
|
|
63
|
+
- `Secure` — TLS-only transmission.
|
|
64
|
+
- `SameSite=Strict` for primary session cookies. Use `Lax` only when cross-site GET reads are required.
|
|
65
|
+
- `SameSite=None` REQUIRES `Partitioned` per CHIPS. Chrome's 2026 enforcement plan treats unpartitioned third-party cookies as deprecated.
|
|
66
|
+
- Short expiry (8-72h sliding); rolling refresh on activity.
|
|
67
|
+
|
|
68
|
+
CSRF defense ordering: `SameSite=Strict` is the primary defense for session cookies. Add a double-submit token (Origin/Cookie pair) for state-changing requests reachable from `SameSite=Lax` cookies. Validate `Origin` and `Sec-Fetch-Site` headers on high-value mutations.
|
|
69
|
+
|
|
70
|
+
## MFA and NIST 800-63B-4 AAL Mapping
|
|
71
|
+
|
|
72
|
+
NIST SP 800-63B-4 (finalized mid-2025) demoted SMS to a restricted authenticator. Email OTP is deprecated. Map operations to AAL:
|
|
73
|
+
|
|
74
|
+
| Level | Authenticators | Use Case |
|
|
75
|
+
|-------|---------------|----------|
|
|
76
|
+
| AAL1 | Single factor — password OR WebAuthn UV | Low-risk reads, public-facing content |
|
|
77
|
+
| AAL2 | Two factor — password + TOTP, OR passkey (WebAuthn) with UV | Account access, settings changes |
|
|
78
|
+
| AAL3 | Hardware-bound multi-factor — WebAuthn UV with hardware-backed key | Admin actions, financial transfers, key rotation |
|
|
79
|
+
|
|
80
|
+
Step-up auth pattern: when a session is AAL1 and a sensitive op is requested (delete account, change email, change password, transfer funds, rotate API key, change billing), re-prompt the user for a fresh authentication. Issue a short-lived step-up token (5-15 min) carrying the AAL upgrade, scoped to the operation.
|
|
81
|
+
|
|
82
|
+
## Authorization Model Rubric
|
|
83
|
+
|
|
84
|
+
Pick the model per app complexity. Document the choice in the project spec.
|
|
85
|
+
|
|
86
|
+
| Model | Use When | Engines |
|
|
87
|
+
|-------|----------|---------|
|
|
88
|
+
| **RBAC** (roles to permissions) | Flat-org tools, role count <20, permissions don't depend on resource attributes | App-layer; CASL; Pundit |
|
|
89
|
+
| **ABAC** (attributes to policy) | Access depends on user/resource attributes — department, region, classification, time-of-day | OPA (Rego), AWS Cedar |
|
|
90
|
+
| **ReBAC** (relationships to permissions) | Collaboration apps with sharing graphs — "user can edit doc if member of folder shared with team" | SpiceDB, OpenFGA, Permify, AuthZed |
|
|
91
|
+
|
|
92
|
+
ReBAC reference: Google Zanzibar paper (USENIX ATC 2019). For new collaboration apps, default to ReBAC over hand-rolled per-resource ACL tables.
|
|
93
|
+
|
|
94
|
+
**AuthZEN Authorization API 1.0** (OIDF Final, Jan 2026) — engine-neutral PEP-to-PDP wire format. Adopt for service architectures where authorization is centralized.
|
|
95
|
+
|
|
96
|
+
## Multi-Tenancy Isolation
|
|
97
|
+
|
|
98
|
+
- Every tenant-scoped table carries a `tenant_id` column.
|
|
99
|
+
- Postgres Row-Level Security policies enforce isolation at the DB layer: `CREATE POLICY tenant_isolation ON {table} USING (tenant_id = current_setting('app.tenant_id')::uuid)`.
|
|
100
|
+
- Per-tenant signing keys for sensitive crypto operations (BYOK pattern for Level 4 data per `rules/hatch3r-data-classification.md`).
|
|
101
|
+
- Cross-tenant access attempts return 404, not 403 — never confirm tenant existence to unauthorized callers.
|
|
102
|
+
- Integration tests assert cross-tenant access returns 404 on every tenant-scoped endpoint.
|
|
103
|
+
|
|
104
|
+
## Token Storage on Client
|
|
105
|
+
|
|
106
|
+
- Web: never `localStorage` or `sessionStorage` for tokens. Use `HttpOnly` `__Host-` cookies for sessions, OR in-memory access token + `HttpOnly` refresh cookie (BFF / silent-refresh pattern).
|
|
107
|
+
- Mobile iOS: Keychain Services with `kSecAttrAccessibleWhenUnlockedThisDeviceOnly`.
|
|
108
|
+
- Mobile Android: EncryptedSharedPreferences backed by Android Keystore.
|
|
109
|
+
- Never log full tokens. Log the `jti` (token ID) only for audit correlation.
|
|
110
|
+
|
|
111
|
+
## Secret Rotation Cadence
|
|
112
|
+
|
|
113
|
+
- Automated via HashiCorp Vault / AWS Secrets Manager / GCP Secret Manager — never manual.
|
|
114
|
+
- Rotation cadence per secret type — see `rules/hatch3r-secrets-management.md`.
|
|
115
|
+
- Zero-downtime rotation pattern: publish N+1, wait >= 2 * cache TTL, switch signing to N+1, retire N after refresh-token max-age.
|
|
116
|
+
|
|
117
|
+
## Auth Provider 2026 Landscape — Roll vs Buy
|
|
118
|
+
|
|
119
|
+
Decision rubric: managed for B2B + SSO/SAML/SCIM requirements; self-host when compliance forbids third-party identity OR when cost crosses break-even at scale.
|
|
120
|
+
|
|
121
|
+
| Provider | Sweet Spot |
|
|
122
|
+
|----------|-----------|
|
|
123
|
+
| Clerk | Best DX for React/Next.js consumer apps |
|
|
124
|
+
| Supabase Auth | Postgres-native + RLS-integrated stacks |
|
|
125
|
+
| WorkOS | Enterprise SSO + SCIM + Directory Sync |
|
|
126
|
+
| Auth0 / Okta | Enterprise B2B with mature compliance |
|
|
127
|
+
| Stytch | Passwordless + WebAuthn focus |
|
|
128
|
+
| Better Auth | OSS framework-agnostic, full control |
|
|
129
|
+
| Auth.js (NextAuth.js) | Next.js with minimal external dependency |
|
|
130
|
+
| FusionAuth / Keycloak / Ory | Self-host with full IdP capability |
|
|
131
|
+
|
|
132
|
+
## API Key Design
|
|
133
|
+
|
|
134
|
+
- Prefix convention for secret-scanner detection (`sk_live_*`, `pk_live_*`).
|
|
135
|
+
- Hash-only storage server-side (Argon2id or SHA-256 with per-key salt); never store plaintext.
|
|
136
|
+
- Per-key scope grants (resource + method allowlist).
|
|
137
|
+
- Per-key rate limit; per-key usage analytics with last-used timestamp.
|
|
138
|
+
- Revocation API; rotate quarterly; never log the full key value.
|
|
139
|
+
- For human users, replace API keys with passkeys + short-lived tokens.
|
|
140
|
+
|
|
141
|
+
## Audit Logging for Auth Events
|
|
142
|
+
|
|
143
|
+
Every auth event logged with `actor` (user_id), `target` (resource_id), `ip`, `user_agent`, `result` (success/failure/code), `timestamp`, and `trace_id` for SIEM correlation. Tamper-resistant append-only store; 1-year retention minimum.
|
|
144
|
+
|
|
145
|
+
Required event set: login success, login failure, MFA challenge issued, MFA verified, MFA failed, password reset requested, password reset completed, email change, role/scope grant, role/scope revoke, token issued, token revoked, session terminated, passkey added, passkey removed, step-up auth challenge, step-up auth verified.
|
|
146
|
+
|
|
147
|
+
## Cross-References
|
|
148
|
+
|
|
149
|
+
- `rules/hatch3r-passkey-server.md` — server-side WebAuthn ceremony (paired companion).
|
|
150
|
+
- `rules/hatch3r-ux-states-and-flows.md` — frontend identifier-first login + Conditional UI.
|
|
151
|
+
- `rules/hatch3r-ai-ux-patterns.md` — frontend WebAuthn UX patterns.
|
|
152
|
+
- `rules/hatch3r-api-versioning.md` — OAuth 2.1 in the API-versioning context.
|
|
153
|
+
- `rules/hatch3r-secrets-management.md` — JWT signing key + OAuth client secret rotation cadence.
|
|
154
|
+
- `rules/hatch3r-data-classification.md` — multi-tenant data isolation + BYOK.
|
|
155
|
+
|
|
156
|
+
## References
|
|
157
|
+
|
|
158
|
+
- RFC 9700 — OAuth 2.0 Security Best Current Practice (Jan 2025).
|
|
159
|
+
- RFC 9449 — OAuth 2.0 Demonstrating Proof of Possession (DPoP).
|
|
160
|
+
- RFC 8725 — JSON Web Token Best Current Practice.
|
|
161
|
+
- `draft-ietf-oauth-v2-1` — The OAuth 2.1 Authorization Framework.
|
|
162
|
+
- OpenID Connect Core 1.0 + RP-Initiated Logout 1.0 + Back-Channel Logout 1.0.
|
|
163
|
+
- NIST SP 800-63B-4 — Digital Identity Guidelines: Authentication and Authenticator Management.
|
|
164
|
+
- FAPI 2.0 Final (Feb 2025) — Financial-grade API profiles.
|
|
165
|
+
- AuthZEN Authorization API 1.0 Final (OpenID Foundation, Jan 2026).
|
|
166
|
+
- Google Zanzibar — Consistent, Global Authorization (USENIX ATC 2019).
|
|
@@ -10,6 +10,15 @@ cache_friendly: true
|
|
|
10
10
|
---
|
|
11
11
|
# Component Conventions
|
|
12
12
|
|
|
13
|
+
## Library and Token Detection (Mandatory Pre-Author Step)
|
|
14
|
+
|
|
15
|
+
Before authoring any new UI primitive, complete this scan and reuse > extend > create:
|
|
16
|
+
|
|
17
|
+
- Scan `package.json` for `@radix-ui/*`, shadcn (`components.json`), Tailwind v4, MUI, or Chakra. If a matching primitive exists in those libraries, extend it instead of writing a new one.
|
|
18
|
+
- Locate the token source: `tokens.json` (DTCG spec, 2025.10 revision), `src/styles/tokens.css`, Tailwind `@theme` block (v4), or `tailwind.config.{js,ts}` (v3 fallback). Reference the token by name — never hardcode the resolved value.
|
|
19
|
+
- Map the component library convention before writing files: shadcn projects use `src/components/ui/*`; non-shadcn projects typically use `src/components/primitives/*`. Place new files in the existing directory layout.
|
|
20
|
+
- Cross-reference `rules/hatch3r-design-system-detection.md` for the full detection workflow and tooling.
|
|
21
|
+
|
|
13
22
|
## Structure
|
|
14
23
|
|
|
15
24
|
- Use framework-recommended component syntax (e.g., `<script setup>` for Vue).
|
|
@@ -41,6 +50,20 @@ cache_friendly: true
|
|
|
41
50
|
|
|
42
51
|
## State Patterns (Required)
|
|
43
52
|
|
|
53
|
+
### Four-State Surface Contract
|
|
54
|
+
|
|
55
|
+
Every async view must render all four states. A missing state is a blocker for merge.
|
|
56
|
+
|
|
57
|
+
- **Loading:** skeleton with explicit `width` and `height` matching the final content dimensions to prevent Cumulative Layout Shift (CLS). Generic spinners on content surfaces are insufficient.
|
|
58
|
+
- **Empty:** distinguish three sub-types, each with the matching CTA:
|
|
59
|
+
- Cold-start (no data ever) — onboarding CTA (e.g., "Create your first project").
|
|
60
|
+
- Active-filter (filters/search exclude all data) — clear-filters CTA.
|
|
61
|
+
- No-permission (auth scope blocks access) — request-access CTA.
|
|
62
|
+
- **Error:** show the cause, a retry action, and a fallback path; use a corrective verb ("Try again", "Reload"). Never use "Oops" or generic copy that hides the cause.
|
|
63
|
+
- **Partial:** when some data resolves and some fails, render a banner explaining the gap plus the degraded data plus a retry control for the failed slice.
|
|
64
|
+
|
|
65
|
+
Cross-reference `rules/hatch3r-ux-states-and-flows.md` for the full state-flow specification.
|
|
66
|
+
|
|
44
67
|
### Loading States
|
|
45
68
|
- Use skeleton screens (not spinners) for content areas — match the layout shape of the loaded content.
|
|
46
69
|
- Apply a shimmer/pulse CSS animation on skeletons to indicate activity.
|
|
@@ -88,6 +111,13 @@ cache_friendly: true
|
|
|
88
111
|
- Provide clear success feedback: redirect to the result page or display a success toast.
|
|
89
112
|
- Prevent double submission by disabling the button and ignoring duplicate submit events during pending requests.
|
|
90
113
|
|
|
114
|
+
### Error Recovery
|
|
115
|
+
- Clear inline field errors immediately when the user enters a corrective character — no debounce on the clear path.
|
|
116
|
+
- Re-enable the submit button in real time as the form returns to a valid state.
|
|
117
|
+
- On submit with errors, render an error summary at the top of the form with anchor links to each invalid field; move focus to the summary container, not to the first invalid field.
|
|
118
|
+
- Required attributes on inputs: `autocomplete` (HTML autofill tokens), `inputmode` (matches expected character set), `aria-describedby` (links help/format hints), and `aria-invalid="true"` once invalid.
|
|
119
|
+
- Never use a disabled submit button as the only error signal — disabled state is unreadable to many screen readers and gives no recovery path.
|
|
120
|
+
|
|
91
121
|
### Accessible Labels
|
|
92
122
|
- Every `<input>`, `<select>`, and `<textarea>` must have a visible `<label>` element with a matching `for`/`id` pair.
|
|
93
123
|
- Mark required fields with a visual asterisk (`*`) and screen-reader-only text ("required").
|
|
@@ -5,6 +5,15 @@ alwaysApply: false
|
|
|
5
5
|
---
|
|
6
6
|
# Component Conventions
|
|
7
7
|
|
|
8
|
+
## Library and Token Detection (Mandatory Pre-Author Step)
|
|
9
|
+
|
|
10
|
+
Before authoring any new UI primitive, complete this scan and reuse > extend > create:
|
|
11
|
+
|
|
12
|
+
- Scan `package.json` for `@radix-ui/*`, shadcn (`components.json`), Tailwind v4, MUI, or Chakra. If a matching primitive exists in those libraries, extend it instead of writing a new one.
|
|
13
|
+
- Locate the token source: `tokens.json` (DTCG spec, 2025.10 revision), `src/styles/tokens.css`, Tailwind `@theme` block (v4), or `tailwind.config.{js,ts}` (v3 fallback). Reference the token by name — never hardcode the resolved value.
|
|
14
|
+
- Map the component library convention before writing files: shadcn projects use `src/components/ui/*`; non-shadcn projects typically use `src/components/primitives/*`. Place new files in the existing directory layout.
|
|
15
|
+
- Cross-reference `rules/hatch3r-design-system-detection.md` for the full detection workflow and tooling.
|
|
16
|
+
|
|
8
17
|
## Structure
|
|
9
18
|
|
|
10
19
|
- Use framework-recommended component syntax (e.g., `<script setup>` for Vue).
|
|
@@ -36,6 +45,20 @@ alwaysApply: false
|
|
|
36
45
|
|
|
37
46
|
## State Patterns (Required)
|
|
38
47
|
|
|
48
|
+
### Four-State Surface Contract
|
|
49
|
+
|
|
50
|
+
Every async view must render all four states. A missing state is a blocker for merge.
|
|
51
|
+
|
|
52
|
+
- **Loading:** skeleton with explicit `width` and `height` matching the final content dimensions to prevent Cumulative Layout Shift (CLS). Generic spinners on content surfaces are insufficient.
|
|
53
|
+
- **Empty:** distinguish three sub-types, each with the matching CTA:
|
|
54
|
+
- Cold-start (no data ever) — onboarding CTA (e.g., "Create your first project").
|
|
55
|
+
- Active-filter (filters/search exclude all data) — clear-filters CTA.
|
|
56
|
+
- No-permission (auth scope blocks access) — request-access CTA.
|
|
57
|
+
- **Error:** show the cause, a retry action, and a fallback path; use a corrective verb ("Try again", "Reload"). Never use "Oops" or generic copy that hides the cause.
|
|
58
|
+
- **Partial:** when some data resolves and some fails, render a banner explaining the gap plus the degraded data plus a retry control for the failed slice.
|
|
59
|
+
|
|
60
|
+
Cross-reference `rules/hatch3r-ux-states-and-flows.md` for the full state-flow specification.
|
|
61
|
+
|
|
39
62
|
### Loading States
|
|
40
63
|
- Use skeleton screens (not spinners) for content areas — match the layout shape of the loaded content.
|
|
41
64
|
- Apply a shimmer/pulse CSS animation on skeletons to indicate activity.
|
|
@@ -83,6 +106,13 @@ alwaysApply: false
|
|
|
83
106
|
- Provide clear success feedback: redirect to the result page or display a success toast.
|
|
84
107
|
- Prevent double submission by disabling the button and ignoring duplicate submit events during pending requests.
|
|
85
108
|
|
|
109
|
+
### Error Recovery
|
|
110
|
+
- Clear inline field errors immediately when the user enters a corrective character — no debounce on the clear path.
|
|
111
|
+
- Re-enable the submit button in real time as the form returns to a valid state.
|
|
112
|
+
- On submit with errors, render an error summary at the top of the form with anchor links to each invalid field; move focus to the summary container, not to the first invalid field.
|
|
113
|
+
- Required attributes on inputs: `autocomplete` (HTML autofill tokens), `inputmode` (matches expected character set), `aria-describedby` (links help/format hints), and `aria-invalid="true"` once invalid.
|
|
114
|
+
- Never use a disabled submit button as the only error signal — disabled state is unreadable to many screen readers and gives no recovery path.
|
|
115
|
+
|
|
86
116
|
### Accessible Labels
|
|
87
117
|
- Every `<input>`, `<select>`, and `<textarea>` must have a visible `<label>` element with a matching `for`/`id` pair.
|
|
88
118
|
- Mark required fields with a visual asterisk (`*`) and screen-reader-only text ("required").
|