Skip to content

Commit

Permalink
Attempt to clarify GitHubApp docs (#1824)
Browse files Browse the repository at this point in the history
* Attempt to clarify GitHubApp docs

* Tweak additional notes formatting

* more tweaks
  • Loading branch information
ryangribble authored Jun 29, 2018
1 parent 23b25f5 commit ef1994d
Showing 1 changed file with 66 additions and 33 deletions.
99 changes: 66 additions & 33 deletions docs/github-apps.md
Original file line number Diff line number Diff line change
@@ -1,38 +1,56 @@
# Working with GitHub Apps

## Overview
## Introduction
GitHub Apps are a new type of integration offering narrow, specific permissions, compared to OAuth apps or user authentication.

To learn more, head to the GitHub Apps section under the GitHub Developer [Getting started with Building Apps](https://developer.github.com/apps/getting-started-with-building-apps/#using-github-apps) documentation.
:warning: Please ensure to follow the links to the official GitHub Developer documentation where they are referenced, as we do not want to include all of the detail in this walkthrough (and run the risk of it becoming out of date or incorrect)

To learn more about GitHub Apps, head to the GitHub Apps section under the GitHub Developer [Getting started with Building Apps](https://developer.github.com/apps/getting-started-with-building-apps/#using-github-apps) documentation.

## Overview

A GitHub App (known in Octokit as a `GitHubApp`) is a global entity on GitHub, that specifies permissions (read, write, none) it will be granted for various scopes and additionally defines a list of webhook events the app will be interested in.

A GitHub App (known in Octokit as a `GitHubApp`) specifies permissions (read, write, none) it will be granted for various scopes and also registers for various webhook events.
An "instance" of a GitHub App is then installed in an `Organization` or `User` account (known in Octokit as an `Installation`) where it is further limited to nominated (or all) repositories for that account.

A GitHub App is installed in an `Organization` or `User` account (known in Octokit as an `Installation`) where it is further limited to nominated (or all) repositories for that account.
An `Intsallation` of a `GitHubApp`, thus operates at the "intersection" between the globally defined permissions/scopes/webhooks of the GitHub App itself PLUS the Organization/User repositories that were nominated.

The [GitHub Api Documentation](https://developer.github.com/v3/apps/) on GitHub Apps contains more detailed information.

## Authentication

The below walkthrough outlines how to authenticate as a `GitHubApp` and an `Installation` using Octokit.net.
Authentication for GitHub Apps is reasonably complicated, as there are a few moving parts to take into account.

The below walkthrough outlines how to use Octokit.net to
- Authenticate as the `GitHubApp` itself using a temporary JWT token
- Query top level endpoints as the `GitHubApp`
- Generate a temporary Installation Token as the `GitHubApp`, to allow further authentication as a specific `Installation` of the `GitHubApp`
- Access specific endpoints as the `Installation`

Be sure to see the [GitHub Api Documentation](https://developer.github.com/apps/building-github-apps/authentication-options-for-github-apps/#authentication-options-for-github-apps) on GitHub Apps authentication, if you require more details.
Be sure to read the [GitHub Api Documentation](https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps) on GitHub Apps authentication, before proceeding!

## GitHub App Walkthrough

Each GitHub App has a private certificate (PEM file) generated through the GitHub website and possessed by the owner of the GitHub App. Authentication occurs using a time based JWT token, signed by the GitHub App's private certificate.
Each GitHub App has a private certificate (PEM file) which is [generated via the GitHub website](https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/#generating-a-private-key) by the owner of the GitHub App. Wherever the owner decides to host the GitHub App, it would need access to this private certificate, as it is the entry point to authentication with GitHub.

The first step in the authentication process, is to generate a temporary JWT token, signed by the GitHub App's private certificate. It also needs to include the GitHub App's unique Id, which is obtainable from the GitHub website.

:bulb: There are several ways to generate JWT tokens in .NET and this library aims to have minimal depdendencies on other libraries. Therefore the expectation is that your app will create the JWT token however you see fit, and pass it in to Octokit.net. The example below contains a hardcoded JWT token string as an example. See the Additional Notes section for one recommended library, to generate the JWT token.

:warning: GitHub enforces that the JWT token used can only be valid for a maximum of 10 minutes - a new token will be required after this time. In the future, Octokit.net may provide hooks/helpers to help you take care of this, but for now your appliction will need to handle this itself.

``` csharp
// A time based JWT token, signed by the GitHub App's private certificate
var jwtToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1MjA0Mjc3MTQsImV4cCI6MTUyMDQyODMxNCwiaXNzIjo5NzM1fQ.K-d3FKWKddMygFqvPZYWQusqhbF1LYfcIM0VbBq4uJsS9VkjhyXALlHmTJWjdblzx-U55lkZc_KWdJd6GlDxvoRb5w_9nrLcIFRbYVgi9XTYpCc3o5j7Qh3FvKxA1bzEs8XGrxjjE7-WJn_xi85ugFKTy9tlIRPa-PHeIOvNp4fz4ru8SFPoD4epiraeEyLfpU_ke-HYF7Ws7ar19zQkfJKRHSIFm1LxJ5MGKWT8pQBBUSGxGPgEG_tYI83aYw6cVx-DLV290bpr23LRUC684Wv_XabUDzXjPUYynAc01APZF6aN8B0LHdPbG8I6Yd74sQfmN-aHz5moz8ZNWLNm8Q";

// Use the JWT as a Bearer token
var gitHubClient = new GitHubClient(new ProductHeaderValue("MyApp"))
var appClient = new GitHubClient(new ProductHeaderValue("MyApp"))
{
Credentials = new Credentials(jwtToken, AuthenticationType.Bearer)
};
```

The authenticated `GitHubApp` can query various top level information about itself:
Now we have an authenticated `GitHubApp` (`appClient`), we can query various top level information about the `GitHubApp` itself:

``` csharp
// Get the current authenticated GitHubApp
Expand All @@ -46,13 +64,17 @@ var installation = await appClient.GetInstallation(123);

```

In order to do more than top level calls, a `GitHubApp` needs to authenticate as a specific `Installation` by creating a temporary installation token, and using that for authentication:
In order to do more than top level calls, a `GitHubApp` needs to authenticate as a specific `Installation` by creating a temporary Installation Token (currently these expire after 1 hour), and using that for authentication.

:bulb: The example below includes a hardcoded Installation Id, but this would typically come from a webhook payload (so a GitHub App knows which Installation it needs to authenticate as, to deal with the received webhook). See the Additional Notes section for more details on Installation Id's in webhooks.

:warning: These temporary Installation Tokens are only valid for 1 hour, and a new Installation Token will be required after this time. In the future, Octokit.net may provide hooks/helpers to help you take care of this, but for now your appliction will need to handle this itself.

``` csharp
// Create an Installation token for Insallation Id 123
var response = await appClient.CreateInstallationToken(123);

// NOTE - the token will expire!
// NOTE - the token will expire in 1 hour!
response.ExpiresAt;

// Create a new GitHubClient using the installation token as authentication
Expand All @@ -62,7 +84,7 @@ var installationClient = new GitHubClient(new ProductHeaderValue("MyApp-Installa
};
```

Once authenticated as an `Installation`, a [subset of regular API endpoints](https://developer.github.com/v3/apps/available-endpoints/) can be queried, using the permissions of the `GitHubApp` and repository settings of the `Installation`:
Once authenticated as an `Installation`, a [subset of regular API endpoints](https://developer.github.com/v3/apps/available-endpoints/) can be accessed, using the intersection of the permissions/scopes of the `GitHubApp` and the repositories nominated by the User/Organization as part of the `Installation`:

``` csharp
// Create a Comment on an Issue
Expand All @@ -71,10 +93,39 @@ Once authenticated as an `Installation`, a [subset of regular API endpoints](htt
var response = await installationClient.Issue.Comment.Create("owner", "repo", 1, "Hello from my GitHubApp Installation!");
```

## A Note on identifying Installation Id's
GitHub Apps can be registered for webhook events.
That concludes the walkthrough!

## Additional Notes

### A Note on JWT Tokens
Octokit.net aims to have no external dependencies, therefore we do not curently have the ability to generate/sign JWT tokens for you, and instead expect that you will pass in the appropriately signed JWT token required to authenticate the `GitHubApp`.

Luckily one of our contributors [@adriangodong](https://github.com/adriangodong) has created a library `GitHubJwt` ( [GitHub](https://github.com/adriangodong/githubjwt) | [NuGet](https://www.nuget.org/packages/githubjwt) ) which you can use as per the following example.

``` csharp
// Use GitHubJwt library to create the GitHubApp Jwt Token using our private certificate PEM file
var generator = new GitHubJwt.GitHubJwtFactory(
new GitHubJwt.FilePrivateKeySource("/path/to/pem_file"),
new GitHubJwt.GitHubJwtFactoryOptions
{
AppIntegrationId = 1, // The GitHub App Id
ExpirationSeconds = 600 // 10 minutes is the maximum time allowed
}
);

var jwtToken = generator.CreateEncodedJwtToken();

// Pass the JWT as a Bearer token to Octokit.net
var appClient = new GitHubClient(new ProductHeaderValue("MyApp"))
{
Credentials = new Credentials(jwtToken, AuthenticationType.Bearer)
};
```

### A Note on identifying Installation Id's
GitHub Apps specify which webhook events they are interested in, and when installed in a User/Organization account and restricted to some/all repositories, these webhooks will then be sent to the GitHub App's URL.

WebHook payloads sent to these registrations now include an extra field to indicate the Id of the GitHub App Installation that is associated with the received webhook.
WebHook payloads now include an extra field to indicate the Id of the GitHub App Installation that is associated with the received webhook.

Example webhook for an opened Pull Request:
``` json
Expand Down Expand Up @@ -111,21 +162,3 @@ var payload = serializer_.Deserialize<PullRequestEventPayload>(json);
// Create an Installation token for the associated Insallation Id
var response = await appClient.CreateInstallationToken(payload.Installation.Id);
```

## A Note on JWT Tokens
Octokit.net expects that you will pass in the appropriately signed JWT token required to authenticate the `GitHubApp`.

Luckily one of our contributors [@adriangodong](https://github.com/adriangodong) has created a library `GitHubJwt` ( [GitHub](https://github.com/adriangodong/githubjwt) | [NuGet](https://www.nuget.org/packages/githubjwt) ) which you can use to help with this (as long as you are targetting `netstandard2.0` or above).

``` csharp
var generator = new GitHubJwt.GitHubJwtFactory(
new GitHubJwt.FilePrivateKeySource("/path/to/pem_file"),
new GitHubJwt.GitHubJwtFactoryOptions
{
AppIntegrationId = 123, // The GitHub App Id
ExpirationSeconds = 600 // 10 minutes is the maximum time allowed
}
);

var jwtToken = generator.CreateEncodedJwtToken();
```

0 comments on commit ef1994d

Please sign in to comment.