diff --git a/Octokit.Reactive/Clients/IObservableOauthClient.cs b/Octokit.Reactive/Clients/IObservableOauthClient.cs
new file mode 100644
index 0000000000..2afa944c00
--- /dev/null
+++ b/Octokit.Reactive/Clients/IObservableOauthClient.cs
@@ -0,0 +1,28 @@
+using System;
+
+namespace Octokit.Reactive
+{
+ public interface IObservableOauthClient
+ {
+ ///
+ /// Gets the URL used in the first step of the web flow. The Web application should redirect to this URL.
+ ///
+ /// Parameters to the Oauth web flow login url
+ ///
+ Uri GetGitHubLoginUrl(OauthLoginRequest request);
+
+ ///
+ /// Makes a request to get an access token using the code returned when GitHub.com redirects back from the URL
+ /// GitHub login url to the application.
+ ///
+ ///
+ /// If the user accepts your request, GitHub redirects back to your site with a temporary code in a code
+ /// parameter as well as the state you provided in the previous step in a state parameter. If the states don’t
+ /// match, the request has been created by a third party and the process should be aborted. Exchange this for
+ /// an access token using this method.
+ ///
+ ///
+ ///
+ IObservable CreateAccessToken(OauthTokenRequest request);
+ }
+}
diff --git a/Octokit.Reactive/Clients/ObservableOauthClient.cs b/Octokit.Reactive/Clients/ObservableOauthClient.cs
new file mode 100644
index 0000000000..db62a7e13d
--- /dev/null
+++ b/Octokit.Reactive/Clients/ObservableOauthClient.cs
@@ -0,0 +1,45 @@
+using System;
+using System.Reactive.Linq;
+using System.Reactive.Threading.Tasks;
+
+namespace Octokit.Reactive
+{
+ public class ObservableOauthClient : IObservableOauthClient
+ {
+ readonly IGitHubClient _client;
+
+ public ObservableOauthClient(IGitHubClient client)
+ {
+ Ensure.ArgumentNotNull(client, "client");
+
+ _client = client;
+ }
+
+ ///
+ /// Gets the URL used in the first step of the web flow. The Web application should redirect to this URL.
+ ///
+ /// Parameters to the Oauth web flow login url
+ ///
+ public Uri GetGitHubLoginUrl(OauthLoginRequest request)
+ {
+ return _client.Oauth.GetGitHubLoginUrl(request);
+ }
+
+ ///
+ /// Makes a request to get an access token using the code returned when GitHub.com redirects back from the URL
+ /// GitHub login url to the application.
+ ///
+ ///
+ /// If the user accepts your request, GitHub redirects back to your site with a temporary code in a code
+ /// parameter as well as the state you provided in the previous step in a state parameter. If the states don’t
+ /// match, the request has been created by a third party and the process should be aborted. Exchange this for
+ /// an access token using this method.
+ ///
+ ///
+ ///
+ public IObservable CreateAccessToken(OauthTokenRequest request)
+ {
+ return _client.Oauth.CreateAccessToken(request).ToObservable();
+ }
+ }
+}
diff --git a/Octokit.Reactive/IObservableGitHubClient.cs b/Octokit.Reactive/IObservableGitHubClient.cs
index ecc8dd89dc..c8983ff83f 100644
--- a/Octokit.Reactive/IObservableGitHubClient.cs
+++ b/Octokit.Reactive/IObservableGitHubClient.cs
@@ -8,6 +8,7 @@ public interface IObservableGitHubClient
IObservableActivitiesClient Activity { get; }
IObservableIssuesClient Issue { get; }
IObservableMiscellaneousClient Miscellaneous { get; }
+ IObservableOauthClient Oauth { get; }
IObservableOrganizationsClient Organization { get; }
IObservableRepositoriesClient Repository { get; }
IObservableGistsClient Gist { get; }
diff --git a/Octokit.Reactive/ObservableGitHubClient.cs b/Octokit.Reactive/ObservableGitHubClient.cs
index 8b251ecf84..cba117f23c 100644
--- a/Octokit.Reactive/ObservableGitHubClient.cs
+++ b/Octokit.Reactive/ObservableGitHubClient.cs
@@ -1,5 +1,4 @@
using System;
-using System.Net.Http.Headers;
namespace Octokit.Reactive
{
@@ -37,6 +36,7 @@ public ObservableGitHubClient(IGitHubClient gitHubClient)
Issue = new ObservableIssuesClient(gitHubClient);
Miscellaneous = new ObservableMiscellaneousClient(gitHubClient.Miscellaneous);
Notification = new ObservableNotificationsClient(gitHubClient);
+ Oauth = new ObservableOauthClient(gitHubClient);
Organization = new ObservableOrganizationsClient(gitHubClient);
Repository = new ObservableRepositoriesClient(gitHubClient);
SshKey = new ObservableSshKeysClient(gitHubClient);
@@ -56,6 +56,7 @@ public IConnection Connection
public IObservableActivitiesClient Activity { get; private set; }
public IObservableIssuesClient Issue { get; private set; }
public IObservableMiscellaneousClient Miscellaneous { get; private set; }
+ public IObservableOauthClient Oauth { get; private set; }
public IObservableOrganizationsClient Organization { get; private set; }
public IObservableRepositoriesClient Repository { get; private set; }
public IObservableGistsClient Gist { get; private set; }
diff --git a/Octokit.Reactive/Octokit.Reactive-Mono.csproj b/Octokit.Reactive/Octokit.Reactive-Mono.csproj
index 3882f838b4..911ea6eb7d 100644
--- a/Octokit.Reactive/Octokit.Reactive-Mono.csproj
+++ b/Octokit.Reactive/Octokit.Reactive-Mono.csproj
@@ -143,6 +143,8 @@
+
+
diff --git a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj
index acf6bfb085..c00d82cda0 100644
--- a/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj
+++ b/Octokit.Reactive/Octokit.Reactive-MonoAndroid.csproj
@@ -152,6 +152,8 @@
+
+
diff --git a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj
index 5996e3ff11..5c6cf52b50 100644
--- a/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj
+++ b/Octokit.Reactive/Octokit.Reactive-Monotouch.csproj
@@ -147,6 +147,8 @@
+
+
diff --git a/Octokit.Reactive/Octokit.Reactive.csproj b/Octokit.Reactive/Octokit.Reactive.csproj
index 801fbd704e..453b88aea3 100644
--- a/Octokit.Reactive/Octokit.Reactive.csproj
+++ b/Octokit.Reactive/Octokit.Reactive.csproj
@@ -73,7 +73,9 @@
Properties\SolutionInfo.cs
+
+
@@ -161,7 +163,6 @@
-
diff --git a/Octokit.Tests/Clients/OauthClientTests.cs b/Octokit.Tests/Clients/OauthClientTests.cs
new file mode 100644
index 0000000000..d009af682e
--- /dev/null
+++ b/Octokit.Tests/Clients/OauthClientTests.cs
@@ -0,0 +1,87 @@
+using System;
+using System.Net.Http;
+using System.Threading.Tasks;
+using NSubstitute;
+using Octokit;
+using Octokit.Tests;
+using Xunit;
+using Xunit.Extensions;
+
+public class OauthClientTests
+{
+ public class TheGetGitHubLoginUrlMethod
+ {
+ [Theory]
+ [InlineData("https://api.github.com", "https://github.com/login/oauth/authorize?client_id=secret")]
+ [InlineData("https://github.com", "https://github.com/login/oauth/authorize?client_id=secret")]
+ [InlineData("https://example.com", "https://example.com/login/oauth/authorize?client_id=secret")]
+ [InlineData("https://api.example.com", "https://api.example.com/login/oauth/authorize?client_id=secret")]
+ public void ReturnsProperAuthorizeUrl(string baseAddress, string expectedUrl)
+ {
+ var connection = Substitute.For();
+ connection.BaseAddress.Returns(new Uri(baseAddress));
+ var client = new OauthClient(connection);
+
+ var result = client.GetGitHubLoginUrl(new OauthLoginRequest("secret"));
+
+ Assert.Equal(new Uri(expectedUrl), result);
+ }
+
+ [Fact]
+ public void ReturnsUrlWithAllParameters()
+ {
+ var request = new OauthLoginRequest("secret")
+ {
+ RedirectUri = new Uri("https://example.com/foo?foo=bar"),
+ Scopes = { "foo", "bar" },
+ State = "canARY"
+ };
+ var connection = Substitute.For();
+ connection.BaseAddress.Returns(new Uri("https://api.github.com"));
+ var client = new OauthClient(connection);
+
+ var result = client.GetGitHubLoginUrl(request);
+
+ const string expected = "https://github.com/login/oauth/authorize?client_id=secret&redirect_uri=https://example.com/foo?foo=bar&scope=foo,bar&state=canARY";
+ Assert.Equal(expected, result.ToString());
+ Assert.Equal("?client_id=secret&redirect_uri=https%3A%2F%2Fexample.com%2Ffoo%3Ffoo%3Dbar&scope=foo%2Cbar&state=canARY", result.Query);
+ }
+ }
+
+ public class TheCreateAccessTokenMethod
+ {
+ [Fact]
+ public async Task PostsWithCorrectBodyAndContentType()
+ {
+ var responseToken = new OauthToken();
+ var response = Substitute.For>();
+ response.BodyAsObject.Returns(responseToken);
+ var connection = Substitute.For();
+ connection.BaseAddress.Returns(new Uri("https://api.github.com/"));
+ Uri calledUri = null;
+ FormUrlEncodedContent calledBody = null;
+ Uri calledHostAddress = null;
+ connection.PostAsync(
+ Arg.Do(uri => calledUri = uri),
+ Arg.Do
+
diff --git a/Octokit/Clients/IOAuthClient.cs b/Octokit/Clients/IOAuthClient.cs
new file mode 100644
index 0000000000..b0bde0191a
--- /dev/null
+++ b/Octokit/Clients/IOAuthClient.cs
@@ -0,0 +1,32 @@
+using System;
+using System.Threading.Tasks;
+
+namespace Octokit
+{
+ ///
+ /// Provides methods used in the OAuth web flow.
+ ///
+ public interface IOauthClient
+ {
+ ///
+ /// Gets the URL used in the first step of the web flow. The Web application should redirect to this URL.
+ ///
+ /// Parameters to the Oauth web flow login url
+ ///
+ Uri GetGitHubLoginUrl(OauthLoginRequest request);
+
+ ///
+ /// Makes a request to get an access token using the code returned when GitHub.com redirects back from the URL
+ /// GitHub login url to the application.
+ ///
+ ///
+ /// If the user accepts your request, GitHub redirects back to your site with a temporary code in a code
+ /// parameter as well as the state you provided in the previous step in a state parameter. If the states don’t
+ /// match, the request has been created by a third party and the process should be aborted. Exchange this for
+ /// an access token using this method.
+ ///
+ ///
+ ///
+ Task CreateAccessToken(OauthTokenRequest request);
+ }
+}
diff --git a/Octokit/Clients/OAuthClient.cs b/Octokit/Clients/OAuthClient.cs
new file mode 100644
index 0000000000..6c1b092aab
--- /dev/null
+++ b/Octokit/Clients/OAuthClient.cs
@@ -0,0 +1,65 @@
+using System;
+using System.Net.Http;
+using System.Threading.Tasks;
+
+namespace Octokit
+{
+ ///
+ /// Provides methods used in the OAuth web flow.
+ ///
+ public class OauthClient : IOauthClient
+ {
+ readonly IConnection connection;
+ readonly Uri hostAddress;
+
+ public OauthClient(IConnection connection)
+ {
+ Ensure.ArgumentNotNull(connection, "connection");
+
+ this.connection = connection;
+ var baseAddress = connection.BaseAddress ?? GitHubClient.GitHubDotComUrl;
+
+ // The Oauth login stuff uses https://github.com and not the https://api.github.com URLs.
+ hostAddress = baseAddress.Host.Equals("api.github.com")
+ ? new Uri("https://github.com")
+ : baseAddress;
+ }
+
+ ///
+ /// Gets the URL used in the first step of the web flow. The Web application should redirect to this URL.
+ ///
+ /// Parameters to the Oauth web flow login url
+ ///
+ public Uri GetGitHubLoginUrl(OauthLoginRequest request)
+ {
+ Ensure.ArgumentNotNull(request, "request");
+
+ return new Uri(hostAddress, ApiUrls.OauthAuthorize())
+ .ApplyParameters(request.ToParametersDictionary());
+ }
+
+ ///
+ /// Makes a request to get an access token using the code returned when GitHub.com redirects back from the URL
+ /// GitHub login url to the application.
+ ///
+ ///
+ /// If the user accepts your request, GitHub redirects back to your site with a temporary code in a code
+ /// parameter as well as the state you provided in the previous step in a state parameter. If the states don’t
+ /// match, the request has been created by a third party and the process should be aborted. Exchange this for
+ /// an access token using this method.
+ ///
+ ///
+ ///
+ public async Task CreateAccessToken(OauthTokenRequest request)
+ {
+ Ensure.ArgumentNotNull(request, "request");
+
+ var endPoint = ApiUrls.OauthAccessToken();
+
+ var body = new FormUrlEncodedContent(request.ToParametersDictionary());
+
+ var response = await connection.PostAsync(endPoint, body, "application/json", null, hostAddress);
+ return response.BodyAsObject;
+ }
+ }
+}
diff --git a/Octokit/GitHubClient.cs b/Octokit/GitHubClient.cs
index 00f7840541..97a663db6d 100644
--- a/Octokit/GitHubClient.cs
+++ b/Octokit/GitHubClient.cs
@@ -84,6 +84,7 @@ public GitHubClient(IConnection connection)
Issue = new IssuesClient(apiConnection);
Miscellaneous = new MiscellaneousClient(connection);
Notification = new NotificationsClient(apiConnection);
+ Oauth = new OauthClient(connection);
Organization = new OrganizationsClient(apiConnection);
Repository = new RepositoriesClient(apiConnection);
Gist = new GistsClient(apiConnection);
@@ -133,6 +134,7 @@ public Uri BaseAddress
public IActivitiesClient Activity { get; private set; }
public IIssuesClient Issue { get; private set; }
public IMiscellaneousClient Miscellaneous { get; private set; }
+ public IOauthClient Oauth { get; private set; }
public IOrganizationsClient Organization { get; private set; }
public IRepositoriesClient Repository { get; private set; }
public IGistsClient Gist { get; private set; }
diff --git a/Octokit/Helpers/ApiUrls.cs b/Octokit/Helpers/ApiUrls.cs
index 3d863ef995..9e4f2c52ce 100644
--- a/Octokit/Helpers/ApiUrls.cs
+++ b/Octokit/Helpers/ApiUrls.cs
@@ -17,6 +17,8 @@ public static class ApiUrls
static readonly Uri _currentUserNotificationsEndpoint = new Uri("notifications", UriKind.Relative);
static readonly Uri _currentUserAllIssues = new Uri("issues", UriKind.Relative);
static readonly Uri _currentUserOwnedAndMemberIssues = new Uri("user/issues", UriKind.Relative);
+ static readonly Uri _oauthAuthorize = new Uri("login/oauth/authorize", UriKind.Relative);
+ static readonly Uri _oauthAccesToken = new Uri("login/oauth/access_token", UriKind.Relative);
///
/// Returns the that returns all of the repositories for the currently logged in user in
@@ -1194,5 +1196,23 @@ public static Uri IsFollowing(string login, string following)
{
return "users/{0}/following/{1}".FormatUri(login, following);
}
+
+ ///
+ /// Creates the relative for initiating the OAuth Web login Flow
+ ///
+ ///
+ public static Uri OauthAuthorize()
+ {
+ return _oauthAuthorize;
+ }
+
+ ///
+ /// Creates the relative to request an OAuth access token.
+ ///
+ ///
+ public static Uri OauthAccessToken()
+ {
+ return _oauthAccesToken;
+ }
}
}
diff --git a/Octokit/Helpers/UriExtensions.cs b/Octokit/Helpers/UriExtensions.cs
index d3d3c10216..718cc795d9 100644
--- a/Octokit/Helpers/UriExtensions.cs
+++ b/Octokit/Helpers/UriExtensions.cs
@@ -44,7 +44,7 @@ public static Uri ApplyParameters(this Uri uri, IDictionary para
}
}
- string query = String.Join("&", p.Select(kvp => kvp.Key + "=" + kvp.Value));
+ string query = String.Join("&", p.Select(kvp => kvp.Key + "=" + Uri.EscapeDataString(kvp.Value)));
if (uri.IsAbsoluteUri)
{
var uriBuilder = new UriBuilder(uri)
diff --git a/Octokit/Http/Connection.cs b/Octokit/Http/Connection.cs
index c9ace05734..45b654067f 100644
--- a/Octokit/Http/Connection.cs
+++ b/Octokit/Http/Connection.cs
@@ -4,7 +4,6 @@
using System.Linq;
using System.Net;
using System.Net.Http;
-using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
using Octokit.Internal;
@@ -22,8 +21,8 @@ public class Connection : IConnection
static readonly ICredentialStore _anonymousCredentials = new InMemoryCredentialStore(Credentials.Anonymous);
readonly Authenticator _authenticator;
- readonly IHttpClient _httpClient;
readonly JsonHttpPipeline _jsonPipeline;
+ readonly IHttpClient _httpClient;
///
/// Creates a new connection instance used to make requests of the GitHub API.
@@ -194,6 +193,14 @@ public Task> PostAsync(Uri uri, object body, string accepts, str
return SendData(uri, HttpMethod.Post, body, accepts, contentType, CancellationToken.None);
}
+ public Task> PostAsync(Uri uri, object body, string accepts, string contentType, Uri baseAddress)
+ {
+ Ensure.ArgumentNotNull(uri, "uri");
+ Ensure.ArgumentNotNull(body, "body");
+
+ return SendData(uri, HttpMethod.Post, body, accepts, contentType, CancellationToken.None, baseAddress: baseAddress);
+ }
+
public Task> PutAsync(Uri uri, object body)
{
return SendData(uri, HttpMethod.Put, body, null, null, CancellationToken.None);
@@ -217,7 +224,8 @@ Task> SendData(
string accepts,
string contentType,
CancellationToken cancellationToken,
- string twoFactorAuthenticationCode = null
+ string twoFactorAuthenticationCode = null,
+ Uri baseAddress = null
)
{
Ensure.ArgumentNotNull(uri, "uri");
@@ -225,7 +233,7 @@ Task> SendData(
var request = new Request
{
Method = method,
- BaseAddress = BaseAddress,
+ BaseAddress = baseAddress ?? BaseAddress,
Endpoint = uri,
};
diff --git a/Octokit/Http/IConnection.cs b/Octokit/Http/IConnection.cs
index 94ed197899..7d2d335ab3 100644
--- a/Octokit/Http/IConnection.cs
+++ b/Octokit/Http/IConnection.cs
@@ -76,6 +76,23 @@ public interface IConnection
/// representing the received HTTP response
Task> PostAsync(Uri uri, object body, string accepts, string contentType);
+ ///
+ /// Performs an asynchronous HTTP POST request.
+ /// Attempts to map the response body to an object of type
+ ///
+ ///
+ /// We have one case where we need to override the BaseAddress. This overload is for that case.
+ /// https://developer.github.com/v3/oauth/#web-application-flow
+ ///
+ /// The type to map the response to
+ /// URI endpoint to send request to
+ /// The object to serialize as the body of the request
+ /// Specifies accepted response media types.
+ /// Specifies the media type of the request body
+ /// Allows overriding the base address for a post.
+ /// representing the received HTTP response
+ Task> PostAsync(Uri uri, object body, string accepts, string contentType, Uri baseAddress);
+
///
/// Performs an asynchronous HTTP PUT request.
/// Attempts to map the response body to an object of type
diff --git a/Octokit/Http/JsonHttpPipeline.cs b/Octokit/Http/JsonHttpPipeline.cs
index 3eea0d4e73..8bf6229ca8 100644
--- a/Octokit/Http/JsonHttpPipeline.cs
+++ b/Octokit/Http/JsonHttpPipeline.cs
@@ -33,7 +33,7 @@ public void SerializeRequest(IRequest request)
}
if (request.Method == HttpMethod.Get || request.Body == null) return;
- if (request.Body is string || request.Body is Stream) return;
+ if (request.Body is string || request.Body is Stream || request.Body is HttpContent) return;
request.Body = _serializer.Serialize(request.Body);
}
diff --git a/Octokit/IGitHubClient.cs b/Octokit/IGitHubClient.cs
index d7b0a222bb..ba5da49043 100644
--- a/Octokit/IGitHubClient.cs
+++ b/Octokit/IGitHubClient.cs
@@ -13,6 +13,7 @@ public interface IGitHubClient
IActivitiesClient Activity { get; }
IIssuesClient Issue { get; }
IMiscellaneousClient Miscellaneous { get; }
+ IOauthClient Oauth { get; }
IOrganizationsClient Organization { get; }
IRepositoriesClient Repository { get; }
IGistsClient Gist { get; }
diff --git a/Octokit/Models/Request/OauthLoginRequest.cs b/Octokit/Models/Request/OauthLoginRequest.cs
new file mode 100644
index 0000000000..501d0cbf2f
--- /dev/null
+++ b/Octokit/Models/Request/OauthLoginRequest.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.Globalization;
+using Octokit.Internal;
+
+namespace Octokit
+{
+ [DebuggerDisplay("{DebuggerDisplay,nq}")]
+ public class OauthLoginRequest : RequestParameters
+ {
+ ///
+ /// Creates an instance of the OAuth login request with the required parameter.
+ ///
+ /// The client ID you received from GitHub when you registered the application.
+ public OauthLoginRequest(string clientId)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(clientId, "clientId");
+
+ ClientId = clientId;
+ Scopes = new Collection();
+ }
+
+ ///
+ /// The client ID you received from GitHub when you registered the application.
+ ///
+ [Parameter(Key = "client_id")]
+ public string ClientId { get; private set; }
+
+ ///
+ /// The URL in your app where users will be sent after authorization.
+ ///
+ ///
+ /// See the documentation about redirect urls
+ /// for more information.
+ ///
+ [Parameter(Key = "redirect_uri")]
+ public Uri RedirectUri { get; set; }
+
+ ///
+ /// A set of scopes to request. If not provided, scope defaults to an empty list of scopes for users that don’t
+ /// have a valid token for the app. For users who do already have a valid token for the app, the user won’t be
+ /// shown the OAuth authorization page with the list of scopes. Instead, this step of the flow will
+ /// automatically complete with the same scopes that were used last time the user completed the flow.
+ ///
+ ///
+ /// See the scopes documentation for more
+ /// information about scopes.
+ ///
+ [Parameter(Key = "scope")]
+ public Collection Scopes { get; private set; }
+
+ ///
+ /// An unguessable random string. It is used to protect against cross-site request forgery attacks. In ASP.NET
+ /// MVC this would correspond to an anti-forgery token.
+ ///
+ [Parameter(Key = "state")]
+ public string State { get; set; }
+
+ internal string DebuggerDisplay
+ {
+ get
+ {
+ return String.Format(CultureInfo.InvariantCulture, "ClientId: {0}, RedirectUri: {1}, Scopes: {2}",
+ ClientId,
+ RedirectUri,
+ Scopes);
+ }
+ }
+ }
+}
diff --git a/Octokit/Models/Request/OauthTokenRequest.cs b/Octokit/Models/Request/OauthTokenRequest.cs
new file mode 100644
index 0000000000..d142462b74
--- /dev/null
+++ b/Octokit/Models/Request/OauthTokenRequest.cs
@@ -0,0 +1,69 @@
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using Octokit.Internal;
+
+namespace Octokit
+{
+ [DebuggerDisplay("{DebuggerDisplay,nq}")]
+ public class OauthTokenRequest : RequestParameters
+ {
+ ///
+ /// Creates an instance of the OAuth login request with the required parameter.
+ ///
+ /// The client ID you received from GitHub when you registered the application.
+ /// The client secret you received from GitHub when you registered.
+ /// The code you received as a response to making the OAuth login request
+ public OauthTokenRequest(string clientId, string clientSecret, string code)
+ {
+ Ensure.ArgumentNotNullOrEmptyString(clientId, "clientId");
+ Ensure.ArgumentNotNullOrEmptyString(clientSecret, "clientSecret");
+ Ensure.ArgumentNotNullOrEmptyString(code, "code");
+
+ ClientId = clientId;
+ ClientSecret = clientSecret;
+ Code = code;
+ }
+
+ ///
+ /// The client ID you received from GitHub when you registered the application.
+ ///
+ [Parameter(Key = "client_id")]
+ public string ClientId { get; private set; }
+
+ ///
+ /// The client secret you received from GitHub when you registered.
+ ///
+ [Parameter(Key = "client_secret")]
+ public string ClientSecret { get; private set; }
+
+ ///
+ /// The code you received as a response to making the OAuth login
+ /// request.
+ ///
+ [Parameter(Key = "code")]
+ public string Code { get; private set; }
+
+ ///
+ /// The URL in your app where users will be sent after authorization.
+ ///
+ ///
+ /// See the documentation about redirect urls
+ /// for more information.
+ ///
+ [Parameter(Key = "redirect_uri")]
+ public Uri RedirectUri { get; set; }
+
+ internal string DebuggerDisplay
+ {
+ get
+ {
+ return String.Format(CultureInfo.InvariantCulture, "ClientId: {0}, ClientSecret: {1}, Code: {2}, RedirectUri: {3}",
+ ClientId,
+ ClientSecret,
+ Code,
+ RedirectUri);
+ }
+ }
+ }
+}
diff --git a/Octokit/Models/Request/RequestParameters.cs b/Octokit/Models/Request/RequestParameters.cs
index 62ad0fee8e..ba69623ec3 100644
--- a/Octokit/Models/Request/RequestParameters.cs
+++ b/Octokit/Models/Request/RequestParameters.cs
@@ -80,7 +80,7 @@ static Func GetValueFunc(Type propertyType)
}
return (prop, value) => value != null
- ? value.ToString().ToLowerInvariant()
+ ? value.ToString()
: null;
}
diff --git a/Octokit/Models/Response/OauthToken.cs b/Octokit/Models/Response/OauthToken.cs
new file mode 100644
index 0000000000..5a4c9244eb
--- /dev/null
+++ b/Octokit/Models/Response/OauthToken.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Globalization;
+
+namespace Octokit
+{
+ [DebuggerDisplay("{DebuggerDisplay,nq}")]
+ public class OauthToken
+ {
+ ///
+ /// The type of OAuth token
+ ///
+ public string TokenType { get; set; }
+
+ ///
+ /// The secret OAuth access token. Use this to authenticate Octokit.net's client.
+ ///
+ public string AccessToken { get; set; }
+
+ ///
+ /// The list of scopes the token includes.
+ ///
+ public IReadOnlyCollection Scope { get; set; }
+
+ internal string DebuggerDisplay
+ {
+ get
+ {
+ return String.Format(CultureInfo.InvariantCulture, "TokenType: {0}, AccessToken: {1}, Scopes: {2}",
+ TokenType,
+ AccessToken,
+ Scope);
+ }
+ }
+ }
+}
diff --git a/Octokit/Octokit-Mono.csproj b/Octokit/Octokit-Mono.csproj
index 3c26538ddb..49a7ba63c5 100644
--- a/Octokit/Octokit-Mono.csproj
+++ b/Octokit/Octokit-Mono.csproj
@@ -315,6 +315,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Octokit/Octokit-MonoAndroid.csproj b/Octokit/Octokit-MonoAndroid.csproj
index 7a5e1ce18a..bdd41ca38b 100644
--- a/Octokit/Octokit-MonoAndroid.csproj
+++ b/Octokit/Octokit-MonoAndroid.csproj
@@ -326,6 +326,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Octokit/Octokit-Monotouch.csproj b/Octokit/Octokit-Monotouch.csproj
index c04a85cd03..aedc78de30 100644
--- a/Octokit/Octokit-Monotouch.csproj
+++ b/Octokit/Octokit-Monotouch.csproj
@@ -321,6 +321,11 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/Octokit/Octokit-Portable.csproj b/Octokit/Octokit-Portable.csproj
index 72f12cbd46..b1b9655c84 100644
--- a/Octokit/Octokit-Portable.csproj
+++ b/Octokit/Octokit-Portable.csproj
@@ -312,6 +312,11 @@
+
+
+
+
+
diff --git a/Octokit/Octokit-netcore45.csproj b/Octokit/Octokit-netcore45.csproj
index 31cf5cefea..0cd0eb91f4 100644
--- a/Octokit/Octokit-netcore45.csproj
+++ b/Octokit/Octokit-netcore45.csproj
@@ -316,6 +316,11 @@
+
+
+
+
+
diff --git a/Octokit/Octokit.csproj b/Octokit/Octokit.csproj
index 121a66e52f..dd956b6c42 100644
--- a/Octokit/Octokit.csproj
+++ b/Octokit/Octokit.csproj
@@ -54,7 +54,9 @@
Properties\SolutionInfo.cs
+
+
@@ -66,6 +68,8 @@
+
+
@@ -140,6 +144,7 @@
+