diff --git a/webflows/src/main/java/com/schibsted/account/webflows/activities/AuthResultLiveData.kt b/webflows/src/main/java/com/schibsted/account/webflows/activities/AuthResultLiveData.kt index 59132ebe..75a734af 100644 --- a/webflows/src/main/java/com/schibsted/account/webflows/activities/AuthResultLiveData.kt +++ b/webflows/src/main/java/com/schibsted/account/webflows/activities/AuthResultLiveData.kt @@ -58,7 +58,14 @@ class AuthResultLiveData private constructor(private val client: Client) : client.handleAuthenticationResponse(intent) { result -> when (result) { is Right -> update(result) - is Left -> update(Left(NotAuthed.LoginFailed(result.value))) + is Left -> update( + Left( + when (result.value) { + is LoginError.CancelledByUser -> NotAuthed.CancelledByUser + else -> NotAuthed.LoginFailed(result.value) + } + ) + ) } } } diff --git a/webflows/src/main/java/com/schibsted/account/webflows/client/Client.kt b/webflows/src/main/java/com/schibsted/account/webflows/client/Client.kt index 36f1220e..4c03b420 100644 --- a/webflows/src/main/java/com/schibsted/account/webflows/client/Client.kt +++ b/webflows/src/main/java/com/schibsted/account/webflows/client/Client.kt @@ -28,7 +28,7 @@ import okhttp3.OkHttpClient import org.json.JSONException import org.json.JSONObject import timber.log.Timber -import java.util.* +import java.util.Date /** Represents a client registered with Schibsted account. */ class Client { @@ -93,7 +93,10 @@ class Client { * @param authRequest Authentication request parameters. */ @JvmOverloads - fun getAuthenticationIntent(context: Context, authRequest: AuthRequest = AuthRequest()): Intent { + fun getAuthenticationIntent( + context: Context, + authRequest: AuthRequest = AuthRequest() + ): Intent { val loginUrl = generateLoginUrl(authRequest) val intent: Intent = if (this.isCustomTabsSupported(context)) { buildCustomTabsIntent() @@ -161,15 +164,27 @@ class Client { val stored = stateStorage.getValue(AUTH_STATE_KEY, AuthState::class) ?: return callback(Left(LoginError.AuthStateReadError)) + val eidUserCancelError = mapOf( + "error" to "access_denied", + "error_description" to "EID authentication was canceled by the user" + ) + val error = authResponse["error"] + val errorDescription = authResponse["error_description"] + if (error != null && error == eidUserCancelError["error"] && errorDescription == eidUserCancelError["error_description"]) { + val oauthError = OAuthError(error, errorDescription) + callback(Left(LoginError.CancelledByUser(oauthError))) + return + } + if (stored.state != authResponse["state"]) { callback(Left(LoginError.UnsolicitedResponse)) return } + stateStorage.removeValue(AUTH_STATE_KEY) - val error = authResponse["error"] if (error != null) { - val oauthError = OAuthError(error, authResponse["error_description"]) + val oauthError = OAuthError(error, errorDescription) callback(Left(LoginError.AuthenticationErrorResponse(oauthError))) return } @@ -260,6 +275,7 @@ class Client { Left(RefreshTokenError.UnexpectedError("User has logged-out during token refresh")) } } + is Left -> { Timber.e("Failed to refresh token: $result") Left(RefreshTokenError.RefreshRequestFailed(result.value.cause)) @@ -318,6 +334,9 @@ sealed class LoginError { */ data class TokenErrorResponse(val error: OAuthError) : LoginError() + /** User canceled login. */ + data class CancelledByUser(val error: OAuthError) : LoginError() + /** Something went wrong. */ data class UnexpectedError(val message: String) : LoginError() }