feat(api+client): linked-identities panel on the account screen (#216) #244
No reviewers
Labels
No labels
area:auth
area:ci
area:db
area:infra
area:native
area:pwa
area:service
epic
feature
foundation
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
james/carol!244
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "216-linked-identities-panel"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Restore the "Sign-in methods" panel on the universal client's
/accountscreen. The PWA had this; #185 deleted it. This is the universal-client rebuild against@carol/api-clientper ADR-0027.API
GET /api/account/identities— bundle:availableis the server's enabled OAuth/OIDC providers minus the providers the user is already linked to. That keeps the panel a single round-trip and avoids baking a build-time provider list into the client (which wouldn't match the configured server in self-hoster deployments).DELETE /api/account/identities/oauth/{id}— enforces the same "last sign-in method" check the deleted PWAunlink-action.tscarried: refuse with409 last_sign_in_methodif removing this row would leave the user with zero ways to sign in. Cross-user attempts return 404 per the don't-leak-existence rule.getAuthIdentity()so they accept session OR bearer (ADR-0027).apps/api/lib/dto/account-identities.ts; both routes registered inlib/api/openapi-routes.ts;last_sign_in_methodlisted indocs/api-conventions.md.@carol/api-clientuseAccountIdentities(query, keykeys.account.identities) anduseUnlinkAccountIdentity(mutation, invalidates on success) underpackages/api-client/src/hooks/account-identities.ts.Client UI
New
SignInMethodsCardsits between the header and the PATs card on/account:availableprovider with a button that hits/api/auth/oauth/start?provider=…&next=/account. On web it's a same-origin navigation. On native it goes throughexpo-linking'sopenURLso the system browser carries the session cookie. A hint under the buttons documents the native handoff.useTranslation("account"); new keys land inpackages/i18n/messages/en.json. Spanish stays partial per ADR-0025.Surprises / notable calls
/api/auth/oauth/startcould detect. The start route'slinkbranch hinges ongetSession(req)returning a session; without that cookie the user lands in asigninflow instead. That's the same constraint the PWA's old panel had — linking is web-only today. The native button still opens the URL so a self-hoster who's web-signed-in already can complete the link in their browser, and the hint string under the buttons documents that handoff.Test plan
pnpm install --frozen-lockfilepnpm -F @carol/api typecheckpnpm -F @carol/api lintpnpm -F @carol/api test— 47 files / 567 tests, 11 new for the identities surface (happy path GET, GET after unlink, DELETE with multi-methods, DELETE with single method → 409, cross-user 404 on both routes, 404 on random id)pnpm -F @carol/api openapi:checkpnpm -F @carol/api openapi:coverage— 56 registered (was 54)pnpm -F @carol/api-client typecheck/lint/test/checkpnpm -F @carol/client typecheck/lint/test/export:webLinks
Trivy (container image)
Threshold:
high· Total findings: 121 · At/above threshold: 16.27.0, 7.28.0, 8.5.0📊 Test coverage
Patch coverage: no testable lines changed.
Overall (
app/,lib/,db/, excluding UI per ADR-0019):Soft thresholds per ADR-0019. Coverage is informational and does not block merge.