Skip to content

Instantly share code, notes, and snippets.

@weitzhandler
Created November 2, 2015 02:58
Show Gist options
  • Save weitzhandler/4071da688485cdb49502 to your computer and use it in GitHub Desktop.
Save weitzhandler/4071da688485cdb49502 to your computer and use it in GitHub Desktop.
A HttpClient that handles bearer tokens
using Microsoft.Owin.Security.OAuth;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
namespace System.Net.Http
{
public class OAuthHttpClient : HttpClient
{
public OAuthHttpClient()
: base(new OAuthHttpClientHandler())
{
var type = typeof(HttpMessageInvoker);
var flags = BindingFlags.Instance | BindingFlags.NonPublic;
var field = type.GetField("handler", flags)
?? type.GetField("_handler", flags);
Handler = (OAuthHttpClientHandler)field.GetValue(this);
Handler.Client = this;
}
public string ClientId { get; set; }
public string ClientSecret { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string TokenUrl { get; set; }
public string AuthenticationType { get; set; } = OAuthDefaults.AuthenticationType;
public BearerToken Token { get; set; }
public BearerToken CurrentToken { get; set; }
public bool IsValid
{
get
{
return CurrentToken != null && !CurrentToken.HasExpired;
}
}
private readonly OAuthHttpClientHandler Handler;
private class OAuthHttpClientHandler : HttpClientHandler
{
public OAuthHttpClient Client { get; set; }
public virtual async Task RequestTokenAsync()
{
if (Client.IsValid)
return;
var data = new
{
grant_type = "password",
client_id = Client.ClientId,
client_secret = Client.ClientSecret,
username = Client.UserName,
password = Client.Password
};
var time = DateTime.UtcNow;
var tokenUrl = new Uri(Client.BaseAddress, Client.TokenUrl ?? "/token");
var response = await base.SendAsync(new HttpRequestMessage(HttpMethod.Post, tokenUrl) { Content = GetObjectContent(data) }, CancellationToken.None);
var result = await response.Content.ReadAsAsync<dynamic>();
Client.Token = new BearerToken(result.access_token, result.token_type, time, TimeSpan.FromSeconds(result.expires_in));
}
private static ObjectContent<T> GetObjectContent<T>(T value) => new ObjectContent<T>(value, new JsonMediaTypeFormatter());
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
await RequestTokenAsync();
request.Headers.Authorization = new AuthenticationHeaderValue(Client.AuthenticationType, Client.CurrentToken.Token);
return await base.SendAsync(request, cancellationToken);
}
}
}
public class BearerToken
{
public BearerToken(string token, string type, DateTime issuedUtc, TimeSpan validity)
{
_Token = token;
_Type = type;
_IssuedUtc = issuedUtc;
_Validity = validity;
}
private readonly string _Type;
public string Type
{
get
{
return _Type;
}
}
private readonly string _Token;
public string Token
{
get
{
return _Token;
}
}
private readonly DateTime _IssuedUtc;
public DateTime Issued
{
get
{
return _IssuedUtc;
}
}
private readonly TimeSpan _Validity;
public TimeSpan Validity
{
get
{
return _Validity;
}
}
public DateTime ExpiryUtc
{
get
{
return Issued.Add(Validity);
}
}
public bool HasExpired
{
get
{
return DateTime.UtcNow > ExpiryUtc;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment