Skip to content

Add support for Bearer tokens. #15

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion PlanGrid.Api.Tests/ProjectsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,4 @@ public async Task CreateProject()
}
*/
}
}
}
4 changes: 3 additions & 1 deletion PlanGrid.Api/AutoGeneratedIPlanGridApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ public partial class AutoGeneratedIPlanGridApi
public RefitSettings Settings { get; private set; }
public string Version { get; private set; }
public int? MaxRetries { get; private set; }
public TokenType KeyType { get; private set; }

public void Initialize(string apiKey, RefitSettings settings, string version, int? maxRetries)
public void Initialize(string apiKey, RefitSettings settings, string version, int? maxRetries, TokenType keyType)
{
ApiKey = apiKey;
Settings = settings;
Version = version;
MaxRetries = maxRetries;
KeyType = keyType;

foreach (KeyValuePair<string, Func<HttpClient, object[], object>> methodImpl in methodImpls.ToArray())
{
Expand Down
3 changes: 2 additions & 1 deletion PlanGrid.Api/PlanGrid.Api.projitems
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,6 @@
<Compile Include="$(MSBuildThisFileDirectory)UploadVersionRequest.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Status.cs" />
<Compile Include="$(MSBuildThisFileDirectory)VirtualFile.cs" />
<Compile Include="$(MSBuildThisFileDirectory)TokenType.cs" />
</ItemGroup>
</Project>
</Project>
13 changes: 9 additions & 4 deletions PlanGrid.Api/PlanGridClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,20 @@ public class PlanGridClient
/// <param name="version">The version of the API you want to use.</param>
/// <param name="timeout">The maximum time that may elapse when making a call before timing out.</param>
/// <param name="maxRetries">The maximum number of attempts to make contacting the server in the event of a 503 service unavailable repsonse. This defaults to unlimited retries, with a delay between each attempt that multiplies by two.</param>
/// <param name="keyType">The type of API key provided by PlanGrid.</param>
/// <returns>An interface upon which you can invoke the various methods exposed via the Public PlanGrid API.</returns>
public static IPlanGridApi Create(string apiKey = null, string baseUrl = null, string version = "1", int timeout = 60, int? maxRetries = null)
public static IPlanGridApi Create(string apiKey = null, string baseUrl = null, string version = "1", int timeout = 60, int? maxRetries = null, TokenType keyType = TokenType.Unknown)
{
apiKey = apiKey ?? Settings.ApiKey ?? Environment.GetEnvironmentVariable("PLANGRIDAPIKEY");
if (apiKey == null)
{
throw new ArgumentException("An ApiKey is required. Either pass it in to this method, add it to your App.config file, or set the environment variable \"PLANGRIDAPIKEY\".", nameof(apiKey));
}
baseUrl = baseUrl ?? Settings.ApiBaseUrl ?? Environment.GetEnvironmentVariable("PLANGRIDAPIURL") ?? "https://io.plangrid.com";
if (keyType == TokenType.Unknown)
{
keyType = Settings.ApiKeyType ?? Environment.GetEnvironmentVariable("PLANGRIDAPIKEYTYPE") ?? TokenType.Basic;
}

string url = baseUrl;
var settings = new RefitSettings
Expand All @@ -48,13 +53,13 @@ public static IPlanGridApi Create(string apiKey = null, string baseUrl = null, s
}
};
var api = (AutoGeneratedIPlanGridApi)RestService.For<IPlanGridApi>(
new HttpClient(new PlanGridHttpHandler(apiKey, settings, version, maxRetries))
new HttpClient(new PlanGridHttpHandler(apiKey, settings, version, maxRetries, keyType))
{
BaseAddress = new Uri(url), Timeout = TimeSpan.FromSeconds(timeout)
},
settings);
api.Initialize(apiKey, settings, version, maxRetries);
api.Initialize(apiKey, settings, version, maxRetries, keyType);
return api;
}
}
}
}
28 changes: 19 additions & 9 deletions PlanGrid.Api/PlanGridHttpHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,15 @@ public class PlanGridHttpHandler : HttpClientHandler
public const HttpStatusCode RateLimitExceeded = (HttpStatusCode)429;

private string authenticationToken;
private TokenType tokenType;
private RefitSettings settings;
private string version;
private int? maxRetries;

public PlanGridHttpHandler(string accessToken, RefitSettings settings, string version, int? maxRetries)
public PlanGridHttpHandler(string accessToken, RefitSettings settings, string version, int? maxRetries, TokenType tokenType = TokenType.Basic)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this will probably require some callsite changes in PlanGridApiClient:

https://github.com/plangrid/plangrid-api-net/blob/master/PlanGrid.Api/PlanGridClient.cs#L50

            var api = (AutoGeneratedIPlanGridApi)RestService.For<IPlanGridApi>(
                new HttpClient(new PlanGridHttpHandler(apiKey, settings, version, maxRetries))
                {
                    BaseAddress = new Uri(url), Timeout = TimeSpan.FromSeconds(timeout)
                },
                settings);

i.e. you'll want to surface this new type in the Create method so clients have the opportunity to override the default scheme.

{
authenticationToken = BuildAuthenticationToken(accessToken);
authenticationToken = BuildAuthenticationToken(accessToken, tokenType);
this.tokenType = tokenType;
this.settings = settings;
this.version = version;
this.maxRetries = maxRetries;
Expand All @@ -42,7 +44,7 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
request.Content = new StringContent("", Encoding.UTF8, "application/json");
}

request.Headers.Authorization = new AuthenticationHeaderValue("Basic", authenticationToken);
request.Headers.Authorization = new AuthenticationHeaderValue(this.tokenType.ToString(), authenticationToken);
request.Headers.Accept.Add(MediaTypeWithQualityHeaderValue.Parse($"application/vnd.plangrid+json; version={version}"));

HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
Expand Down Expand Up @@ -79,12 +81,20 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
throw new FailedRequestException(HttpStatusCode.ServiceUnavailable, $"Service unavailable after retrying {maxRetries} times.");
}

private string BuildAuthenticationToken(string accessToken)
private string BuildAuthenticationToken(string accessToken, TokenType tokenType)
{
string unencoded = $"{accessToken}:";
byte[] authParamBytes = Encoding.ASCII.GetBytes(unencoded);
string encodedAuthParams = Convert.ToBase64String(authParamBytes);
return encodedAuthParams;
switch (tokenType)
{
case TokenType.Basic:
string unencoded = $"{accessToken}:";
byte[] authParamBytes = Encoding.ASCII.GetBytes(unencoded);
string encodedAuthParams = Convert.ToBase64String(authParamBytes);
return encodedAuthParams;
case TokenType.Bearer:
return accessToken;
default:
throw new InvalidEnumArgumentException();
}
}
}
}
}
15 changes: 15 additions & 0 deletions PlanGrid.Api/TokenType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Runtime.Serialization;

namespace PlanGrid.Api
{
public enum TokenType
{
Unknown,

[EnumMember(Value = "Basic")]
Basic,

[EnumMember(Value = "Bearer")]
Bearer
}
}