Roadmap: #188
Respect the [auth] roadmap first and the AGENTS.md file of every repository touched.
Previous roadmap step
[auth 5] (#193) establishes one brokered OAuth flow across Web, iOS and Android. This issue defines the stable adapter-neutral domain consumed after authentication so profile UI, bindings and account operations do not depend on Supabase/provider metadata shapes.
Repository impact
Likely:
ankhorage/contracts
ankhorage/supabase-auth
ankhorage/runtime
ankhorage/infra where generated profile persistence/trigger ownership must evolve
ankhorage/studio only for configuration/generation consumption
Pause at package release boundaries. Contracts own neutral serializable/interfaces; Supabase Auth implements them; Runtime exposes them; Studio must not duplicate them.
Goal
Complete one canonical Auth/account domain that separates:
Auth identity/session
-> authenticated subject and provider-normalized claims
Editable user profile
-> app-owned mutable fields
Account operations
-> security/identity mutations and lifecycle actions
The same generated UI and bindings must work with future Auth adapters without knowing their provider-specific metadata.
Current baseline and gaps
Current AuthUser already normalizes fields such as email, phone, username, displayName and avatarUrl, while AuthProfileSpec can request fields including firstName and lastName.
Gaps to resolve:
firstName/lastName are not canonical normalized Auth/Profile fields everywhere;
- identity/session claims and editable profile values are not explicitly separated;
- no generic profile read/update adapter contract exists;
- account actions such as change email/password/delete account are absent or provider-specific;
- bindings have generic
context/state but no canonical auth or profile source;
- provider metadata merge/ownership policy is not explicit.
Domain direction
The exact APIs must be finalized in Contracts, but conceptually:
interface AuthUser {
id: string;
email?: string;
phone?: string;
username?: string;
displayName?: string;
firstName?: string;
lastName?: string;
avatarUrl?: string;
metadata?: Record<string, unknown>;
}
interface UserProfile {
id: string;
displayName?: string;
firstName?: string;
lastName?: string;
avatarUrl?: string;
custom?: Record<string, unknown>;
}
Do not freeze this sketch without deciding whether email/phone/username belong only to identity or may also be mirrored read-only into profile presentation.
Requirements
Identity/session
- adapters normalize provider/backend-specific claims into canonical fields;
- raw provider metadata remains available only as an escape hatch, not the preferred binding surface;
- session serialization remains secure and minimal;
- no client secret/provider token leakage into normalized user metadata;
- identity fields have explicit mutability/verification semantics.
Profile adapter/capabilities
Define capability-driven operations, conceptually:
getProfile()
updateProfile(patch)
Potential additional capabilities must be explicit rather than assumed.
The profile store may be an app-owned table for Supabase today and another implementation later. Generated UI consumes only the neutral result.
Account operations
Define neutral capabilities/results for supported operations such as:
- change email/identifier;
- change password;
- request/confirm re-authentication where required;
- sign out all devices;
- delete account;
- link/unlink identity where later supported.
Passwords are write-only inputs. They never appear in AuthSession, AuthUser, UserProfile or bindings.
Email changes are account operations, not ordinary profile-table mutation.
Provider profile initialization and merge policy
Model explicit policy for first login and future login refresh, for example:
initializeFromProvider:
displayName
avatarUrl
firstName
lastName
refreshFromProvider:
avatarUrl (optional)
A user-edited profile value must not be overwritten on every OAuth login unless configuration explicitly declares provider authority.
Define ownership/source metadata only if required; avoid unnecessary complexity while preserving deterministic behavior.
Canonical bindings
Extend binding sources with explicit neutral domains, conceptually:
{ kind: 'auth', path: 'user.email' }
{ kind: 'profile', path: 'displayName' }
Requirements:
- typed/validated paths where current binding architecture supports them;
- lifecycle states for loading/error/empty profile;
- read-only identity vs editable profile distinction;
- no recommendation to bind UI directly to provider-specific
metadata.full_name/picture keys;
- account actions available as canonical event/action targets rather than arbitrary operation strings.
Supabase implementation
- normalize Google/provider aliases consistently;
- include first/last name where available;
- read/update the configured app-owned profile table through correct policies;
- preserve trigger/API/app profile creation strategies;
- map neutral account actions to Supabase Auth methods where supported;
- advertise unsupported capabilities honestly.
Likely files
Contracts, non-exhaustive:
src/auth.ts
src/bindings.ts
src/types.ts
src/profile-contract.test.ts
src/auth-*.test.ts
src/bindings.test.ts
Supabase Auth:
src/session.ts
src/profileVerification.ts
src/types.ts
src/createSupabaseAuthAdapter.ts
src/accountLifecycle.ts
Runtime/Infra/Studio paths must be determined from current binding context, profile generation and action ownership.
Phases
Phase 1 — canonical domain and capabilities
Finalize AuthUser/UserProfile/account-operation contracts, mutability semantics and capability reporting.
Phase 2 — binding source/action contracts
Add neutral Auth/Profile sources and account action targets with validation/runtime resolution contracts.
Phase 3 — Supabase implementation and profile ownership
Implement normalization, profile read/update, merge policy and account capabilities behind @ankhorage/supabase-auth and generated Infra profile ownership.
Phase 4 — Runtime/Studio integration hardening
Expose canonical context/action resolution and update configuration/admin diagnostics without provider-specific UI coupling.
Tests
Cover at minimum:
- provider claim aliases normalize into canonical user fields;
- firstName/lastName round-trip where configured;
- raw metadata does not override canonical fields unexpectedly;
- profile get/update capability and unsupported behavior;
- first-login provider initialization;
- later login does not overwrite user-owned fields outside merge policy;
- email/password account operations remain distinct from profile mutation;
- password never serializes into session/profile/binding values;
auth and profile binding path resolution/lifecycle;
- account action capability checks and result mapping;
- Supabase profile table/RLS-safe behavior;
- another fake adapter can satisfy the same contracts without Supabase types.
Acceptance criteria
- Identity, editable profile and account operations are explicitly separate.
- Canonical user/profile fields include the configured name/avatar concerns consistently.
- Adapters advertise profile/account capabilities honestly.
- Provider metadata initialization/refresh follows an explicit merge policy.
- User-edited profile fields are not silently overwritten on every login.
- Bindings use canonical
auth/profile sources rather than provider metadata keys.
- Password and email security operations are modeled correctly.
- Supabase implements the neutral contracts without leaking Supabase types into generated UI.
- Future adapters can implement the same contracts.
- Behavior-focused tests, package releases/changesets and full validation pass.
Roadmap: #188
Respect the
[auth]roadmap first and theAGENTS.mdfile of every repository touched.Previous roadmap step
[auth 5](#193) establishes one brokered OAuth flow across Web, iOS and Android. This issue defines the stable adapter-neutral domain consumed after authentication so profile UI, bindings and account operations do not depend on Supabase/provider metadata shapes.Repository impact
Likely:
ankhorage/contractsankhorage/supabase-authankhorage/runtimeankhorage/infrawhere generated profile persistence/trigger ownership must evolveankhorage/studioonly for configuration/generation consumptionPause at package release boundaries. Contracts own neutral serializable/interfaces; Supabase Auth implements them; Runtime exposes them; Studio must not duplicate them.
Goal
Complete one canonical Auth/account domain that separates:
The same generated UI and bindings must work with future Auth adapters without knowing their provider-specific metadata.
Current baseline and gaps
Current
AuthUseralready normalizes fields such asemail,phone,username,displayNameandavatarUrl, whileAuthProfileSpeccan request fields includingfirstNameandlastName.Gaps to resolve:
firstName/lastNameare not canonical normalized Auth/Profile fields everywhere;context/statebut no canonicalauthorprofilesource;Domain direction
The exact APIs must be finalized in Contracts, but conceptually:
Do not freeze this sketch without deciding whether email/phone/username belong only to identity or may also be mirrored read-only into profile presentation.
Requirements
Identity/session
Profile adapter/capabilities
Define capability-driven operations, conceptually:
Potential additional capabilities must be explicit rather than assumed.
The profile store may be an app-owned table for Supabase today and another implementation later. Generated UI consumes only the neutral result.
Account operations
Define neutral capabilities/results for supported operations such as:
Passwords are write-only inputs. They never appear in
AuthSession,AuthUser,UserProfileor bindings.Email changes are account operations, not ordinary profile-table mutation.
Provider profile initialization and merge policy
Model explicit policy for first login and future login refresh, for example:
A user-edited profile value must not be overwritten on every OAuth login unless configuration explicitly declares provider authority.
Define ownership/source metadata only if required; avoid unnecessary complexity while preserving deterministic behavior.
Canonical bindings
Extend binding sources with explicit neutral domains, conceptually:
Requirements:
metadata.full_name/picturekeys;Supabase implementation
Likely files
Contracts, non-exhaustive:
Supabase Auth:
Runtime/Infra/Studio paths must be determined from current binding context, profile generation and action ownership.
Phases
Phase 1 — canonical domain and capabilities
Finalize AuthUser/UserProfile/account-operation contracts, mutability semantics and capability reporting.
Phase 2 — binding source/action contracts
Add neutral Auth/Profile sources and account action targets with validation/runtime resolution contracts.
Phase 3 — Supabase implementation and profile ownership
Implement normalization, profile read/update, merge policy and account capabilities behind
@ankhorage/supabase-authand generated Infra profile ownership.Phase 4 — Runtime/Studio integration hardening
Expose canonical context/action resolution and update configuration/admin diagnostics without provider-specific UI coupling.
Tests
Cover at minimum:
authandprofilebinding path resolution/lifecycle;Acceptance criteria
auth/profilesources rather than provider metadata keys.