TTL: 2 min was te kort voor handmatig curl-paste-confirm-testen — gebruiker zag 'Pairing verlopen' voor hij kon bevestigen. Bumpt naar 5 min (gelijk aan approved-TTL): nog steeds tight voor security, ruim voor menselijke reactie. - app/api/auth/pair/start/route.ts: PENDING_TTL_MS 120s → 300s - lib/auth/pair-cookie.ts: MAX_AGE_SECONDS 120 → 300 - __tests__/api/pair-start.test.ts: maxAge en expires_at-window meegegroeid Kleuren: bevestigingspagina gebruikte bg-destructive/10 + text-destructive- foreground — beide lichte kleuren, te weinig contrast. Vervangen door MD3 container-tokens (zelfde patroon als components/auth/auth-form.tsx): - error-state: bg-error-container + text-error-container-foreground + border-l-4 border-error - approved-state: bg-success-container + foreground + accent-border - cancelled-state: bg-surface-container-high + neutral foreground Quality gates: lint 0 errors, tsc clean, vitest 139/139. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
33 lines
1.1 KiB
TypeScript
33 lines
1.1 KiB
TypeScript
// ST-1002: HttpOnly pre-auth cookie voor de QR-pairing desktop-side.
|
|
//
|
|
// Wordt gezet door /api/auth/pair/start (ST-1003), gelezen door
|
|
// /api/auth/pair/stream/[id] (ST-1004) en /api/auth/pair/claim (ST-1006),
|
|
// en gewist op claim of cancel. Path-scoped naar /api/auth/pair zodat de
|
|
// cookie niet naar andere routes lekt.
|
|
|
|
import { cookies } from 'next/headers'
|
|
|
|
const COOKIE_NAME = 's4m_pair'
|
|
const MAX_AGE_SECONDS = 300 // gelijk aan pending-TTL van LoginPairing (5 min)
|
|
const COOKIE_PATH = '/api/auth/pair'
|
|
|
|
export async function setPairCookie(desktopToken: string): Promise<void> {
|
|
const jar = await cookies()
|
|
jar.set(COOKIE_NAME, desktopToken, {
|
|
httpOnly: true,
|
|
secure: process.env.NODE_ENV === 'production',
|
|
sameSite: 'lax',
|
|
path: COOKIE_PATH,
|
|
maxAge: MAX_AGE_SECONDS,
|
|
})
|
|
}
|
|
|
|
export async function readPairCookie(): Promise<string | null> {
|
|
const jar = await cookies()
|
|
return jar.get(COOKIE_NAME)?.value ?? null
|
|
}
|
|
|
|
export async function clearPairCookie(): Promise<void> {
|
|
const jar = await cookies()
|
|
jar.delete({ name: COOKIE_NAME, path: COOKIE_PATH })
|
|
}
|