Skip to content

Commit

Permalink
Merge pull request #17 from viagogo/auth_code_grant
Browse files Browse the repository at this point in the history
Added IOAuth2Client methods for the Authorization Code grant type
  • Loading branch information
akilburge committed Feb 20, 2016
2 parents dbc6db1 + 7e7edde commit f9d655a
Show file tree
Hide file tree
Showing 12 changed files with 279 additions and 16 deletions.
3 changes: 3 additions & 0 deletions ReleaseNotes.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
### New in 0.10.0 (Released 2016/02/20)
* Added IOAuth2Client methods for the Authorization Code grant type

### New in 0.9.0 (Released 2016/02/13)
* Added support for cancelling requests in the ISellerListingClient, IBatchClient and IUserClient

Expand Down
8 changes: 4 additions & 4 deletions SolutionInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
[assembly: AssemblyProductAttribute("GogoKit")]
[assembly: AssemblyCompanyAttribute("viagogo")]
[assembly: AssemblyCopyrightAttribute("Copyright viagogo 2016")]
[assembly: AssemblyVersionAttribute("0.9.0")]
[assembly: AssemblyFileVersionAttribute("0.9.0")]
[assembly: AssemblyInformationalVersionAttribute("0.9.0")]
[assembly: AssemblyVersionAttribute("0.10.0")]
[assembly: AssemblyFileVersionAttribute("0.10.0")]
[assembly: AssemblyInformationalVersionAttribute("0.10.0")]
[assembly: ComVisibleAttribute(false)]
namespace System {
internal static class AssemblyVersionInformation {
internal const string Version = "0.9.0";
internal const string Version = "0.10.0";
}
}
63 changes: 63 additions & 0 deletions src/GogoKit/Clients/IOAuth2Client.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,80 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using GogoKit.Models.Response;
using System;

namespace GogoKit.Clients
{
/// <summary>
/// Provides methods used in OAuth authentication.
/// </summary>
/// <remarks>See http://developer.viagogo.net/#authentication</remarks>
public interface IOAuth2Client
{
/// <summary>
/// Gets the URL where applications can obtain a user’s consent to make API calls
/// on their behalf.
/// </summary>
/// <param name="redirectUri">Application return URL where the authorization code
/// is sent. This must match the URL registered for your application</param>
/// <param name="scopes">The scopes that specify the type of access that
/// is needed.</param>
/// <remarks>
/// If the user accepts the request, viagogo will redirect them back to your
/// application's <paramref name="redirectUrl"/> with a temporary code that
/// can be exchanged for an access token.
/// </remarks>
Uri GetAuthorizationUrl(Uri redirectUri, IEnumerable<string> scopes);

/// <summary>
/// Gets the URL where applications can obtain a user’s consent to make API calls
/// on their behalf.
/// </summary>
/// <param name="redirectUri">Application return URL where the authorization code
/// is sent. This must match the URL registered for your application</param>
/// <param name="scopes">The scopes that specify the type of access that
/// is needed.</param>
/// <param name="state">An opaque value used to maintain state between the
/// authorize request and the callback.</param>
/// <remarks>
/// If the user accepts the request, viagogo will redirect them back to your
/// application's <paramref name="redirectUrl"/> with a temporary code that
/// can be exchanged for an access token.
/// </remarks>
Uri GetAuthorizationUrl(Uri redirectUri, IEnumerable<string> scopes, string state);

/// <summary>
/// Requests an OAuth access token.
/// </summary>
/// <param name="grantType">The OAuth2 grant type that should be used.</param>
/// <param name="scopes">The scopes that specify the type of access that
/// is needed.</param>
/// <param name="parameters">Other parameters that should be sent in the
/// request.</param>
Task<OAuth2Token> GetAccessTokenAsync(string grantType,
IEnumerable<string> scopes,
IDictionary<string, string> parameters);

/// <summary>
/// Requests an access token that will provide access to user-specific
/// data (purchases, sales, listings, etc).
/// </summary>
/// <param name="code">The authorization code that was sent to your
/// application’s return URL.</param>
/// <param name="scopes">The scopes that specify the type of access that
/// is needed.</param>
Task<OAuth2Token> GetAuthorizationCodeAccessTokenAsync(string code, IEnumerable<string> scopes);

/// <summary>
/// Requests an access token that will provide access to public, non-user-specific
/// data (events, listings, etc).
/// </summary>
Task<OAuth2Token> GetClientAccessTokenAsync(IEnumerable<string> scopes);

/// <summary>
/// Obtain additional access tokens in order to prolong access to a
/// user’s data.
/// </summary>
Task<OAuth2Token> RefreshAccessTokenAsync(OAuth2Token token);
}
}
47 changes: 44 additions & 3 deletions src/GogoKit/Clients/OAuth2Client.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,52 @@
using System.Threading.Tasks;
using GogoKit.Models.Response;
using HalKit.Http;
using HalKit.Services;
using HalKit.Models.Response;

