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 token
is valid for1 hour
and can be used many times.The
refresh token
is valid for1 month
and is used when theaccess token
expires.The refresh
token 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