Making Oauth request asynchronously, with retry if token has expired

I’m struggling with asynchronous code. Does anyone have suggestions of a better way to do the following?

What I’m doing: hitting an API (google’s, actually), with a call that might get a 401 if the oauth access token has expired. If that happens, I call out to a different endpoint to refresh the access token, and then try the original call again.

Constraints: I’m trying to do this without any external libraries, which (alas) means no promises. Also, I’d prefer not to implement the delegation pattern, even though I know that’s idiomatic swift, just because I dislike classes and the rest of the cumbersome baggage that delegation creates. But maybe I just need to get over that?

Thus, the best solution I can come up with is a monstrosity that involves a factory function that returns a function that rewrites the original request with a new token (passed as a get parameter for GoodReasons™) and calls it, this function itself passed as a callback to the function that goes and refreshes the token. That seems… like a terrible unintuitive and ugly way to do it. But I can’t dream up anything simpler.

The code looks like this:

func postData(callback:@escaping (Data) -> Void){ // ... snip... the initial request if resp.statusCode == 401 {                     retryCall(request: request, callback: callback)                     return }  func retryCall(request: URLRequest, callback:@escaping (Data) -> Void){     let newPostFunction = refresherCallbackFactory(request: request, callback: callback)     refreshAccess(callback: newPostFunction) }  func refresherCallbackFactory(request: URLRequest, callback:@escaping (Data) -> Void) -> (String) -> Void {     func tokenTaker(_ tokenJSON: String) {         let tjParsed = parseRefreshTokenJson(json: .utf8)!)         let token = tjParsed.accessToken         var url = request.url!         var newRequest = request         var components = URLComponents(url: url, resolvingAgainstBaseURL: false)!         components.queryItems = [             URLQueryItem(name: "uploadType", value: "multipart"),             URLQueryItem(name: "access_token", value: token)         ]         url = components.url!         newRequest.url = url          let session = URLSession.shared         // ...snip... code generating a task based on the rebuilt request and handling errors, which calls the original callback on success per next line             callback(data!)         })         task.resume()         }     return tokenTaker }  func refreshAccess(callback:@escaping (String) -> Void){     let endpoint = ""     let queries = ["refresh_token": refreshToken.get()!,                    "client_id": clientKey.get()!,                    "grant_type": "refresh_token"]     post(url: endpoint, queries: queries, callback: callback)  // post is a generic helper function for issuing post requests } 

This runs just fine, but it seems like so so so much of a code smell…