@NonNull
  private AuthResponse refreshAccessToken(AuthResponse currentAuth)
      throws IOException, HttpResponseStatusException {
    OkHttpClient client = OkHttpUtil.getClient(context);
    Retrofit retrofit =
        new Retrofit.Builder()
            .client(client)
            .baseUrl(config.getApiHostURL())
            .addConverterFactory(GsonConverterFactory.create())
            .build();
    LoginService loginService = retrofit.create(LoginService.class);

    retrofit2.Response<AuthResponse> refreshTokenResponse;
    refreshTokenResponse =
        loginService
            .refreshAccessToken(
                "refresh_token", config.getOAuthClientId(), currentAuth.refresh_token)
            .execute();
    if (!refreshTokenResponse.isSuccessful()) {
      throw new HttpResponseStatusException(refreshTokenResponse.code());
    }
    AuthResponse refreshTokenData = refreshTokenResponse.body();
    loginPrefs.storeRefreshTokenResponse(refreshTokenData);
    return refreshTokenData;
  }
  @Override
  public synchronized Request authenticate(Route route, final Response response)
      throws IOException {
    logger.warn(response.toString());

    final AuthResponse currentAuth = loginPrefs.getCurrentAuth();
    if (null == currentAuth || null == currentAuth.refresh_token) {
      return null;
    }

    String errorCode = getErrorCode(response.peekBody(200).string());

    if (errorCode != null) {
      switch (errorCode) {
        case TOKEN_EXPIRED_ERROR_MESSAGE:
          final AuthResponse refreshedAuth;
          try {
            refreshedAuth = refreshAccessToken(currentAuth);
          } catch (HttpResponseStatusException e) {
            return null;
          }
          return response
              .request()
              .newBuilder()
              .header("Authorization", refreshedAuth.token_type + " " + refreshedAuth.access_token)
              .build();
        case TOKEN_NONEXISTENT_ERROR_MESSAGE:
        case TOKEN_INVALID_GRANT_ERROR_MESSAGE:
          // Retry request with the current access_token if the original access_token used in
          // request does not match the current access_token. This case can occur when
          // asynchronous calls are made and are attempting to refresh the access_token where
          // one call succeeds but the other fails. https://github.com/edx/edx-app-android/pull/834
          if (!response
              .request()
              .headers()
              .get("Authorization")
              .split(" ")[1]
              .equals(currentAuth.access_token)) {
            return response
                .request()
                .newBuilder()
                .header("Authorization", currentAuth.token_type + " " + currentAuth.access_token)
                .build();
          }
      }
    }
    return null;
  }