I am performing background uploads to an endpoint that requires authorization using a token. The token is included as an HTTP header to the individual upload tasks that are created/started.
Is it possible to respond to expired token messages and prevent 401s? Roughly, the timeline I am hoping to implement is:
- Start upload in foreground with valid token
- App is backgrounded, uploads continue but app itself is closed
- Some time passes, user is using device with other apps, etc.
- Token used in step 1 expires, and all uploads still in progress will require new token.
- App is launched in background, telling me that the auth token has expired.
- I refresh app token, and uploads are allowed to continue
- Uploads report success.
So far I've been unable to get this behavior - at step 5 instead of issuing a challenge/etc. that the session or task delegate can handle, I simply get 401 responses.
Setup config/session/task:
let config = URLSessionConfiguration.background(withIdentifier: "background_upload_session")
session = URLSession(configuration: config, delegate: self, delegateQueue: nil)
var request = URLRequest(url: NetworkService.uploadUrl)
request.httpMethod = "POST"
...
request.setValue(authToken, forHTTPHeaderField: "Authorization-Token")
...
let task = session.uploadTask(with: request, fromFile: filePath)
task.taskDescription = filePath.lastPathComponent
task.resume()
Delegate methods:
public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
if error != nil {
DDLogError("NetworkService urlSession didCompleteWithError:\(String(describing: error))")
}
if let httpResponse = task.response as? HTTPURLResponse {
let statusMessage = httpResponse.statusCode == 201 ? "success" : "fail"
DDLogInfo("NetworkService didCompleteWithError status code: \(httpResponse.statusCode) - \(statusMessage)")
}
}
public func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
DDLogInfo("NetworkService urlSession task didReceive challenge")
completionHandler(.performDefaultHandling, nil)
}
The didReceiveChallenge method is not called - which is what I was expecting in this case. Assuming it was called, I'm not sure how to respond with a new token in this situation.
Any ideas?