Opus finding
verifyTokenDetailed reads HMAC secret before validating token shape, leaking malformed-token failure mode behind misconfiguration
lowmaintainabilitymedium
- apps/web/lib/optin-token.ts:71-80
verifyTokenDetailed calls getSecret() before computing/comparing anything. If OPTIN_HMAC_SECRET is unset in production, every opt-in click — even with a clearly malformed token like 'garbage' — throws a 500 rather than returning a clean 400 'Invalid link'. The route's tests assume the secret is always present, but in a misconfigured deploy this turns user-visible 400s into 500s and could mask the real problem (missing env var) behind generic Next error pages. This is intentional per design ('throws if OPTIN_HMAC_SECRET is missing at verify time' is tested), but it's worth noting that handleOptIn does not catch this throw, so misconfiguration becomes a 500 rather than a graceful error page.
Recommendation
Either (a) catch the missing-secret throw at the route layer and render a generic 500 error page consistent with the rest of the design, or (b) document this contract explicitly in route.ts so operators understand that secret rotation/unset means HTTP 500 across all opt-in links.