Skip to content

Commit dfc4ea4

Browse files
committed
docs: record authkit production schema repair
1 parent d653928 commit dfc4ea4

6 files changed

Lines changed: 287 additions & 21 deletions

File tree

docs/codealmanac-launch/auth-api-contract.md

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,61 @@ persist upstream `oauthTokens` from `handleAuth({ onSuccess })` when present.
191191
This replaces the old Supabase callback behavior where `provider_token` and
192192
`provider_refresh_token` were sent to the backend.
193193

194+
Docs-backed setup contract:
195+
196+
```text
197+
browser -> /sign-in
198+
/sign-in -> AuthKit getSignInUrl()
199+
AuthKit -> GitHub OAuth provider
200+
GitHub -> WorkOS GitHub OAuth Redirect URI
201+
WorkOS -> /auth/callback
202+
/auth/callback -> handleAuth({ onSuccess })
203+
onSuccess -> send WorkOS accessToken + GitHub oauthTokens to backend
204+
backend -> verify WorkOS AuthKit access token, then store GitHub token pair
205+
```
206+
207+
The frontend should use WorkOS' standard Next.js SDK helpers:
208+
209+
```text
210+
getSignInUrl() in the sign-in route
211+
handleAuth() in the callback route
212+
AuthKitProvider in the app layout
213+
authkitProxy/authkit middleware or proxy for session handling
214+
```
215+
216+
Do not hand-roll the OAuth callback, state verifier, or PKCE cookie. If the
217+
provider setup is correct, the callback should be boring.
218+
219+
The backend should verify the WorkOS/AuthKit bearer as an AuthKit session token:
220+
221+
```text
222+
verify JWT signature against WorkOS JWKS
223+
require normal session claims such as subject, issuer, issued-at, and expiry
224+
accept the WorkOS/AuthKit issuer shape used by the SDK/runtime
225+
do not require GitHub oauthTokens to be embedded in the WorkOS access token
226+
do not require a non-documented `client_id` claim as a hard auth condition
227+
reject wrong client_id if WorkOS includes one
228+
```
229+
230+
GitHub provider tokens are not the browser session. They are upstream provider
231+
tokens returned during the AuthKit callback and stored only after the WorkOS
232+
session bearer verifies.
233+
234+
Production schema drift note from Slice 58:
235+
236+
```text
237+
symptom: /login?error=github_required after GitHub OAuth
238+
actual failing hop: POST /api/auth/github-app/session
239+
root cause: production users table still had supabase_user_id
240+
fix: repair production DB to workos_user_id plus encrypted token columns
241+
tracking migration: 20260703000000_repair_workos_identity_schema.sql
242+
```
243+
244+
If sign-in fails after WorkOS/GitHub redirects have succeeded, check backend
245+
logs and the production `users` schema before adding AuthKit retry machinery.
246+
The simplest correct path is the documented SDK callback plus a matching
247+
database schema.
248+
194249
Default GitHub OAuth scope:
195250

196251
```text
@@ -208,6 +263,67 @@ Repository reads, writes, PRs, branch checks, and delivery should use GitHub App
208263
installation tokens and GitHub App permissions. Add user OAuth scopes only for a
209264
specific user-on-behalf-of-user feature that cannot be served by the GitHub App.
210265

266+
When using a GitHub App as the WorkOS GitHub OAuth credential, GitHub App user
267+
access tokens do not use OAuth scopes in the classic OAuth App sense. They are
268+
bounded by the intersection of the GitHub App permissions and the user's own
269+
permissions. Keep the WorkOS scope field simple unless a concrete user-token
270+
feature requires more.
271+
272+
GitHub App optional feature:
273+
274+
```text
275+
User-to-server token expiration: enabled
276+
```
277+
278+
Reason:
279+
280+
```text
281+
GitHub returns ghu_ access tokens that expire after 8 hours and ghr_ refresh
282+
tokens that can refresh them. CodeAlmanac needs the refresh token path for
283+
stable user-linked GitHub identity and repository visibility.
284+
```
285+
286+
GitHub App installation OAuth prompt:
287+
288+
```text
289+
Request user authorization during installation: off by default
290+
```
291+
292+
Reason:
293+
294+
```text
295+
The normal user identity path is WorkOS/AuthKit sign-in. Installation is the
296+
repo permission path. If we enable OAuth during installation, GitHub starts a
297+
separate web application flow and chooses the first app callback unless the full
298+
flow controls redirect_uri. Keep identity and installation separate unless we
299+
intentionally redesign onboarding around installation-first auth.
300+
```
301+
302+
Provider config that should stay simple:
303+
304+
```text
305+
WorkOS GitHub provider enabled
306+
WorkOS GitHub provider uses GitHub App client id and client secret
307+
Return GitHub OAuth tokens enabled
308+
scope user:email
309+
GitHub App callback URL is the WorkOS GitHub OAuth Redirect URI
310+
GitHub App setup URL is https://www.codealmanac.com/setup
311+
GitHub App webhook URL is https://api.codealmanac.com/api/webhooks/github
312+
```
313+
314+
Production environment contract:
315+
316+
```text
317+
WORKOS_API_KEY
318+
WORKOS_CLIENT_ID
319+
WORKOS_COOKIE_PASSWORD
320+
NEXT_PUBLIC_WORKOS_REDIRECT_URI
321+
```
322+
323+
`WORKOS_COOKIE_PASSWORD` must be at least 32 characters because the AuthKit
324+
Next.js SDK uses it to encrypt the session cookie. An empty value is a broken
325+
deployment even when the WorkOS and GitHub dashboards are otherwise correct.
326+
211327
Empirical check on 2026-07-02 against `codealmanac/prd`: after refreshing the
212328
stored GitHub App user token for `rohans0509`, GitHub returned an empty
213329
`X-OAuth-Scopes` header and still allowed:

docs/codealmanac-launch/next-agent-brief.md

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# Next Agent Brief
22

33
Status: active.
4-
Updated: 2026-07-02.
4+
Updated: 2026-07-03.
55

66
## Current Hypothesis
77

@@ -98,30 +98,48 @@ Slice 57 hardens GitHub-only hosted sign-in:
9898
`https://codealmanac-hosted-jaxnxk6oq-thealmanac.vercel.app` is aliased to
9999
`https://www.codealmanac.com`
100100

