Files
2026-04-29 21:07:49 +02:00

8.2 KiB

phase, plan, subsystem, tags, requires, provides, affects, tech-stack, key-files, key-decisions, patterns-established, requirements-completed, duration, completed
phase plan subsystem tags requires provides affects tech-stack key-files key-decisions patterns-established requirements-completed duration completed
02-authentication-foundation 03 auth
oidc
appauth
kmp
wasm
jvm
authstate
phase provides
02-authentication-foundation 02-01 shared OIDC constants and Phase 2 client dependencies
Common `OidcClient` expect seam with suspend login, refresh, and logout
Common `OidcResult` model for AuthSession and LoginViewModel consumers
Common `SecureAuthStateStore` expect contract for opaque AppAuth AuthState JSON
JVM dev-only `DEV_AUTH_TOKEN` OIDC actual and in-memory AuthState store actual
Wasm v2 OIDC stubs and in-memory AuthState store actual
SecureAuthStateStore common contract tests for write, overwrite, read, and clear
02-04-android-auth-actuals
02-05-ios-auth-actuals
02-06-auth-session-ui
added patterns
OIDC seam pattern: common expects pin AppAuth/scopes/logout semantics while target actuals own platform mechanics.
Secondary target pattern: JVM uses explicit DEV_AUTH_TOKEN dev behavior; Wasm throws the documented v2 NotImplementedError boundary.
created modified
composeApp/src/commonMain/kotlin/dev/ulfrx/recipe/auth/OidcClient.kt
composeApp/src/commonMain/kotlin/dev/ulfrx/recipe/auth/OidcResult.kt
composeApp/src/commonMain/kotlin/dev/ulfrx/recipe/auth/SecureAuthStateStore.kt
composeApp/src/jvmMain/kotlin/dev/ulfrx/recipe/auth/OidcClient.jvm.kt
composeApp/src/jvmMain/kotlin/dev/ulfrx/recipe/auth/SecureAuthStateStore.jvm.kt
composeApp/src/webMain/kotlin/dev/ulfrx/recipe/auth/OidcClient.wasmJs.kt
composeApp/src/webMain/kotlin/dev/ulfrx/recipe/auth/SecureAuthStateStore.wasmJs.kt
composeApp/src/commonTest/kotlin/dev/ulfrx/recipe/auth/SecureAuthStateStoreContractTest.kt
JVM actuals were added with Task 1 because the required `:composeApp:jvmTest` acceptance gate cannot compile common expect classes without JVM actual declarations.
Kotlin expect/actual beta diagnostics are suppressed at the auth seam file level to satisfy the existing `-Werror` build without changing Gradle configuration.
Wasm OIDC remains an explicit v2 boundary by throwing `NotImplementedError("Wasm OIDC: v2")` from login, refresh, and logout.
AuthState JSON is treated as opaque common data; secure mobile storage actuals remain owned by Android/iOS plans.
Desktop auth is dev-only and requires an externally supplied `DEV_AUTH_TOKEN`; no usable bearer token is hardcoded.
AUTH-01
AUTH-02
AUTH-04
AUTH-05
31m 2026-04-28

Phase 02 Plan 03: Common OIDC and AuthState Store Contracts Summary

Stable KMP auth seams for AppAuth-backed mobile login, explicit JVM dev-token behavior, Wasm v2 stubs, and contract-tested AuthState JSON storage semantics.

Performance

  • Duration: 31 min
  • Started: 2026-04-28T11:18:45Z
  • Completed: 2026-04-28T11:49:40Z
  • Tasks: 2
  • Files modified: 8

Accomplishments

  • Added common auth contracts: OidcClient, OidcResult, and SecureAuthStateStore.
  • Pinned native OIDC behavior in common KDoc: AppAuth, suspendCancellableCoroutine, exact openid profile email offline_access scopes, fresh-token refresh, and RP-initiated logout.
  • Added JVM actuals for desktop/dev test compilation with explicit DEV_AUTH_TOKEN behavior and no hardcoded bearer token.
  • Added Wasm actuals that preserve the documented v2 OIDC boundary while keeping compileKotlinWasmJs green.
  • Added common contract tests proving store write overwrite, latest read, and clear semantics.

Task Commits

  1. Task 1 RED: SecureAuthStateStore contract test - 7ef222e (test)
  2. Task 1 GREEN: Common auth contracts plus JVM actuals - edc2a1d (feat)
  3. Task 2: Wasm auth stubs - 0dbd374 (feat)

Note: Task 1 was TDD and produced RED + GREEN commits. No refactor commit was needed.

