Keycloak cookie SSR auth + admin role gate (hooks.server.ts) #2

Closed
opened 2026-04-25 21:58:49 +00:00 by forgejo_admin · 4 comments

Type

Feature

Lineage

Parent / coordinator. Decomposed 2026-05-03 per scope review (review-1132-2026-05-03 verdict: NEEDS_REFINEMENT — over the 5-minute rule, recommend split). Hard depends on forgejo_admin/westside-admin#6 (scaffolding, closed) and forgejo_admin/pal-e-platform#301 (Keycloak client westside-admin created in realm — done 2026-05-03 via sop-keycloak-client-creation).

Repo

forgejo_admin/westside-admin

User Story

story-westside-admin-admin-row-crud. Implements the Keycloak admin gate safety constraint per arch-deployment-westside-admin and arch-dataflow-westside-admin Flow 1.

Context

westside-admin sits behind a public Tailscale funnel. Per feedback_funnel_requires_auth (driving rule from the 2026-04-10 PII leak retro), every funnel-exposed app must have airtight auth documented before merge. Cookie SSR model: HttpOnly+Secure cookie holds AES-GCM ciphertext of tokens, JWT validated server-side per request via Keycloak's JWKS endpoint, no Bearer token in browser, no XSS exfiltration path.

The Keycloak westside-admin confidential OIDC client was created in the westside-basketball realm on 2026-05-03 via sop-keycloak-client-creation (admin-console-driven). The client_secret is landing via forgejo_admin/pal-e-deployments#147 (QA-approved, awaiting merge). All 5 env vars (KEYCLOAK_URL, KEYCLOAK_REALM, KEYCLOAK_CLIENT_ID, KEYCLOAK_CLIENT_SECRET, COOKIE_SIGNING_KEY) will be present in the cluster Secret once #147 merges.

No internal prior art — westside-contracts has zero Keycloak code (uses signed-token URLs); westside-app uses browser-side keycloak-js (adapter-static). This decomposition is the new pattern reference for adapter-node SSR-Keycloak consumers.

Decomposition (consolidated spec)

This parent ticket is non-executable — its work is delivered through 4 sub-tickets that each live within the 5-minute rule:

Sub Issue Scope Depends on
1 #14 keycloak.ts lib (JWKS cache, JWT verify, AES-GCM, OIDC state, token refresh) + unit tests #6 (closed), #pal-e-deployments-147 (env vars)
2 #15 hooks.server.ts handle hook + app.d.ts Locals extension #14
3 #16 /auth/login, /auth/callback, /auth/logout endpoints #14
4 #17 (unauthorized) route group 403 page #15, #16

Sub-tickets carry their own File Targets, Acceptance Criteria, Test Expectations, and Constraints. The list below is the rollup of acceptance criteria across all 4 sub-tickets — this parent closes only when every sub-ticket's PR is merged AND the integration ACs are verified end-to-end.

File Targets (rollup — see sub-tickets for individual scopes)