101+
Slice 58 repairs production AuthKit schema drift:
102+
103+
- WorkOS/GitHub OAuth was configured correctly; the failing production request
104+
was backend persistence after the callback.
105+
- Production Supabase still had the old Supabase Auth-era `users.supabase_user_id`
106+
table shape, while deployed backend code expected `users.workos_user_id` plus
107+
encrypted GitHub token columns.
108+
- Hosted migration
109+
`supabase/migrations/20260703000000_repair_workos_identity_schema.sql`
110+
records the repair path.
111+
- Production now has an active `rohans0509` WorkOS user row with encrypted
112+
GitHub access and refresh tokens.
113+
- Hosted commit `01c84637e082945f22c71e09dfb7216c49c7769d` is on hosted
114+
`origin/codex/workos-authkit-api-foundation` and hosted `origin/main`.
115+
- Render deploy `dep-d93h21h9rddc73a2q0g0` is live for commit `01c8463`.
116+
- Browser-harness verified signed-in production `/setup` with `rohans0509`,
117+
`ReverieOne`, and `AlmanacCode`.
118+
101119
## Current Repo State
102120

103121
CodeAlmanac:
104122

105123
- repo: `/Users/rohan/Desktop/Projects/codealmanac`
106124
- branch: `dev`
107-
- current launch-docs commit before Slice 57 docs:
108-
`deda8a4faf336b98431d95719978f72719ad88da`
125+
- current launch-docs commit before Slice 58 docs:
126+
`d65392818f6d22f6b963b20259344bcd759b8dd1`
109127
- `origin/dev` and `origin/main` both point at
110-
`deda8a4faf336b98431d95719978f72719ad88da`
128+
`d65392818f6d22f6b963b20259344bcd759b8dd1`
111129
- package version in `pyproject.toml`: `0.1.0`
112130
- PyPI live version checked on 2026-07-02: `0.1.0`
113131

114132
Hosted:
115133

116134
- repo: `/Users/rohan/.config/superpowers/worktrees/usealmanac/hosted-baseline-convergence`
117135
- branch: `codex/workos-authkit-api-foundation`
118-
- current Slice 57 commit:
119-
`041deb878edb3931121ad861659dff0568f23b99`
136+
- current Slice 58 commit:
137+
`01c84637e082945f22c71e09dfb7216c49c7769d`
120138
- `origin/codex/workos-authkit-api-foundation` and `origin/main` both point at
121-
`041deb878edb3931121ad861659dff0568f23b99`
139+
`01c84637e082945f22c71e09dfb7216c49c7769d`
122140
- production frontend: `https://www.codealmanac.com`
123-
- hosted main has the setup/auth hardening, route-test guardrails, and cloud
124-
setup checklist through `041deb8`
141+
- hosted main has setup/auth hardening, route-test guardrails, cloud setup
142+
checklist, and production WorkOS identity schema repair through `01c8463`.
125143

126144
The local wiki command currently fails on this checkout with:
127145

