fix(02-04): harden Android OIDC token result mapping

- Treat missing access tokens as auth failures
- Preserve AppAuth discovery errors for correct network/auth classification
This commit is contained in:
2026-04-28 16:00:20 +02:00
parent 6385453653
commit 11a5eeb3ff

View File

@@ -28,8 +28,11 @@ actual class OidcClient {
get() = GlobalContext.get().get<Context>().applicationContext
actual suspend fun login(): OidcResult {
val configuration = fetchConfiguration()
?: return OidcResult.NetworkError
val configuration =
when (val outcome = fetchConfiguration()) {
is ConfigurationOutcome.Success -> outcome.configuration
is ConfigurationOutcome.Error -> return outcome.exception.toOidcError()
}
val request =
AuthorizationRequest
@@ -87,14 +90,19 @@ actual class OidcClient {
}
}
private suspend fun fetchConfiguration(): AuthorizationServiceConfiguration? =
private suspend fun fetchConfiguration(): ConfigurationOutcome =
suspendCancellableCoroutine { continuation ->
AuthorizationServiceConfiguration.fetchFromIssuer(Uri.parse(Constants.OIDC_ISSUER)) { configuration, exception ->
if (!continuation.isActive) return@fetchFromIssuer
when {
configuration != null -> continuation.resume(configuration)
exception != null && exception.isNetworkFailure() -> continuation.resume(null)
else -> continuation.resume(null)
configuration != null -> continuation.resume(ConfigurationOutcome.Success(configuration))
exception != null -> continuation.resume(ConfigurationOutcome.Error(exception))
else ->
continuation.resume(
ConfigurationOutcome.Error(
AuthorizationException.GeneralErrors.INVALID_DISCOVERY_DOCUMENT,
),
)
}
}
}
@@ -110,6 +118,8 @@ actual class OidcClient {
when {
exception != null -> continuation.resume(exception.toOidcError())
tokenResponse == null -> continuation.resume(OidcResult.AuthError("Token exchange returned no response"))
tokenResponse.accessToken.isNullOrBlank() ->
continuation.resume(OidcResult.AuthError("Token exchange returned no access token"))
else -> {
authState.update(tokenResponse, null)
continuation.resume(authState.toSuccess(tokenResponse))
@@ -276,4 +286,10 @@ actual class OidcClient {
data object Cancelled : AuthorizationOutcome
}
private sealed interface ConfigurationOutcome {
data class Success(val configuration: AuthorizationServiceConfiguration) : ConfigurationOutcome
data class Error(val exception: AuthorizationException) : ConfigurationOutcome
}
}