Search code examples
swiftjwttokenalamofireinterceptor

Correct Alamofire retry for JWT if status 401?


I am trying to make a retry for my Alamofire Interceptor because I work with JSON Web Token. Adapt works great. But the server updates the Access token every 10 minutes after user registration or authorization. After 10 mins Access token doesn't work anymore, and the server response is 401. So I need to Refresh the token when the status is 401. As I mentioned above, adapt works great. But I need help understanding how to deal with retry. Below is my Interceptor:

class RequestInterceptor: Alamofire.RequestInterceptor {

    func adapt( _ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
    var urlRequest = urlRequest
            urlRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
            completion(.success(urlRequest))
    }

    func retry( _ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
        
        guard let response = request.task?.response as? HTTPURLResponse, response.statusCode == 401 else {
            completion(.doNotRetryWithError(error))
            return
        }
    }

}

My View Model:

func refreshTokenFunc() {
        
        AF.request(TabBarModel.Request.refreshTokenUrl, method: .post, parameters: parameters, encoder: JSONParameterEncoder.default, interceptor: RequestInterceptor()).response { response in
...

And usage (I work with SwiftUI):

.task {
            tabBarViewModel.refreshTokenFunc()
        }

I was trying with some examples from the Internet. But it doesn't work for me.


Solution

  • In you retry you need to call the completion handler on both sides of the guard, not just in the else side. completion(.retry) is common but you could also track a delay to make sure you don't overload the backend.

    Additionally, you should be validating response and checking the error, not reaching directly into request.task.

    AF.request(...).validate()... // Ensure the response code is within range.
    
    // In retry
    
    guard let error = error.asAFError, error.responseCode == 401 else { ... }