@@ -180,12 +198,17 @@ repaired.
180198
`/sign-in` set a `wos-auth-verifier-*` cookie before redirecting to WorkOS,
181199
browser-harness showed `/login` with `Continue with GitHub` and no inputs,
182200
and Vercel had no recent error logs.
201+
- Slice 58 production auth verification passed: focused hosted backend auth
202+
tests (`24 passed`), production DB row for `rohans0509` with encrypted access
203+
and refresh token ciphertext, Render live deploy `dep-d93h21h9rddc73a2q0g0`,
204+
backend health `{"status":"ok"}`, Vercel production Ready, and browser-harness
205+
signed-in `/setup` showing `rohans0509`, `ReverieOne`, and `AlmanacCode`.
183206

184207
## Next Pressure Tests
185208

186-
- Do a real signed-in production browser pass through:
187-
`/login` -> GitHub AuthKit -> `/setup` -> GitHub App install/config ->
188-
repository settings.
209+
- Continue the real signed-in production browser pass from the verified
210+
`/setup` state into repository settings, branch trigger configuration,
211+
capture consent, and run visibility.
189212
- Add `GITHUB_TOKEN_ENCRYPTION_KEYS` to Doppler `codealmanac/dev_personal` if a
190213
local signed-in setup walkthrough is needed; the backend currently refuses to
191214
start without it.

docs/codealmanac-launch/progress.md

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
# Launch Progress
22

33
Status: active.
4-
Updated: 2026-07-02.
4+
Updated: 2026-07-03.
55

66
This file tracks the rough percentage estimates used in RelayForge updates.
77
Percentages are planning estimates, not accounting metrics.
88

99
## Latest RelayForge Update
1010

11-
Sent: 2026-07-02 after Slice 57 AuthKit sign-in hardening.
11+
Sent: 2026-07-03 after Slice 58 AuthKit production schema repair.
1212

1313
Route:
1414