namespace GogoKit.Clients
{
public class OAuth2Client : IOAuth2Client
{
private readonly IHttpConnection _connection;
private readonly IGogoKitConfiguration _configuration;
private readonly string _clientId;
private readonly ILinkResolver _linkResolver;

public OAuth2Client(IHttpConnection connection, IGogoKitConfiguration configuration)
public OAuth2Client(IHttpConnection connection,
IGogoKitConfiguration configuration,
string clientId)
{
Requires.ArgumentNotNull(connection, nameof(connection));
Requires.ArgumentNotNull(configuration, nameof(configuration));
Requires.ArgumentNotNullOrEmpty(clientId, nameof(clientId));

_connection = connection;
_configuration = configuration;
_clientId = clientId;
_linkResolver = new LinkResolver();
}

public Uri GetAuthorizationUrl(Uri redirectUri, IEnumerable<string> scopes)
{
return GetAuthorizationUrl(redirectUri, scopes, null);
}

public Uri GetAuthorizationUrl(Uri redirectUri, IEnumerable<string> scopes, string state)
{
Requires.ArgumentNotNull(redirectUri, nameof(redirectUri));
Requires.ArgumentNotNull(scopes, nameof(scopes));

return _linkResolver.ResolveLink(
new Link { HRef = _configuration.ViagogoAuthorizationEndpoint.OriginalString },
new Dictionary<string, string>()
{
["client_id"] = _clientId,
["response_type"] = "code",
["redirect_uri"] = redirectUri.OriginalString,
["scope"] = string.Join(" ", scopes),
["state"] = state
});
}

public async Task<OAuth2Token> GetAccessTokenAsync(
Expand All @@ -43,7 +74,7 @@ public async Task<OAuth2Token> GetAccessTokenAsync(
new FormUrlEncodedContent(parameters),
new Dictionary<string, IEnumerable<string>>
{
{"Accept", new[] {"application/json"}}
["Accept"] = new[] {"application/json"}
},
CancellationToken.None).ConfigureAwait(_configuration);
var token = response.BodyAsObject;
Expand All @@ -55,6 +86,16 @@ public async Task<OAuth2Token> GetAccessTokenAsync(
return token;
}

public Task<OAuth2Token> GetAuthorizationCodeAccessTokenAsync(string code, IEnumerable<string> scopes)
{
Requires.ArgumentNotNullOrEmpty(code, nameof(code));

return GetAccessTokenAsync(
"authorization_code",
scopes,
new Dictionary<string, string> {["code"] = code });
}

public Task<OAuth2Token> GetClientAccessTokenAsync(IEnumerable<string> scopes)
{
return GetAccessTokenAsync("client_credentials", scopes, new Dictionary<string, string>());
Expand All @@ -71,7 +112,7 @@ public Task<OAuth2Token> RefreshAccessTokenAsync(OAuth2Token token)
return GetAccessTokenAsync(
"refresh_token",
scopes,
new Dictionary<string, string> {{ "refresh_token", token.RefreshToken }});
new Dictionary<string, string> {["refresh_token"] = token.RefreshToken});
}
}
}
30 changes: 30 additions & 0 deletions src/GogoKit/Default.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using GogoKit.Enumerations;
using System;
using System.Collections.Generic;

namespace GogoKit
{
public static class Default
{
public static readonly IDictionary<ApiEnvironment, Uri> ViagogoApiRootEndpoints =
new Dictionary<ApiEnvironment, Uri>()
{
[ApiEnvironment.Production] = new Uri("https://api.viagogo.net/v2"),
[ApiEnvironment.Sandbox] = new Uri("https://sandbox.api.viagogo.net/v2")
};

public static readonly IDictionary<ApiEnvironment, Uri> ViagogoOAuthTokenEndpoints =
new Dictionary<ApiEnvironment, Uri>()
{
[ApiEnvironment.Production] = new Uri("https://account.viagogo.com/oauth2/token"),
[ApiEnvironment.Sandbox] = new Uri("https://sandbox.account.viagogo.com/oauth2/token")
};

public static readonly IDictionary<ApiEnvironment, Uri> ViagogoAuthorizationEndpoints =
new Dictionary<ApiEnvironment, Uri>()
{
[ApiEnvironment.Production] = new Uri("https://account.viagogo.com/authorize"),
[ApiEnvironment.Sandbox] = new Uri("https://sandbox.account.viagogo.com/authorize")
};
}
}
8 changes: 8 additions & 0 deletions src/GogoKit/Enumerations/ApiEnvironment.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace GogoKit.Enumerations
{
public enum ApiEnvironment
{
Production,
Sandbox
}
}
2 changes: 2 additions & 0 deletions src/GogoKit/GogoKit.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
<Compile Include="Clients\IWebhooksClient.cs" />
<Compile Include="Clients\SellerListingsClient.cs" />
<Compile Include="Clients\WebhooksClient.cs" />
<Compile Include="Enumerations\ApiEnvironment.cs" />
<Compile Include="Default.cs" />
<Compile Include="Http\BasicAuthenticationHandler.cs" />
<Compile Include="Http\BearerTokenAuthenticationHandler.cs" />
<Compile Include="Http\ErrorHandler.cs" />
Expand Down
65 changes: 60 additions & 5 deletions src/GogoKit/GogoKitConfiguration.cs
Original file line number Diff line number Diff line change
@@ -1,42 +1,97 @@
using System;
using GogoKit.Enumerations;
using HalKit;
using System.Threading;

