private static async Task HandleTokenRefreshFailure(HttpResponseMessage response) { // OneDrive specific logic: If the refresh token is expired, the server will return a 400 Bad Request // response with json content saying that the user must sign in. if (response.StatusCode == HttpStatusCode.BadRequest) { WindowsLiveError errorData = await response.Content.TryReadAsJsonAsync <WindowsLiveError>().ConfigureAwait(false); if (errorData != null && errorData.Error == "invalid_grant") { throw new OneDriveTokenRefreshFailedException("The refresh token is expired.", errorData); } } // Dev note: Try to understand all of the refresh token failures. Any expected failures should be // throw as OneDriveTokenRefreshFailedException. This is here as a catch-all. var exception = new OneDriveHttpException("Failed to refresh token.", response.StatusCode); if (response.Headers.Contains("WwwAuthenticate")) { exception.Data["HttpAuthenticationHeader"] = response.Headers.WwwAuthenticate; } throw exception; }
private async Task <HttpResponseMessage> SendOneDriveRequest(HttpRequestMessage request) { var response = await this.SendOneDriveRequest(request, this.oneDriveHttpClient).ConfigureAwait(false); // Any failures (including those from re-issuing after a refresh) will ne handled here if (!response.IsSuccessStatusCode) { throw OneDriveHttpException.FromResponse(response); } return(response); }
public static Exception FromResponse(HttpResponseMessage response) { string exceptionMessage = string.Format("The OneDrive service returned {0} ({1})", (int)response.StatusCode, response.ReasonPhrase); OneDriveErrorResponseContainer errorResponse = response.Content.TryReadAsJsonAsync <OneDriveErrorResponseContainer>().Result; var exception = new OneDriveHttpException(exceptionMessage, response.StatusCode); if (errorResponse != null) { exception.ErrorResponse = errorResponse.ErrorResponse; } foreach (KeyValuePair <string, IEnumerable <string> > responseHeader in response.Headers) { exception.ResponseHeaders.Add(responseHeader.Key, new List <string>(responseHeader.Value)); } return(exception); }
/// <summary> /// Send an HTTP request to the Live endpoint, handling the case when a token refresh is required. /// </summary> /// <remarks> /// The caller must provide the request to send. The authentication header will be set by this method. Any error /// returned by the call (including failure to refresh the token) will result in an exception being thrown. /// </remarks> private async Task <HttpResponseMessage> SendLiveRequest(HttpRequestMessage request) { var qsParams = request.RequestUri.GetQueryParameters(); qsParams["access_token"] = this.CurrentToken.AccessToken; var uriParts = request.RequestUri.ToString().Split(new [] { '?' }, 2); request.RequestUri = new Uri(uriParts[0] + UriExtensions.CombineQueryString(qsParams)); LogRequest(request, this.liveHttpClient.BaseAddress); HttpResponseMessage response = await this.liveHttpClient.SendAsync(request).ConfigureAwait(false); LogResponse(response); // Check for token refresh if (response.StatusCode == HttpStatusCode.Unauthorized) { string responseContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); bool refreshToken = false; try { JObject jObject = JObject.Parse(responseContent); refreshToken = Convert.ToString(jObject["error"]["code"]) == "request_token_expired"; } catch { // There was an error parsing the response from the server. } if (refreshToken) { // Refresh the current token await this.RefreshToken().ConfigureAwait(false); var newRequest = await request.Clone().ConfigureAwait(false); // Resend the request using the new token qsParams = newRequest.RequestUri.GetQueryParameters(); qsParams["access_token"] = this.CurrentToken.AccessToken; uriParts = newRequest.RequestUri.ToString().Split(new[] { '?' }, 2); newRequest.RequestUri = new Uri(uriParts[0] + UriExtensions.CombineQueryString(qsParams)); LogRequest(request, this.liveHttpClient.BaseAddress); response = await this.liveHttpClient.SendAsync(newRequest).ConfigureAwait(false); LogResponse(response); } } // Any failures (including those from re-issuing after a refresh) will be handled here if (!response.IsSuccessStatusCode) { var exception = new OneDriveHttpException("Live exception", response.StatusCode); exception.Data["Content"] = response.Content.ReadAsStringAsync().Result; throw exception; } return(response); }