4 · Accessibility & cookie compliance
Objective — run the WCAG 2.1 AA checks (automated scanners + manual verification) and build the GDPR/CCPA cookie inventory with consent gating that actually blocks non-essential cookies — the audits that keep the app usable for everyone and keep it legal.
Background
Section titled “Background”The audits that keep the app usable for everyone — and keep it legal. Automated tools catch the deterministic failures; the judgment-heavy checks (focus order, banner behavior) still need human eyes.
1. Audit accessibility (WCAG 2.1 AA)
Section titled “1. Audit accessibility (WCAG 2.1 AA)”Run automated scanners (WAVE, axe DevTools) on key pages, then verify by hand what tools can’t.
| Check | Requirement |
|---|---|
| Keyboard nav | Logical tab order, visible focus, no traps |
| Focus indicator | Never removed globally; :focus { outline: 2px solid … } |
| Images | Descriptive alt; alt="" for decorative |
| Form inputs | Every visible input has a <label for> or aria-label |
| Color contrast | 4.5:1 normal text · 3:1 large text & UI |
| Icon buttons | aria-label or .sr-only text |
| Structure | Semantic landmarks, skip link, sequential headings |
Agent-runnable greps for the deterministic failures (the scanners catch the rest):
# Images missing alt textgrep -rn "<img" resources/views/ --include="*.blade.php" | grep -v "alt=" || echo "OK all <img> have alt"
# Inputs that may lack a label (excluding hidden)grep -rn "<input" resources/views/ --include="*.blade.php" | grep -v 'type="hidden"' | head -20
# Icon-only elements missing an accessible namegrep -rn 'class=".*fa-' resources/views/ --include="*.blade.php" | grep -v "aria-" || echo "OK icons labelled"
# Landmark / semantic elements present in layoutsgrep -rn "<main\|<nav\|<header\|<footer" resources/views/layouts/ --include="*.blade.php"Then add visible focus styles (never remove the outline globally) and a skip link to #main-content.
-
Scan key pages, then verify the manual checks by hand against every row of the table above.
- ✅ Automated scanners are clean and the manual checks (tab order, focus, contrast) all pass.
2. Verify cookie compliance (GDPR / CCPA)
Section titled “2. Verify cookie compliance (GDPR / CCPA)”Inventory every cookie, then verify consent actually gates the non-essential ones.
-
Inventory all cookies (name, expiry,
HttpOnly,Secure,SameSite) and classify them Essential / Functional / Analytics / Marketing.- ✅ Every cookie is listed with its attributes and a category.
-
Verify session security — session cookies need
HttpOnly=true,Secure=true,SameSite=lax.Terminal window php artisan tinker --execute="echo json_encode(\Illuminate\Support\Arr::only(config('session'), ['secure','http_only','same_site']));"# Expected: {"secure":true,"http_only":true,"same_site":"lax"} (production/staging APP_URL=https://…)- ✅ Runtime session config reports
secure,http_only, andsame_site=lax(not justenv()lines inconfig/session.php).
- ✅ Runtime session config reports
-
Scan for custom cookies in app code and enforce the lifetime ceilings. Every custom cookie must carry the same security attributes as the session cookie.
Terminal window grep -rnE "Cookie::make|cookie\(|setcookie|->cookie\(" app/ routes/ --include="*.php"# Expected: each hit uses HttpOnly + Secure + SameSite; none sets a raw long-lived plaintext cookieLifetime ceilings:
Cookie Max lifetime Session 120 min Remember-me 30 days Consent 1 year - ✅ Every custom cookie sets
HttpOnly+Secure+SameSite, and no cookie exceeds its lifetime ceiling (session ≤ 120 min, remember-me ≤ 30 days, consent ≤ 1 year).
- ✅ Every custom cookie sets
-
Test the banner in incognito: only essential cookies pre-consent; “Accept All” loads analytics/marketing; “Reject” keeps them blocked; preferences are changeable later.
- ✅ Pre-consent loads only essential cookies; Accept/Reject behave correctly; preferences are editable later.
-
Use one consent mechanism only — if you use a third-party manager, disable the built-in one. Confirm the cookie policy page matches reality.
- ✅ A single consent mechanism is active and the cookie policy page matches the real inventory.
Checklist
Section titled “Checklist”Do not mark this step done until every box below is checked.
- 👤 WCAG 2.1 AA passes — scanners clean; keyboard, focus, contrast, and structure verified by hand.
- 🤖 Cookies inventoried — every cookie listed with attributes and a category.
- 🤖 Session cookies secure — runtime
config('session')hassecure,http_only,same_site=lax. - 👤 Banner gates non-essential — incognito test confirms Accept/Reject and editable preferences.
- 🔀 One consent mechanism — built-in disabled if a third-party manager is used; policy page matches.