namespace GogoKit
{
public class GogoKitConfiguration : IGogoKitConfiguration
{
public static readonly Uri DefaultViagogoApiRootEndpoint = new Uri("https://api.viagogo.net/v2");
public static readonly Uri DefaultViagogoOAuthTokenEndpoint = new Uri("https://www.viagogo.com/secure/oauth2/token");

private readonly HalKitConfiguration _halKitConfiguration;
private ApiEnvironment _apiEnvironment;

public GogoKitConfiguration()
{
_halKitConfiguration = new HalKitConfiguration(DefaultViagogoApiRootEndpoint)
_halKitConfiguration = new HalKitConfiguration(Default.ViagogoApiRootEndpoints[ApiEnvironment.Production])
{
CaptureSynchronizationContext = false
};
ViagogoOAuthTokenEndpoint = DefaultViagogoOAuthTokenEndpoint;
ViagogoApiEnvironment = ApiEnvironment.Production;
}

/// <summary>
/// The root endpoint of the API to get the root resource that links to
/// all other API resources.
/// </summary>
/// <remarks>See http://developer.viagogo.net/#explorable-api</remarks>
public Uri ViagogoApiRootEndpoint
{
get { return _halKitConfiguration.RootEndpoint; }
set { _halKitConfiguration.RootEndpoint = value; }
}

/// <summary>
/// The endpoint where OAuth2 access tokens are granted.
/// </summary>
/// <remarks>See http://developer.viagogo.net/#getting-access-tokens</remarks>
public Uri ViagogoOAuthTokenEndpoint { get; set; }

/// <summary>
/// The endpoint where applications can obtain a user’s consent to make API calls
/// on their behalf.
/// </summary>
/// <remarks>See http://developer.viagogo.net/#authorization-code-grant</remarks>
public Uri ViagogoAuthorizationEndpoint { get; set; }

/// <summary>
/// Determines which <see cref="ApiEnvironment"/> should be used. Setting
/// this value will configure the values for <see cref="ViagogoApiRootEndpoint"/>,
/// <see cref="ViagogoOAuthTokenEndpoint"/> and <see cref="ViagogoAuthorizationEndpoint"/>.
/// </summary>
/// <remarks>See http://developer.viagogo.net/#sandbox-environment</remarks>
public ApiEnvironment ViagogoApiEnvironment
{
get
{
return _apiEnvironment;
}
set
{
_apiEnvironment = value;
ViagogoApiRootEndpoint = Default.ViagogoApiRootEndpoints[_apiEnvironment];
ViagogoOAuthTokenEndpoint = Default.ViagogoOAuthTokenEndpoints[_apiEnvironment];
ViagogoAuthorizationEndpoint = Default.ViagogoAuthorizationEndpoints[_apiEnvironment];
}
}

/// <summary>
/// Determines whether asynchronous operations should capture the current
/// <see cref="SynchronizationContext"/>.
/// </summary>
/// <remarks>See http://blog.stephencleary.com/2012/02/async-and-await.html#avoiding-context.</remarks>
public bool CaptureSynchronizationContext
{
get { return _halKitConfiguration.CaptureSynchronizationContext; }
set { _halKitConfiguration.CaptureSynchronizationContext = value; }
}

/// <summary>
/// Determines the language of the API response content (e.g. event names
/// and error messages).
/// </summary>
/// <remarks>See http://developer.viagogo.net/#localization</remarks>
public string LanguageCode { get; set; }

/// <summary>
/// Determines the geography-context of requests.
/// </summary>
/// <remarks>See http://developer.viagogo.net/#localization</remarks>
public string CountryCode { get; set; }

/// <summary>
/// Determines the currency of responses that include monetary values.
/// </summary>
/// <remarks>See http://developer.viagogo.net/#localization</remarks>
public string CurrencyCode { get; set; }
}
}
2 changes: 1 addition & 1 deletion src/GogoKit/Http/HttpConnectionBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public HalKit.Http.HttpConnection Build()
.HttpClientHandler(_httpClientHandler)
.AdditionalHandlers(_additionalHandlers)
.Build();
var oauthClient = new OAuth2Client(oauthConnection, _configuration);
var oauthClient = new OAuth2Client(oauthConnection, _configuration, _clientId);
authenticationHandler = new BearerTokenAuthenticationHandler(oauthClient, _tokenStore, _configuration);
break;
}
Expand Down
Loading

0 comments on commit f9d655a

Please sign in to comment.