@@ -20,18 +20,20 @@ doppler run --project almanac --config dev -- \
2020
```
2121

2222
Note: rate limits were postponed. PyPI Trusted Publishing is working for
23-
CodeAlmanac `0.1.0`. Hosted sign-in is now routed through the product login
24-
page first, with `/sign-in` as the only WorkOS/AuthKit start endpoint.
23+
CodeAlmanac `0.1.0`. Hosted sign-in now reaches the production `/setup` page
24+
with GitHub accounts visible. The root cause was production Supabase schema
25+
drift: backend code expected WorkOS-shaped `users` rows, while production still
26+
had the old Supabase Auth-shaped `users.supabase_user_id` table shape.
2527

2628
## Percentages
2729

2830
| Area | Latest | Previous | Basis |
2931
| --- | ---: | ---: | --- |
30-
| CodeAlmanac backend/local | 96% | 96% | CodeAlmanac local/backend unchanged in Slice 57. |
31-
| CodeAlmanac CLI/public UX | 98% | 98% | PyPI `0.1.0` remains published and install-smoked; no CLI code changed in Slice 57. |
32-
| CodeAlmanac-hosted backend/auth/API | 97% | 96% | AuthKit callback now rejects non-GitHub-token completions and maps callback errors back to GitHub-only login states. |
33-
| Hosted frontend/onboarding | 84% | 78% | Public CTAs, protected redirects, login, `/sign-in`, and production `/setup` smoke now follow one GitHub-first setup path. |
34-
| Infra/deploy rename | 98% | 98% | Vercel production redeployed and aliased after Slice 57; remaining infra work is provider cleanup and signed-in walkthrough coverage. |
32+
| CodeAlmanac backend/local | 96% | 96% | CodeAlmanac local/backend unchanged in Slice 58. |
33+
| CodeAlmanac CLI/public UX | 98% | 98% | PyPI `0.1.0` remains published and install-smoked; no CLI code changed in Slice 58. |
34+
| CodeAlmanac-hosted backend/auth/API | 98% | 97% | Production DB now matches the WorkOS/AuthKit identity schema and stores encrypted GitHub access plus refresh tokens. |
35+
| Hosted frontend/onboarding | 88% | 84% | Signed-in production `/setup` now renders `rohans0509` and connected GitHub accounts after the fixed auth/session write. |
36+
| Infra/deploy rename | 99% | 98% | Hosted `main` and branch point at the schema-repair commit; Render deployed it live and Vercel remains Ready. |
3537

3638
## Update Rule
3739

docs/codealmanac-launch/verification-matrix.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,27 @@ Current evidence:
172172
`codealmanac-hosted-jaxnxk6oq-thealmanac.vercel.app`, production `/setup`
173173
redirect smoke, production `/sign-in` verifier-cookie smoke,
174174
browser-harness `/login` smoke, and Vercel error-log check.
175+
- Slice 58 repaired production Supabase schema drift. Production had old
176+
Supabase Auth-era `users.supabase_user_id` and plaintext token columns while
177+
the deployed backend expected WorkOS/AuthKit `users.workos_user_id` and
178+
encrypted token columns.
179+
- Hosted migration
180+
`supabase/migrations/20260703000000_repair_workos_identity_schema.sql`
181+
records the repair path. The migration converts legacy identity columns and
182+
foreign keys to WorkOS text ids, adds `oauth_token_ciphertext` and
183+
`refresh_token_ciphertext`, removes plaintext token columns, and recreates
184+
foreign keys to `users(workos_user_id)`.
185+
- Production migration history includes `20260703000000` plus the previously
186+
drifted launch migrations. The repair was applied through Doppler-backed
187+
`psql` because Supabase CLI migration commands hit a pooler
188+
prepared-statement conflict.
189+
- Production DB check proved `rohans0509` has an active WorkOS user row with
190+
encrypted GitHub access and refresh tokens present.
191+
- Slice 58 hosted verification passed: focused backend auth tests
192+
(`24 passed`), Render deploy `dep-d93h21h9rddc73a2q0g0` live on commit
193+
`01c8463`, backend health `{"status":"ok"}`, Vercel production Ready, and
194+
browser-harness signed-in `/setup` rendering `rohans0509`, `ReverieOne`, and
195+
`AlmanacCode`.
175196

176197
## CodeAlmanac Local Repo
177198

docs/codealmanac-launch/worklog.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,49 @@
22

33
## 2026-07-02
44

5+
- Planned Slice 58 in
6+
`docs/plans/2026-07-02-slice-58-authkit-stale-session-retry.md`. The initial
7+
hypothesis was a stale AuthKit session retry problem; production evidence
8+
changed the slice into a schema-drift repair.
9+
- Confirmed the real production auth failure was not WorkOS or GitHub OAuth
10+
configuration. WorkOS/GitHub returned tokens, but
11+
`POST /api/auth/github-app/session` failed because production Supabase still
12+
had the old Supabase Auth-era `users.supabase_user_id` shape while deployed
13+
backend code expected `users.workos_user_id` and encrypted token columns.
14+
- Repaired production Supabase through Doppler-backed `psql` because Supabase
15+
CLI migration commands hit the pooler prepared-statement error
16+
`prepared statement "lrupsc_1_0" already exists`.
17+
- Added hosted migration
18+
`supabase/migrations/20260703000000_repair_workos_identity_schema.sql`. The
19+
migration creates missing launch tables, converts legacy identity foreign keys
20+
to WorkOS text ids, drops plaintext GitHub token columns, adds encrypted token
21+
columns, and recreates foreign keys to `users(workos_user_id)`.
22+
- Applied and repaired production migration history for:
23+
`launch_security_hardening`, `local_agent_setup_intro`,
24+
`hosted_conversation_sync`, `conversation_ingest_scheduler`,
25+
`conversation_source_refs`, `encrypt_github_user_tokens`, and
26+
`repair_workos_identity_schema`.
27+
- Verified production DB has `user_01KWJ304254FX8W88S879S8PQG` for
28+
`rohans0509`, active, with encrypted GitHub access and refresh token
29+
ciphertext present.
30+
- Verified hosted backend focused auth tests:
31+
`uv run pytest tests/test_identity_auth_contract.py tests/test_github_auth_contract.py tests/test_installations_contract.py -q`
32+
(`24 passed`).
33+
- Pushed hosted commit
34+
`01c84637e082945f22c71e09dfb7216c49c7769d fix(auth): repair WorkOS identity schema migration`
35+
to `origin/codex/workos-authkit-api-foundation` and hosted `origin/main`.
36+
- Render deployed hosted commit `01c8463` live as deploy
37+
`dep-d93h21h9rddc73a2q0g0`. Backend health returned `{"status":"ok"}`.
38+
- Vercel production remained Ready and aliased to `https://www.codealmanac.com`.
39+
No new Vercel deployment was needed for the SQL-only migration commit.
40+
- Browser-harness verified signed-in production setup after the Render deploy:
41+
`https://www.codealmanac.com/setup` rendered `rohans0509`, cloud setup,
42+
connected GitHub accounts `ReverieOne` and `AlmanacCode`, and the PyPI-shaped
43+
machine setup command.
44+
- Sent RelayForge update through `rohan-almanac-main` with Slice 58 verification
45+
evidence and progress percentages: CodeAlmanac backend/local 96%,
46+
CLI/public UX 98%, hosted backend/auth/API 98%, hosted frontend/onboarding
47+
88%, infra/deploy rename 99%.
548
- Planned Slice 57 in
649
`docs/plans/2026-07-02-slice-57-authkit-signin-hardening.md`.
750
- Hardened hosted sign-in so `/sign-in` is the only route that starts

0 commit comments

Comments
 (0)