# ADR-012: Hub PWA Is the Single SSO Gateway for All Employee-Facing PWAs

## Status

Accepted, 2026-06-25.

## Status History

```yaml
status_history:
  - date: 2026-06-25
    status: Proposed
    changed_by: hkl
    reason: Formalising hub-as-SSO pattern that all PWAs depend on
    changed_via: adr-kit (360lm)
  - date: 2026-06-25
    status: Accepted
    changed_by: hkl
    reason: All PWAs authenticate via hub; pattern proven stable
    changed_via: adr-kit (360lm)
```

## Context

360lm has 20+ PWAs. Each needs to know who the logged-in employee is (ID, name, role) to enforce access control and personalise content. Without a central auth point, each PWA would need its own login screen, its own session management, and its own employee lookup — leading to duplicated code and inconsistent UX. The hub (`/hub/`) already has the full employee PIN login flow, the PWA registry, and access control logic.

## Decision

All employee-facing PWAs MUST authenticate via the hub. A PWA that detects no valid session redirects to `/hub/?next=<current-path>` (see ADR-001). After hub login, the hub writes a shared session (cookie or localStorage under a common key) readable by all same-origin PWAs. A PWA reads this session on load to get `{ employee_id, name, role }` without prompting for credentials again.

New PWAs MUST NOT implement their own login screen or their own employee PIN verification. They redirect to hub and read the hub session.

**Decision Maker:** hkl

## Alternatives Considered

- **Each PWA has its own login screen.** Rejected: 20 login screens to maintain; employee must re-login when switching between PWAs; inconsistent UX; duplicated verify_pin calls.
- **Shared login component embedded in each PWA.** Rejected: same duplication problem with an extra layer of indirection; any change to the login flow requires updating all 20 PWAs.
- **Central auth API (separate service, e.g. JWT issuer).** Rejected: over-engineered for the current scale; adds a new service dependency; hub already provides this functionality without a separate service. // ponytail: upgrade trigger=multi-device concurrent sessions needed or token expiry audit required
- **Browser fingerprint / device trust.** Rejected: shared devices make device trust meaningless; unreliable across Android versions.

## Consequences

**Positive:**
- Single login for all PWAs — employee logs into hub once, all PWAs recognise the session.
- One place to update login UX, session format, or access control rules.
- Hub PWA registry controls which PWAs an employee can access (see ADR-016).

**Negative / Trade-offs:**
- Hub is a single point of failure for all PWA auth — if hub is down, no PWA can authenticate new sessions.
- Session format is a shared contract — changing it requires updating all PWAs simultaneously.
- PWAs must handle the case where hub session exists but employee lacks access to that specific PWA.

**Risks and mitigations:**
- Hub down: existing sessions continue to work (session is read from storage, not re-verified on every page load); only new logins are blocked.
- Session format change: always version the session key (e.g., `lm360-session-v2`) and migrate with a fallback read of the old key; deprecate old key after all PWAs are updated.

## Related Decisions

- ADR-001 (hub ?next= redirect) — the redirect mechanic.
- ADR-011 (PIN auth) — the auth method hub uses.
- ADR-016 (hub PWA registry) — hub controls which PWAs are accessible.

## References

- `memory/project_arch.md` — hub PWA description
- `hub/index.html` — session write logic
- `memory/feedback_hub_next_redirect.md` — redirect pattern