Create across the 4 sub-tickets:

  • src/lib/server/keycloak.ts (#14)
  • src/lib/server/keycloak.test.ts (#14)
  • src/hooks.server.ts (#15)
  • src/app.d.ts extension (#15)
  • src/routes/auth/login/+server.ts (#16)
  • src/routes/auth/callback/+server.ts (#16)
  • src/routes/auth/logout/+server.ts (#16)
  • src/routes/(unauthorized)/+page.svelte (#17)
  • src/routes/(unauthorized)/+layout.svelte (#17)

Update:

  • package.json — add jose (#14)

Acceptance Criteria (integration rollup)

  • Anonymous request to / 302s to Keycloak /authorize with PKCE + a fresh state parameter (signed with COOKIE_SIGNING_KEY, stored in transient HttpOnly cookie).
  • Successful Keycloak callback validates state matches transient cookie BEFORE code exchange — mismatched/missing state returns 400, never proceeds.
  • Code exchange returns tokens; tokens AES-GCM encrypted and stored in HttpOnly + Secure + SameSite=Lax session cookie (browser cannot read raw JWT via JS).
  • Authenticated user with admin role passes through to the page.
  • Authenticated user WITHOUT admin role sees the 403 page with logout button (NOT redirected away).
  • JWT signature validated against JWKS on every request; JWKS cached with 10-minute TTL.
  • JWT validation also checks: audience = westside-admin, exp not passed, iss = ${KEYCLOAK_URL}/realms/westside-basketball.
  • Tokens refreshed server-side when access_token within 30s of expiry.
  • JWKS-unreachable resilience (added per scope review): cold cache + JWKS down → callers can surface HTTP 503; warm cache within TTL → fall back; warm-but-stale cache + JWKS down → log warning + reject with 503-typed error.
  • No tokens, refresh tokens, or cookie ciphertext appear in any log line (verify via grep over server logs after running auth flow).
  • All required env vars (KEYCLOAK_URL, KEYCLOAK_REALM, KEYCLOAK_CLIENT_ID, KEYCLOAK_CLIENT_SECRET, COOKIE_SIGNING_KEY) documented in README.
  • SSO verified: signing into westside-app then opening westside-admin requires no second login form.

Test Expectations

  • Per-sub-ticket unit tests live in #14.
  • End-to-end integration tested manually after all 4 sub-tickets merge: full login flow against real Keycloak in staging.
  • SSO test: open westside-app, sign in, then open westside-admin in same browser — expect zero login form.
  • Log audit: tail server logs through one full auth flow, grep for token/cookie material — must be empty.

Constraints (rollup)

  • HttpOnly + Secure + SameSite=Lax (NOT Strict — Strict breaks the OIDC redirect).
  • Cookie name: westside_admin_session.
  • Token contents in cookie: AES-GCM encrypted using COOKIE_SIGNING_KEY env var.
  • Never log access_token, refresh_token, or cookie value.
  • Redirect URI in Keycloak client must be https://westside-admin.tail5b443a.ts.net/auth/callback (exact match — no /*).
  • OIDC state parameter is non-negotiable — funnel-exposed apps without state validation are vulnerable to CSRF on the callback.

Checklist

  • All 4 sub-tickets reviewed (todo→next_up gate per feedback_review_before_dispatch)
  • All 4 sub-tickets dispatched in dependency order (#14 first, then #15+#16 parallel, then #17)
  • All 4 PRs merged
  • Integration ACs verified end-to-end
  • PR descriptions include funnel-auth review per feedback_funnel_requires_auth
  • project-westside-admin — project this work is for
  • arch-dataflow-westside-admin — Flow 1 (the auth sequence this implements)
  • arch-deployment-westside-admin — deployment side
  • feedback_funnel_requires_auth — driving safety constraint
  • sop-keycloak-client-creation — Keycloak side (done)
  • forgejo_admin/pal-e-platform#301 — SOP authoring ticket
  • forgejo_admin/pal-e-deployments#147 — env-var landing PR (must merge before integration ACs run)
  • forgejo_admin/westside-admin#14 — sub-task 1 (keycloak.ts lib)
  • forgejo_admin/westside-admin#15 — sub-task 2 (hooks.server.ts)
  • forgejo_admin/westside-admin#16 — sub-task 3 (auth endpoints)
  • forgejo_admin/westside-admin#17 — sub-task 4 (403 page)
  • review-1132-2026-05-03 — scope review that drove the decomposition
### Type Feature ### Lineage Parent / coordinator. **Decomposed 2026-05-03** per scope review (review-1132-2026-05-03 verdict: NEEDS_REFINEMENT — over the 5-minute rule, recommend split). Hard depends on `forgejo_admin/westside-admin#6` (scaffolding, closed) and `forgejo_admin/pal-e-platform#301` (Keycloak client `westside-admin` created in realm — done 2026-05-03 via `sop-keycloak-client-creation`). ### Repo `forgejo_admin/westside-admin` ### User Story `story-westside-admin-admin-row-crud`. Implements the **Keycloak admin gate** safety constraint per `arch-deployment-westside-admin` and `arch-dataflow-westside-admin` Flow 1. ### Context westside-admin sits behind a public Tailscale funnel. Per `feedback_funnel_requires_auth` (driving rule from the 2026-04-10 PII leak retro), every funnel-exposed app must have airtight auth documented before merge. Cookie SSR model: HttpOnly+Secure cookie holds AES-GCM ciphertext of tokens, JWT validated server-side per request via Keycloak's JWKS endpoint, no Bearer token in browser, no XSS exfiltration path. The Keycloak `westside-admin` confidential OIDC client was created in the `westside-basketball` realm on 2026-05-03 via `sop-keycloak-client-creation` (admin-console-driven). The client_secret is landing via `forgejo_admin/pal-e-deployments#147` (QA-approved, awaiting merge). All 5 env vars (`KEYCLOAK_URL`, `KEYCLOAK_REALM`, `KEYCLOAK_CLIENT_ID`, `KEYCLOAK_CLIENT_SECRET`, `COOKIE_SIGNING_KEY`) will be present in the cluster Secret once #147 merges. **No internal prior art** — westside-contracts has zero Keycloak code (uses signed-token URLs); westside-app uses browser-side `keycloak-js` (adapter-static). This decomposition is the new pattern reference for adapter-node SSR-Keycloak consumers. ### Decomposition (consolidated spec) This parent ticket is **non-executable** — its work is delivered through 4 sub-tickets that each live within the 5-minute rule: | Sub | Issue | Scope | Depends on | |-----|-------|-------|------------| | 1 | `#14` | `keycloak.ts` lib (JWKS cache, JWT verify, AES-GCM, OIDC state, token refresh) + unit tests | #6 (closed), #pal-e-deployments-147 (env vars) | | 2 | `#15` | `hooks.server.ts` handle hook + `app.d.ts` Locals extension | #14 | | 3 | `#16` | `/auth/login`, `/auth/callback`, `/auth/logout` endpoints | #14 | | 4 | `#17` | `(unauthorized)` route group 403 page | #15, #16 | Sub-tickets carry their own File Targets, Acceptance Criteria, Test Expectations, and Constraints. The list below is the **rollup** of acceptance criteria across all 4 sub-tickets — this parent closes only when every sub-ticket's PR is merged AND the integration ACs are verified end-to-end. ### File Targets (rollup — see sub-tickets for individual scopes) Create across the 4 sub-tickets: - `src/lib/server/keycloak.ts` (#14) - `src/lib/server/keycloak.test.ts` (#14) - `src/hooks.server.ts` (#15) - `src/app.d.ts` extension (#15) - `src/routes/auth/login/+server.ts` (#16) - `src/routes/auth/callback/+server.ts` (#16) - `src/routes/auth/logout/+server.ts` (#16) - `src/routes/(unauthorized)/+page.svelte` (#17) - `src/routes/(unauthorized)/+layout.svelte` (#17) Update: - `package.json` — add `jose` (#14) ### Acceptance Criteria (integration rollup) - [ ] Anonymous request to `/` 302s to Keycloak `/authorize` with PKCE + a fresh `state` parameter (signed with COOKIE_SIGNING_KEY, stored in transient HttpOnly cookie). - [ ] Successful Keycloak callback validates `state` matches transient cookie BEFORE code exchange — mismatched/missing state returns 400, never proceeds. - [ ] Code exchange returns tokens; tokens AES-GCM encrypted and stored in HttpOnly + Secure + SameSite=Lax session cookie (browser cannot read raw JWT via JS). - [ ] Authenticated user with `admin` role passes through to the page. - [ ] Authenticated user WITHOUT `admin` role sees the 403 page with logout button (NOT redirected away). - [ ] JWT signature validated against JWKS on every request; JWKS cached with 10-minute TTL. - [ ] JWT validation also checks: audience = `westside-admin`, exp not passed, iss = `${KEYCLOAK_URL}/realms/westside-basketball`. - [ ] Tokens refreshed server-side when access_token within 30s of expiry. - [ ] **JWKS-unreachable resilience** (added per scope review): cold cache + JWKS down → callers can surface HTTP 503; warm cache within TTL → fall back; warm-but-stale cache + JWKS down → log warning + reject with 503-typed error. - [ ] No tokens, refresh tokens, or cookie ciphertext appear in any log line (verify via grep over server logs after running auth flow). - [ ] All required env vars (KEYCLOAK_URL, KEYCLOAK_REALM, KEYCLOAK_CLIENT_ID, KEYCLOAK_CLIENT_SECRET, COOKIE_SIGNING_KEY) documented in README. - [ ] SSO verified: signing into westside-app then opening westside-admin requires no second login form. ### Test Expectations - Per-sub-ticket unit tests live in #14. - End-to-end integration tested manually after all 4 sub-tickets merge: full login flow against real Keycloak in staging. - SSO test: open westside-app, sign in, then open westside-admin in same browser — expect zero login form. - Log audit: tail server logs through one full auth flow, grep for token/cookie material — must be empty. ### Constraints (rollup) - HttpOnly + Secure + SameSite=Lax (NOT Strict — Strict breaks the OIDC redirect). - Cookie name: `westside_admin_session`. - Token contents in cookie: AES-GCM encrypted using `COOKIE_SIGNING_KEY` env var. - Never log access_token, refresh_token, or cookie value. - Redirect URI in Keycloak client must be `https://westside-admin.tail5b443a.ts.net/auth/callback` (exact match — no `/*`). - OIDC `state` parameter is non-negotiable — funnel-exposed apps without state validation are vulnerable to CSRF on the callback. ### Checklist - [ ] All 4 sub-tickets reviewed (todo→next_up gate per `feedback_review_before_dispatch`) - [ ] All 4 sub-tickets dispatched in dependency order (#14 first, then #15+#16 parallel, then #17) - [ ] All 4 PRs merged - [ ] Integration ACs verified end-to-end - [ ] PR descriptions include funnel-auth review per `feedback_funnel_requires_auth` ### Related - `project-westside-admin` — project this work is for - `arch-dataflow-westside-admin` — Flow 1 (the auth sequence this implements) - `arch-deployment-westside-admin` — deployment side - `feedback_funnel_requires_auth` — driving safety constraint - `sop-keycloak-client-creation` — Keycloak side (done) - `forgejo_admin/pal-e-platform#301` — SOP authoring ticket - `forgejo_admin/pal-e-deployments#147` — env-var landing PR (must merge before integration ACs run) - `forgejo_admin/westside-admin#14` — sub-task 1 (keycloak.ts lib) - `forgejo_admin/westside-admin#15` — sub-task 2 (hooks.server.ts) - `forgejo_admin/westside-admin#16` — sub-task 3 (auth endpoints) - `forgejo_admin/westside-admin#17` — sub-task 4 (403 page) - `review-1132-2026-05-03` — scope review that drove the decomposition
Author
Owner

Scope Review: NEEDS_REFINEMENT

Review note: review-1090-2026-04-25

Strong template, all sections present, file targets correct for SvelteKit, dependencies map cleanly to scaffolding (#6) and pal-e-platform Keycloak client (#301). Auth model (HttpOnly cookie SSR + AES-encrypted cookie + JWKS validation) is the right call for a funnel-exposed admin app per feedback_funnel_requires_auth.

Issues to fix before todo

  • Traceability backing notes missingproject-westside-admin, story-westside-admin-admin-row-crud, arch-hooks-server, arch-dataflow-westside-admin, arch-deployment-westside-admin do not exist in pal-e-docs. The body references arch-dataflow-westside-admin Flow 1 as the source of truth diagram — this is a hard blocker for the dev agent. [SCOPE]
  • Public vs confidential client unresolved in companion ticket pal-e-platform#301 — changes whether KEYCLOAK_CLIENT_SECRET is needed here. Resolve #301 first. [SCOPE]

Body refinements

  • Add AC for AES cookie ciphertext (cookie payload is not raw JWT).
  • Add AC for OIDC state parameter generation + validation (CSRF defense — currently absent).
  • Promote "no tokens in logs" from checklist to AC.
  • Add Env Vars subsection: KEYCLOAK_URL, KEYCLOAK_REALM, KEYCLOAK_CLIENT_ID, KEYCLOAK_CLIENT_SECRET (if confidential), COOKIE_SIGNING_KEY, plus JWKS URL construction note.
  • Require code comment on SameSite=Lax rationale (prevent future "hardening" regression).

Decomposition

7 files + 7 ACs + AES cookie crypto + JWT verify + OIDC state CSRF exceeds the 5-minute rule. Recommend route to skill-decompose-ticket with this split:

  • 2a: src/lib/server/keycloak.ts + src/app.d.ts (pure library, unit-testable)
  • 2b: src/hooks.server.ts (handle hook + role gate)
  • 2c: src/routes/auth/callback/+server.ts + auth/logout/+server.ts (OIDC flow + state validation)
  • 2d: src/routes/(unauthorized)/+page.svelte (UI only)

[DECOMPOSE] recommended; tight coupling means accepting as-oversized with a second-pass budget is also defensible — Ava's call.

Prior art

westside-app uses browser-side keycloak-js (do NOT copy). westside-contracts is adapter-node — dev agent should grep it for any existing SSR auth helper before writing keycloak.ts from scratch.

## Scope Review: NEEDS_REFINEMENT Review note: `review-1090-2026-04-25` Strong template, all sections present, file targets correct for SvelteKit, dependencies map cleanly to scaffolding (#6) and pal-e-platform Keycloak client (#301). Auth model (HttpOnly cookie SSR + AES-encrypted cookie + JWKS validation) is the right call for a funnel-exposed admin app per `feedback_funnel_requires_auth`. ### Issues to fix before todo - **Traceability backing notes missing** — `project-westside-admin`, `story-westside-admin-admin-row-crud`, `arch-hooks-server`, `arch-dataflow-westside-admin`, `arch-deployment-westside-admin` do not exist in pal-e-docs. The body references `arch-dataflow-westside-admin` Flow 1 as the source of truth diagram — this is a hard blocker for the dev agent. `[SCOPE]` - **Public vs confidential client unresolved** in companion ticket pal-e-platform#301 — changes whether `KEYCLOAK_CLIENT_SECRET` is needed here. Resolve #301 first. `[SCOPE]` ### Body refinements - Add AC for AES cookie ciphertext (cookie payload is not raw JWT). - Add AC for OIDC `state` parameter generation + validation (CSRF defense — currently absent). - Promote "no tokens in logs" from checklist to AC. - Add Env Vars subsection: `KEYCLOAK_URL`, `KEYCLOAK_REALM`, `KEYCLOAK_CLIENT_ID`, `KEYCLOAK_CLIENT_SECRET` (if confidential), `COOKIE_SIGNING_KEY`, plus JWKS URL construction note. - Require code comment on SameSite=Lax rationale (prevent future "hardening" regression). ### Decomposition 7 files + 7 ACs + AES cookie crypto + JWT verify + OIDC state CSRF exceeds the 5-minute rule. Recommend route to `skill-decompose-ticket` with this split: - 2a: `src/lib/server/keycloak.ts` + `src/app.d.ts` (pure library, unit-testable) - 2b: `src/hooks.server.ts` (handle hook + role gate) - 2c: `src/routes/auth/callback/+server.ts` + `auth/logout/+server.ts` (OIDC flow + state validation) - 2d: `src/routes/(unauthorized)/+page.svelte` (UI only) `[DECOMPOSE]` recommended; tight coupling means accepting as-oversized with a second-pass budget is also defensible — Ava's call. ### Prior art westside-app uses browser-side keycloak-js (do NOT copy). westside-contracts is adapter-node — dev agent should grep it for any existing SSR auth helper before writing `keycloak.ts` from scratch.
Author
Owner

Scope Review: READY (re-review)

Review note: review-1090-2026-04-25-v2
Previous: review-1090-2026-04-25 (NEEDS_REFINEMENT)

All v1 recommendations resolved:

  • [BODY] AES ciphertext AC -- present (AC#3)
  • [BODY] OIDC state CSRF -- present and strengthened (AC#1 generation + AC#2 validate-before-exchange)
  • [BODY] Token leakage grep AC -- present (AC#8, promoted from checklist)
  • [BODY] Env var enumeration with JWKS URL construction -- present in Context
  • [SCOPE] project-westside-admin, story-westside-admin-admin-row-crud, arch-dataflow-westside-admin (with Flow 1), arch-deployment-westside-admin -- all exist
  • [DECOMPOSE] Oversize acknowledged with reasoned defense (tight coupling) and escalation path (split into 4 sub-tickets if dev agent runs over)

Residual minor: no standalone arch-hooks-server note, but arch-dataflow-westside-admin Flow 1 is the de-facto source of truth for the hook flow. Not a blocker.

Ticket clears the backlog -> todo review gate. Do not advance to next_up until hard dependencies clear: #6 (scaffolding) merged + pal-e-platform#301 (Keycloak client + public-vs-confidential decision) finalized.

## Scope Review: READY (re-review) Review note: `review-1090-2026-04-25-v2` Previous: `review-1090-2026-04-25` (NEEDS_REFINEMENT) All v1 recommendations resolved: - [BODY] AES ciphertext AC -- present (AC#3) - [BODY] OIDC state CSRF -- present and strengthened (AC#1 generation + AC#2 validate-before-exchange) - [BODY] Token leakage grep AC -- present (AC#8, promoted from checklist) - [BODY] Env var enumeration with JWKS URL construction -- present in Context - [SCOPE] project-westside-admin, story-westside-admin-admin-row-crud, arch-dataflow-westside-admin (with Flow 1), arch-deployment-westside-admin -- all exist - [DECOMPOSE] Oversize acknowledged with reasoned defense (tight coupling) and escalation path (split into 4 sub-tickets if dev agent runs over) Residual minor: no standalone `arch-hooks-server` note, but `arch-dataflow-westside-admin` Flow 1 is the de-facto source of truth for the hook flow. Not a blocker. Ticket clears the backlog -> todo review gate. Do not advance to next_up until hard dependencies clear: #6 (scaffolding) merged + pal-e-platform#301 (Keycloak client + public-vs-confidential decision) finalized.
Author
Owner

Scope Review: NEEDS_REFINEMENT

Review note: review-1132-2026-05-03

Scope is technically sound and the issue body is high quality, but it's over the 5-minute rule by its own admission, has two label/arch-note gaps, and the "prior art" hint is misleading.

Issues:

  • [LABEL] Board item #1132 carries story:superuser-onboard-service; project Safety Constraints requires story:admin-row-crud (mirrored item on board-westside-admin already uses this). Swap the label.
  • [SCOPE] arch:keycloak label has no backing note in pal-e-docs. Same gap exists on board item #1096 (pal-e-platform#301). Decide create-now vs defer.
  • [BODY] "Prior art: westside-contracts may have SSR auth helpers" is misleading — westside-contracts has zero Keycloak code (signed-token URLs only); westside-app uses browser-side keycloak-js (adapter-static). Implement from scratch using jose.
  • [BODY] Optional: add a JWKS-unreachable resilience AC.
  • [DECOMPOSE] 6 new files + 10 AC + crypto + OIDC state + funnel-auth critical path. Over the 5-min rule. The 4-way split proposed in the issue body (keycloak.ts lib / hooks.server.ts+app.d.ts / auth callback+logout / 403 page) is sound. Ava's call: accept oversized with dev agent on standby, or route to skill-decompose-ticket.

Sequencing note: Do not move to in_progress until pal-e-deployments#147 is merged and ArgoCD has synced the secret — otherwise integration / SSO ACs cannot be validated.

Verified ground truth:

  • All 6 file targets do not yet exist (correct, to create); app.d.ts and package.json exist as expected; adapter is @sveltejs/adapter-node; src/lib/server/ exists and is empty.
  • 5 env vars confirmed in overlays/westside-admin/prod/westside-admin-secrets.enc.yaml on the open PR #147 branch (KEYCLOAK_URL, KEYCLOAK_REALM, KEYCLOAK_CLIENT_ID, KEYCLOAK_CLIENT_SECRET, COOKIE_SIGNING_KEY).
  • Story note story-westside-admin-admin-row-crud exists; arch notes arch-dataflow-westside-admin (Flow 1 referenced) and arch-deployment-westside-admin exist; arch-keycloak does not exist.
  • Issue #6 (scaffolding) closed. Keycloak client created today per prompt context.
## Scope Review: NEEDS_REFINEMENT Review note: `review-1132-2026-05-03` Scope is technically sound and the issue body is high quality, but it's over the 5-minute rule by its own admission, has two label/arch-note gaps, and the "prior art" hint is misleading. **Issues:** - `[LABEL]` Board item #1132 carries `story:superuser-onboard-service`; project Safety Constraints requires `story:admin-row-crud` (mirrored item on board-westside-admin already uses this). Swap the label. - `[SCOPE]` `arch:keycloak` label has no backing note in pal-e-docs. Same gap exists on board item #1096 (pal-e-platform#301). Decide create-now vs defer. - `[BODY]` "Prior art: westside-contracts may have SSR auth helpers" is misleading — westside-contracts has zero Keycloak code (signed-token URLs only); westside-app uses browser-side keycloak-js (adapter-static). Implement from scratch using `jose`. - `[BODY]` Optional: add a JWKS-unreachable resilience AC. - `[DECOMPOSE]` 6 new files + 10 AC + crypto + OIDC state + funnel-auth critical path. Over the 5-min rule. The 4-way split proposed in the issue body (keycloak.ts lib / hooks.server.ts+app.d.ts / auth callback+logout / 403 page) is sound. Ava's call: accept oversized with dev agent on standby, or route to `skill-decompose-ticket`. **Sequencing note:** Do not move to `in_progress` until `pal-e-deployments#147` is merged and ArgoCD has synced the secret — otherwise integration / SSO ACs cannot be validated. **Verified ground truth:** - All 6 file targets do not yet exist (correct, to create); `app.d.ts` and `package.json` exist as expected; adapter is `@sveltejs/adapter-node`; `src/lib/server/` exists and is empty. - 5 env vars confirmed in `overlays/westside-admin/prod/westside-admin-secrets.enc.yaml` on the open PR #147 branch (KEYCLOAK_URL, KEYCLOAK_REALM, KEYCLOAK_CLIENT_ID, KEYCLOAK_CLIENT_SECRET, COOKIE_SIGNING_KEY). - Story note `story-westside-admin-admin-row-crud` exists; arch notes `arch-dataflow-westside-admin` (Flow 1 referenced) and `arch-deployment-westside-admin` exist; `arch-keycloak` does not exist. - Issue #6 (scaffolding) closed. Keycloak client created today per prompt context.
Author
Owner

Closing — all 4 decomposed sub-tasks shipped:

  • #14 keycloak.ts lib (PR #18, merged)
  • #15 hooks.server.ts + app.d.ts (PR #20, merged)
  • #16 /auth/login + /callback + /logout endpoints (PR #21, merged)
  • #17 (unauthorized) 403 page (PR #23, merged)

Functional integration end-to-end (admin login → cookie → admin page; non-admin login → 403 page) becomes testable once ArgoCD finishes reconciling the latest image. End-to-end manual validation is the next gate; until then, board items stay in validation column. Two follow-ups remain in backlog: #19 (CI vitest gate) and #22 (refresh_exp lib extension).

Closing — all 4 decomposed sub-tasks shipped: - #14 keycloak.ts lib (PR #18, merged) - #15 hooks.server.ts + app.d.ts (PR #20, merged) - #16 /auth/login + /callback + /logout endpoints (PR #21, merged) - #17 (unauthorized) 403 page (PR #23, merged) Functional integration end-to-end (admin login → cookie → admin page; non-admin login → 403 page) becomes testable once ArgoCD finishes reconciling the latest image. End-to-end manual validation is the next gate; until then, board items stay in `validation` column. Two follow-ups remain in backlog: #19 (CI vitest gate) and #22 (refresh_exp lib extension).
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
forgejo_admin/westside-admin#2
No description provided.