Files Created/Modified

  • composeApp/src/commonMain/kotlin/dev/ulfrx/recipe/auth/OidcClient.kt - Common expect OIDC client seam with pinned AppAuth/scopes/refresh/logout semantics.
  • composeApp/src/commonMain/kotlin/dev/ulfrx/recipe/auth/OidcResult.kt - Sealed result model for success, cancellation, network failure, and auth failure.
  • composeApp/src/commonMain/kotlin/dev/ulfrx/recipe/auth/SecureAuthStateStore.kt - Common expect secure store contract for opaque AppAuth AuthState JSON.
  • composeApp/src/jvmMain/kotlin/dev/ulfrx/recipe/auth/OidcClient.jvm.kt - Desktop dev actual using DEV_AUTH_TOKEN.
  • composeApp/src/jvmMain/kotlin/dev/ulfrx/recipe/auth/SecureAuthStateStore.jvm.kt - In-memory desktop AuthState store actual.
  • composeApp/src/webMain/kotlin/dev/ulfrx/recipe/auth/OidcClient.wasmJs.kt - Wasm v2 OIDC boundary stubs.
  • composeApp/src/webMain/kotlin/dev/ulfrx/recipe/auth/SecureAuthStateStore.wasmJs.kt - In-memory Wasm AuthState store actual.
  • composeApp/src/commonTest/kotlin/dev/ulfrx/recipe/auth/SecureAuthStateStoreContractTest.kt - Store read/write/overwrite/clear contract tests.

Decisions Made

See frontmatter key-decisions.

Deviations from Plan

Auto-fixed Issues

1. [Rule 3 - Blocking] Added JVM actuals during Task 1 GREEN

  • Found during: Task 1 verification
  • Issue: The plan required ./gradlew :composeApp:jvmTest to pass after adding common expect class declarations, but JVM compilation requires matching JVM actual declarations.
  • Fix: Added the JVM dev OidcClient actual and in-memory SecureAuthStateStore actual in the Task 1 GREEN commit. Task 2 then added the Wasm actuals as planned.
  • Files modified: composeApp/src/jvmMain/kotlin/dev/ulfrx/recipe/auth/OidcClient.jvm.kt, composeApp/src/jvmMain/kotlin/dev/ulfrx/recipe/auth/SecureAuthStateStore.jvm.kt
  • Verification: ./gradlew :composeApp:jvmTest
  • Committed in: edc2a1d

2. [Rule 3 - Blocking] Suppressed expect/actual beta diagnostics at file level

  • Found during: Task 1 verification
  • Issue: Kotlin emitted expect/actual beta warnings and the project treats warnings as errors.
  • Fix: Added targeted @file:Suppress("EXPECT_ACTUAL_CLASSIFIERS_ARE_IN_BETA_WARNING") to the auth expect/actual files.
  • Files modified: OidcClient.kt, SecureAuthStateStore.kt, JVM actual files, Wasm actual files
  • Verification: ./gradlew :composeApp:jvmTest :composeApp:compileKotlinWasmJs
  • Committed in: edc2a1d, 0dbd374

Total deviations: 2 auto-fixed (2 x Rule 3). Impact on plan: No behavior scope changed. The deviations only made the required verification gates compatible with Kotlin expect/actual compilation under the project build settings.

Known Stubs

File Line Reason
composeApp/src/webMain/kotlin/dev/ulfrx/recipe/auth/OidcClient.wasmJs.kt 7 Intentional v2 boundary per D-03 and plan acceptance criteria.
composeApp/src/webMain/kotlin/dev/ulfrx/recipe/auth/OidcClient.wasmJs.kt 11 Intentional v2 boundary per D-03 and plan acceptance criteria.
composeApp/src/webMain/kotlin/dev/ulfrx/recipe/auth/OidcClient.wasmJs.kt 15 Intentional v2 boundary per D-03 and plan acceptance criteria.

Issues Encountered

  • Concurrent Wave 2 work landed 02-02 commits while this plan was executing. No conflicts touched this plan's owned files.
  • gsd-sdk query init.execute-phase 02 updated .planning/STATE.md at startup before task work began. Final state updates are handled in the metadata step.

User Setup Required

None.

Verification

  • ./gradlew :composeApp:jvmTest - PASS
  • ./gradlew :composeApp:jvmTest :composeApp:compileKotlinWasmJs - PASS
  • Task 1 acceptance greps - PASS
  • Task 2 acceptance greps - PASS

Next Phase Readiness

Android and iOS auth actual plans can now implement AppAuth behind stable common seams. AuthSession/UI plans can consume OidcResult and SecureAuthStateStore without platform-specific APIs.

Self-Check: PASSED

  • Created files exist: all 8 plan-owned source/test files plus this summary were found.
  • Commits exist: 7ef222e, edc2a1d, and 0dbd374 were found in git history.
  • Acceptance criteria: all required grep checks passed.
  • Plan-level verification: ./gradlew :composeApp:jvmTest :composeApp:compileKotlinWasmJs passed.

Phase: 02-authentication-foundation Completed: 2026-04-28