I found this example on How to refresh oauth token using moya and rxswift which I had to alter slightly to get to compile. This code works 80% for my scenario. The problem with it is that it will run for all http errors, and not just 401 errors. What I want is to have all my other http errors passed on as errors, so that I can handle them else where and not swallow them here.
With this code, if I get a HttpStatus 500
, it will run the authentication code 3 times which is obviously not what I want.
Ive tried to alter this code to handle only handle 401
errors, but it seem that no matter what I do I can't get the code to compile. It's always complaining about wrong return type, "Cannot convert return expression of type Observable<Response> to return type Observable<Response>"
which makes no sense to me..
What I want: handle 401, but stop on all other errors
import RxSwift
import KeychainAccess
import Moya
public extension ObservableType where E == Response {
/// Tries to refresh auth token on 401 errors and retry the request.
/// If the refresh fails, the signal errors.
public func retryWithAuthIfNeeded() -> Observable<E> {
return self.retryWhen {
(e: Observable<ErrorType>) in
return Observable.zip(e, Observable.range(start: 1, count: 3), resultSelector: { $1 })
.flatMap { i in
return AuthProvider.sharedInstance.request(
.LoginFacebookUser(
accessToken: AuthenticationManager.defaultInstance().getLoginTokenFromKeyChain(),
useFaceBookLogin: AuthenticationManager.defaultInstance().isFacebookLogin())
)
.filterSuccessfulStatusCodes()
.mapObject(Accesstoken.self)
.catchError {
error in
log.debug("ReAuth error: \(error)")
if case Error.StatusCode(let response) = error {
if response.statusCode == 401 {
// Force logout after failed attempt
log.debug("401:, force user logout")
NSNotificationCenter.defaultCenter().postNotificationName(Constants.Notifications.userNotAuthenticated, object: nil, userInfo: nil)
}
}
return Observable.error(error)
}.flatMapLatest({
token -> Observable<Accesstoken> in
AuthenticationManager.defaultInstance().storeServiceTokenInKeychain(token)
return Observable.just(token)
})
}
}
}
}