title: Refresh token with SwiftUI Combine
body: <p>I'm trying to implement a refresh token strategy in Swift 5 and the Combine Framework for iOS.</p>
  
  <p>I don't plan on using any third party package, just using what is provided by the framework, `URLSession.dataTaskPublisher`, so mu goal is to :</p>
  
  <ol>
  <li>Make a request</li>
  <li>If the request fails with 401, refresh the auth token (which is another request)
  
  <ol>
  <li>After the refresh token is done, retry the first request</li>
  <li>If it fails throw the error to be handled by the caller</li>
  </ol></li>
  </ol>
  
  <p>&#x200B;</p>
  
  <p>This is a very trivial use case, but seems to be very hard to implement in Combine, that makes it really hard to use in any real life scenario.</p>
  
  <p>Any help would be welcome !</p>
  
  <p>&#x200B;</p>
  
  <p>This is my try, which unfortonately doesn't work</p>
  
  <pre><code>private func dataTaskPublisherWithAuth(for request: URLRequest) -&gt; URLSession.DataTaskPublisher {
      return session.dataTaskPublisher(for: request)
  
          .tryCatch { error -&gt; URLSession.DataTaskPublisher in
  guard error.errorCode == 401 else {
  throw error
  }
  var components = URLComponents(url: self.baseUrl, resolvingAgainstBaseURL: true)
  components?.path += "/refresh"
  components?.queryItems = [
  URLQueryItem(name: "refresh_token", value: KeychainHelper.RefreshToken),
  ]
  
  let url = components?.url
  var loginRequest = URLRequest(url: url!)
  loginRequest.httpMethod = "GET"
  loginRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
  
  return session.dataTaskPublisher(for: loginRequest)
  .decode(type: LoginResponse.self, decoder: JSONDecoder())
  .map { result in
  if result.accessToken != nil {
  // Save access token
  KeychainHelper.AccessToken = result.accessToken!
  KeychainHelper.RefreshToken = result.refreshToken!
  KeychainHelper.ExpDate = Date(timeIntervalSinceNow: TimeInterval(result.expiresIn!))
  }
  return result
  }
  .flatMap { data -&gt; URLSession.DataTaskPublisher in
  session.dataTaskPublisher(for: request)
  }
      }.eraseToAnyPublsiher()
  
  }
  </code></pre>