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