Fix continue_with:null decode crash + add auth decode/integration tests
Android UI Tests / ui-tests (push) Has been cancelled
Android UI Tests / ui-tests (push) Has been cancelled
Kratos serialises an empty `continue_with` as explicit `null` (not `[]` or an
absent key), which crashed the post-register login decode ("Expected start of
the array '[', but had 'n' at $.continue_with"). Make continue_with nullable on
the three Kratos models and add coerceInputValues as a backstop for other
null-vs-default fields.
Tests (all run + passing):
- KratosDecodeTest: null/absent continue_with on login + registration
- AuthFlowDecodeTest: real captured prod bodies (login, /auth/me, verification)
decoded with the real models + the real client Json configs
- LiveAuthIntegrationTest: live HTTP through the actual AuthApi against prod
(register -> login -> /auth/me -> start-verification -> wrong-code), gated by
RUN_LIVE_IT=1 so it never runs on a normal build
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -39,8 +39,13 @@ data class KratosFlow(
|
||||
* Post-submission instructions. On a completed recovery flow this carries
|
||||
* the privileged session token (`set_ory_session_token`) and the settings
|
||||
* flow to finish the password change in (`show_settings_ui`).
|
||||
*
|
||||
* Nullable because Kratos serialises this as an explicit `"continue_with":
|
||||
* null` (not an empty array / absent key) when there are no items — a
|
||||
* non-nullable List would throw on decode ("Expected start of the array
|
||||
* '[', but had 'n'").
|
||||
*/
|
||||
@SerialName("continue_with") val continueWith: List<KratosContinueWith> = emptyList(),
|
||||
@SerialName("continue_with") val continueWith: List<KratosContinueWith>? = null,
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -149,7 +154,8 @@ data class KratosSession(
|
||||
data class KratosLoginSuccess(
|
||||
val session: KratosSession,
|
||||
@SerialName("session_token") val sessionToken: String,
|
||||
@SerialName("continue_with") val continueWith: List<KratosContinueWith> = emptyList(),
|
||||
// Nullable: Kratos sends "continue_with": null on a plain login.
|
||||
@SerialName("continue_with") val continueWith: List<KratosContinueWith>? = null,
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -162,7 +168,8 @@ data class KratosRegistrationSuccess(
|
||||
val session: KratosSession? = null,
|
||||
@SerialName("session_token") val sessionToken: String? = null,
|
||||
val identity: KratosIdentity? = null,
|
||||
@SerialName("continue_with") val continueWith: List<KratosContinueWith> = emptyList(),
|
||||
// Nullable: Kratos may serialise this as an explicit null.
|
||||
@SerialName("continue_with") val continueWith: List<KratosContinueWith>? = null,
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,6 +49,11 @@ class AuthApi(private val client: HttpClient = ApiClient.httpClient) {
|
||||
ignoreUnknownKeys = true
|
||||
isLenient = true
|
||||
encodeDefaults = true
|
||||
// Kratos serialises empty list/object fields as explicit `null` rather
|
||||
// than omitting them or sending `[]`. Without this, a non-nullable field
|
||||
// with a default (e.g. ui.nodes, ui.messages) throws on a null value.
|
||||
// coerceInputValues falls back to the declared default in that case.
|
||||
coerceInputValues = true
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -69,9 +74,9 @@ class AuthApi(private val client: HttpClient = ApiClient.httpClient) {
|
||||
* is rejected. [verifyEmail] reads the persisted id and posts to it
|
||||
* directly.
|
||||
*/
|
||||
private fun capturePendingVerificationFlow(continueWith: List<KratosContinueWith>) {
|
||||
private fun capturePendingVerificationFlow(continueWith: List<KratosContinueWith>?) {
|
||||
val flowId = continueWith
|
||||
.firstOrNull { it.action == "show_verification_ui" }
|
||||
?.firstOrNull { it.action == "show_verification_ui" }
|
||||
?.flow?.id
|
||||
if (!flowId.isNullOrBlank()) {
|
||||
DataManager.setPendingVerificationFlowId(flowId)
|
||||
|
||||
Reference in New Issue
Block a user