Aller au contenu

Story AUTH-012: Signed-link verification rate-limiting (shared Redis)

Module: identity Slice: arch §0.1 AUTH-006 (rate-limit Redis transverse, shared with CP-005 / NOTIF-004) Side: [BACKEND] Version target: V0 — v0.1.0 Priority: 12 Depends on: AUTH-005; the shared Redis rate-limit primitive introduced by CP-005 / NOTIF-004 Can develop concurrently with: AUTH-010, AUTH-011 Merge order: After AUTH-005 Estimated complexity: S PRD User Stories: V0 envelope AUTH-006 (production hardening — rate-limit) Wireframe: N/A — backend only (any throttle message shown to the customer is rendered by the CP module)


Objective

The v0.0.x signed-link verification has no throughput protection. v0.1.0 adds a cross-cutting Redis rate-limit on link verification, sharing the same rate-limit primitive that CP-005 and NOTIF-004 introduce. Together with the per-link attempt-limit (AUTH-011), this caps brute-force pressure on the SHA-256 token lookup (which has no HMAC in V0, so rate-limit is the main brute-force defence — arch §0.2).


Backend Scope

Entities

No new tables. Rate-limit counters live in Redis (shared primitive), not in signed_links.

Service Layer

  • Apply a Redis-backed rate-limit to verifyLink (and the challenge submit path) keyed by a coarse client identifier (e.g. IP block) and/or token, reusing the shared rate-limit component from CP-005 / NOTIF-004.
  • When the limit is exceeded: reject with HTTP 429 (Retry-After) without consuming a per-link challenge attempt.
  • The rate-limit is a performance/abuse guard fronting the < 50 ms p95 verification hot path (AUTH-NFR-11); a Redis outage must degrade safely (fail-open on rate-limit is acceptable since the per-link attempt-limit from AUTH-011 and link state remain authoritative — arch R4).
  • Optionally trigger link revocation on egregious abuse (defence-in-depth), consistent with the attempt-limit path in AUTH-011.

API Endpoints

None new. Applies to the existing CP-boundary verification/challenge calls.

Validation Rules

  • Rate-limit thresholds and window come from shared configuration (aligned with CP-005 / NOTIF-004).
  • A 429 must not consume a per-link attempt (those are independent guards).

Multi-Tenant Considerations

Rate-limit keys must not allow one tenant's traffic to exhaust another tenant's budget; key by client + token (which resolves to a single tenant). AUTH stays on the platform datasource; Redis is the shared cache layer.

Audit & Logging

  • Reuse existing signed-link audit events; excessive-rate rejections may be counted in metrics/observability (the v0.1.0 observability work is an OP-module concern). If abuse triggers a revoke, AUTH_LINK_PERMANENTLY_REVOKED / AUTH_LINK_REJECTED_REVOKED apply.

Frontend Scope

N/A — backend only. Any "too many requests, retry later" message shown to the customer is rendered by the CP module using the standard low-network / retry copy.

UI States (ALL REQUIRED)

N/A — backend only.


Acceptance Criteria

AC-001: Excessive verification requests are rate-limited
Given a client exceeds the configured verification rate within the window
When further verify/challenge requests arrive
Then they are rejected with HTTP 429 and a Retry-After hint
And no per-link challenge attempt is consumed by the 429
AC-002: The rate-limit shares the CP-005 / NOTIF-004 primitive
Given the shared Redis rate-limit component
When AUTH applies it to verifyLink
Then it uses the same primitive/configuration as CP-005 and NOTIF-004 (no separate bespoke limiter)
AC-003: Redis outage degrades safely
Given Redis is unavailable
When a verification request arrives
Then the rate-limit fails open (does not block legitimate verification)
And the per-link attempt-limit (AUTH-011) and link state remain authoritative

Compliance Rules

  • No new compliance article. Rate-limiting supports the CIMA cybersecurity posture (AUTH-OQ-03, open — does not block this story).
  • [LEGAL-REVIEW]: authentication mechanism only (red flag #5 unchanged).

Standards & Conventions

  • docs/standards/connectivity-low-bandwidth.md (retry / 429 semantics).
  • docs/standards/java-spring-guidelines.md, docs/standards/api-guidelines.md.
  • docs/standards/critical-rules.md (tenant isolation in rate-limit keys).

Testing Requirements

Unit Tests

  • Over-threshold → 429; a 429 does not consume a per-link attempt.
  • Key derivation does not let one tenant exhaust another's budget.

Integration Tests

  • Redis-backed limiter (Testcontainers Redis): burst of verify calls → 429 after the threshold.
  • Redis down → fail-open; verification still works; per-link attempt-limit still enforced.

What QA Will Validate

  • Verification is throttled under abuse; the limiter is the shared one; a Redis outage does not lock out legitimate customers; tenants are isolated in the rate-limit keyspace.

Out of Scope

  • The shared rate-limit primitive itself — introduced by CP-005 / NOTIF-004; this story consumes it.
  • Expiry — AUTH-010; per-link attempt-limit — AUTH-011.
  • HMAC + anti-replay — V1.
  • Observability dashboards / metrics for the back-office — OP module (v0.1.0 observability).

Definition of Done

  • [ ] Redis rate-limit applied to signed-link verification + challenge submit
  • [ ] Over-threshold → 429 with Retry-After; no per-link attempt consumed
  • [ ] Uses the shared CP-005 / NOTIF-004 rate-limit primitive
  • [ ] Redis outage fails open; per-link attempt-limit remains authoritative
  • [ ] Rate-limit keyspace isolates tenants
  • [ ] Unit + integration tests written and passing
  • [ ] Tenant isolation verified (key derivation; platform DB)
  • [ ] No silent failures (graceful degradation on Redis outage)