I've searched a lot before I post my question but unfortunately I wasn't able to find a solution to my question.
I develop an app that connects to a server that requires authentication using access token and refresh token.
The
access tokenis valid for1 hourand can be used many times.The
refresh tokenis valid for1 monthand is used when theaccess tokenexpires.The refreshtoken can be used only one time.
When the refresh token is used, I get a new refresh token as well in addition to the access token.
And here is my problem:
I wrote an APIClient class that handles all request that my app needs. This class works great, except when the access token expires. When the access token expires all requests that will run at this time will fail with a 401 code (unauthorized).
What I want is to find a solution that will refresh the access token using the refresh token and then retry all these requests that failed with status code 401. Keep in mind that the function that refreshes the token must be called only once because the refresh token is only valid for one use.
What I would like to do is to find a way to write my APIClient class so that it supports the refresh of the token and retry all requests that failed. I would be very grateful if you tell me how i can achieve this.
Take a look at the following source code of the getRequest and sendRefreshRequest.
func getRequestWith(requestType: FSRequestType, usingToken: Bool, parameters: RequestParameters?, completionClosure: @escaping (NetworkResult) -> Void) {
let sessioConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessioConfig, delegate: nil, delegateQueue: nil)
guard var URL = APIClient.baseURL?.appendingPathComponent(requestType.rawValue) else { return }
if let parameters = parameters {
URL = URL.appendingQueryParameters(parameters)
}
var request = URLRequest(url: URL)
request.httpMethod = "GET"
if usingToken {
let tokenString = "Bearer " + TokenManager.sharedManager.accessToken()!
request.addValue(tokenString, forHTTPHeaderField: "Authorization")
}
let task = session.dataTask(with: request) { (data, response, error) in
guard error == nil else { return completionClosure(.Error(error!.localizedDescription))}
guard let data = data else { return completionClosure(.Error("Could not load data")) }
let statusCode = (response as! HTTPURLResponse).statusCode
if statusCode == 401 {
//Handle refresh token
} else if statusCode == 200 {
let json = JSON(data: data)
let responseJSON = json["response"]
completionClosure(.Success(responseJSON))
} else {
completionClosure(.Error("Returned status code \(statusCode) from Get request with URL: \(request.url!)"))
}
}
task.resume()
}
func sendRefreshRequest() {
let session = URLSession(configuration: .default)
guard var URL = APIClient.baseURL?.appendingPathComponent(FSRequestType.RefreshToken.rawValue) else {return}
let URLParams = [
"refresh_token" : TokenManager.sharedManager.refreshToken()!
]
URL = URL.appendingQueryParameters(URLParams)
var request = URLRequest(url: URL)
request.httpMethod = "GET"
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
let statusCode = (response as! HTTPURLResponse).statusCode
if statusCode == 200 {
let json = JSON(data: data!)
if TokenManager.sharedManager.saveTokenWith(json) {
print("RefreshedToken")
} else {
print("Failed saving new token.")
SessionManager.sharedManager.deauthorize()
}
} else if statusCode == 400 {
print("The refresh token is invalid")
SessionManager.sharedManager.deauthorize()
}
})
task.resume()
}
Thanks