title: Retrofit POST request w/ Digest HTTP Authentication: “Cannot retry streamed HTTP body”
body: <p>I'm trying to implement digest authentication using Retrofit. My first solution sets an implementation of OkHttp's Authenticator on an OkHttpClient:</p>
  
  <pre><code>class MyAuthenticator implements Authenticator {
    private final DigestScheme digestScheme = new DigestScheme();
    private final Credentials credentials = new UsernamePasswordCredentials("user", "pass");
  
    @Override public Request authenticate(Proxy proxy, Response response) throws IOException {
      try {
        digestScheme.processChallenge(new BasicHeader("WWW-Authenticate", response.header("WWW-Authenticate")));
        HttpRequest request = new BasicHttpRequest(response.request().method(), response.request().uri().toString());
        String authHeader = digestScheme.authenticate(credentials, request).getValue();
        return response.request().newBuilder()
            .addHeader("Authorization", authHeader)
            .build();
      } catch (Exception e) {
        throw new AssertionError(e);
      }
    }
  
    @Override public Request authenticateProxy(Proxy proxy, Response response) throws IOException {
      return null;
    }
  }
  </code></pre>
  
  <p>This works perfectly for GET requests through Retrofit. However, as described in <a href="https://stackoverflow.com/q/21370620/1112407">this StackOverflow question</a>, POST requests result in a "Cannot retry streamed HTTP body" exception:</p>
  
  <pre><code>Caused by: java.net.HttpRetryException: Cannot retry streamed HTTP body
          at com.squareup.okhttp.internal.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:324)
          at com.squareup.okhttp.internal.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:508)
          at com.squareup.okhttp.internal.http.HttpsURLConnectionImpl.getResponseCode(HttpsURLConnectionImpl.java:136)
          at retrofit.client.UrlConnectionClient.readResponse(UrlConnectionClient.java:94)
          at retrofit.client.UrlConnectionClient.execute(UrlConnectionClient.java:49)
          at retrofit.RestAdapter$RestHandler.invokeRequest(RestAdapter.java:357)
          at retrofit.RestAdapter$RestHandler.invoke(RestAdapter.java:282)
          at $Proxy3.login(Native Method)
          at com.audax.paths.job.LoginJob.onRunInBackground(LoginJob.java:41)
          at com.audax.library.job.AXJob.onRun(AXJob.java:25)
          at com.path.android.jobqueue.BaseJob.safeRun(BaseJob.java:108)
          at com.path.android.jobqueue.JobHolder.safeRun(JobHolder.java:60)
          at com.path.android.jobqueue.executor.JobConsumerExecutor$JobConsumer.run(JobConsumerExecutor.java:172)
          at java.lang.Thread.run(Thread.java:841)
  </code></pre>
  
  <p>Jesse Wilson explains that we can't resend our request after authenticating, because the POST body has already been thrown out. But we need the returned <code>WWW-Authenticate</code> header because of digest authentication, so we can't use a <code>RequestInterceptor</code> to simply add a header. Maybe it's possible to perform a separate HTTP request in a <code>RequestInterceptor</code>, and use the <code>WWW-Authenticate</code> header in the response, but this seems hacky.</p>
  
  <p>Is there any way around this?</p>