## OAuth Flow

If you have a service which needs to interact with the GitHub API on behalf of a user, you should use the OAuth flow. [Phil Haack](https://haacked.com) has written a great [blog post](http://haacked.com/archive/2014/04/24/octokit-oauth/) on using Octokit in ASP.NET, and even has a [demo project](https://github.com/Haacked/octokit-oauth-demo) you can try out, so this will just go over the specific APIs in more detail.

### Setup

First, you need to register your application on GitHub (or GitHub Enterprise). While logged in, go to your account settings and click the Applications tab. Then click "Register new application". 

Or just navigate to [https://github.com/settings/applications/new](https://github.com/settings/applications/new) if you're lazy.

Fill in some details about your application:

![application registration](https://cloud.githubusercontent.com/assets/19977/2760125/62600c38-c9ae-11e3-911f-783d7a34aeaf.png)

Then click "Register application", and you'll get your client id and client secret.

![OAuth application registration details](https://cloud.githubusercontent.com/assets/19977/2760128/95587e40-c9ae-11e3-84f2-053d2574f1e8.png)

### Starting the OAuth Flow

We'll use these in a few places, so define these as private fields:

```csharp
var clientId = "some-id-here";
var clientSecret = "some-id-here";
var client = new GitHubClient(new ProductHeaderValue("my-cool-app"));
```

To start the authentication flow, you need to craft a URL indicating your application needs to authenticate on behalf of the current user.

```csharp
// NOTE: this is not required, but highly recommended!
// ask the ASP.NET Membership provider to generate a random value 
// and store it in the current user's session
string csrf = Membership.GeneratePassword(24, 1);
Session["CSRF:State"] = csrf;

var request = new OauthLoginRequest(clientId)
{
    Scopes = {"user", "notifications"},
    State = csrf
};

// NOTE: user must be navigated to this URL
var oauthLoginUrl = client.Oauth.GetGitHubLoginUrl(request);
```

Scopes are keys which specify the permissions the application needs. If you don't specify a `Scopes` value, your application will only have read access to the user's public data (repository, user info, etc). There's lots of different scopes available for different interactions with user data, so have a look at the [documentation](https://developer.github.com/v3/oauth/#scopes) for more information.

### Generating the token

Once the user has been navigated to the URL above and clicked "Authorize Application", you will receive a callback at the default Callback URL for your application. If you require a more flexible URL, you can override this by specifying a different URL when creating the request.

```csharp
var request = new OauthLoginRequest(clientId)
{
    // other parameters
    RedirectUri = new Url("https://mycoolsite.com/some/uri")
};
```

The callback will have two parameters, the code generated by the GitHub API and some additional state - this is specifically to prevent CSRF (Cross-Site Request Forgery) attacks and is highly recommended.

With this code you can then request an access token by providing your client secret. This doesn't require any user interaction, so it can be done in the background.

```csharp
public async Task<ActionResult> Authorize(string code, string state)
{
    if (String.IsNullOrEmpty(code))
        return RedirectToAction("Index");

    var expectedState = Session["CSRF:State"] as string;
    if (state != expectedState) throw new InvalidOperationException("SECURITY FAIL!");
    Session["CSRF:State"] = null;

    var request = new OauthTokenRequest(clientId, clientSecret, code);
    var token = await client.Oauth.CreateAccessToken(request);
    Session["OAuthToken"] = token.AccessToken;

    return RedirectToAction("Index");
}
```

And now you have an access token, you can set up your credentials to use this token:

```csharp
// repositories which include public and private repositories.
public async Task<ActionResult> Index()
{
    var accessToken = Session["OAuthToken"] as string;
    if (accessToken != null)
    {
        client.Credentials = new Credentials(accessToken);
        
        var repositories = await client.Repository.GetAllForCurrent();
    }
    
    /* TODO: all the rest of the webapp */
}
```
