Reputation: 61
Situation I need to fix - Imagine 2 requests are made in same time (when access token is not valid). Both try to refresh token but one of them will invalidate token for another one.
Is there any way how to:
Or do you have any idea how to solve this by other way?
This is how my request look like in every view controller:
AF.request(encodedURLRequest, interceptor: AuthInterceptor()).validate().responseData { (response) in
...
}
This is my AuthInterceptor:
final class AuthInterceptor: RequestInterceptor {
func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void) {
var adaptedUrlRequest = urlRequest
adaptedUrlRequest.setValue("Bearer \(UserDefaults.standard.getAccessToken())", forHTTPHeaderField: "Authorization")
completion(.success(adaptedUrlRequest))
}
func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) {
print("request \(request) failed")
if let response = request.task?.response as? HTTPURLResponse, response.statusCode == 403 {
guard let url = URL(string: Endpoint.login.url) else { return }
var urlRequest = URLRequest(url: url)
urlRequest.httpMethod = "POST"
urlRequest.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
let parameters: [String: String] = [
"refresh_token": UserDefaults.standard.getRefreshToken(),
"grant_type": "refresh_token"
]
guard let encodedURLRequest = try? URLEncodedFormParameterEncoder.default.encode(parameters,
into: urlRequest) else { return }
AF.request(encodedURLRequest).validate().responseData { (response) in
if let data = response.data {
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
if let loginResponse = try? decoder.decode(LoginResponse.self, from: data) {
UserDefaults.standard.setAccessToken(value: loginResponse.accessToken)
UserDefaults.standard.setRefreshToken(value: loginResponse.refreshToken)
completion(.retryWithDelay(1))
}
}
}
}
}
}
Upvotes: 2
Views: 1615
Reputation: 12770
You can use Alamofire's RequestRetrier
protocol (as part of the RequestInterceptor
protocol) to do this without having to manually start and stop requests.
Essentially, you need to know when a refresh is being performed and store any additional completion handlers from requests which failed because of the expired token. You can do this in your AuthInterceptor
class. Just make sure your implementation is thread safe!
Upvotes: 1