Skip to content
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

[Documentation] :: Add GitHub App Developer Guide #586

Merged
merged 4 commits into from
Nov 1, 2019
Merged
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
28 changes: 28 additions & 0 deletions src/site/apt/githubappappinsttokenauth.apt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
Authenticating as an installation

In order to authenticate to GitHub as an installation of your GitHub App, you must use the App Installation Token
authentication mechanism. This can be achieved with by creating a <<<GitHub>>> instance like this:

+-----+
GitHub githubAuthAsInst = new GitHubBuilder()
.withAppInstallationToken(appInstallationToken.getToken())
.build();
+-----+

How do I create an App Installation Token?

Assuming that you followed the {{{/githubappjwtauth.html} GitHub App Authentication via JWT token guide}} then you
can create the App Installation Token like this:

+-----+
String jwtToken = createJWT("44435", 600000); //sdk-github-api-app-test
GitHub gitHubApp = new GitHubBuilder().withJwtToken(jwtToken).build();
GHAppInstallation appInstallation = gitHubApp.getApp().getInstallationById(111111); // Installation Id

Map<String, GHPermissionType> permissions = new HashMap<>();
permissions.put("pull_requests", GHPermissionType.WRITE);

GHAppInstallationToken appInstallationToken = appInstallation
.createToken(permissions)
.create();
+-----+
41 changes: 41 additions & 0 deletions src/site/apt/githubappflow.apt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
GitHub App Auth Flow

GitHub Apps are commonly mistaken for OAuth Apps due to their similarities but understanding the differences between
them will help you decide which kind of app you want to create.

In a nutshell, an OAuth App acts as a GitHub user, whereas a GitHub App uses its own identity when installed on an
organization or on repositories within an organization. For a comprehensive comparision please refer to the official
GitHub {{{https://developer.github.com/apps/differences-between-apps/}documentation}}.

For this guide, we are going assume that you are using a GitHub App.

Overview

Assuming that your GitHub app has already been installed on either a user or an organization, the programmatic flow
the developer must follow in order to be able to authenticate on their behalf is:

[images/GitHub_App_Auth_Flow.jpg] GitHub_App_Auth_Flow

Multiple <<<GitHub>>> instances will have to be created and each of them will be using a different authentication
mechanism. Some actions are only accessible if you are authenticated as a GitHub App while others will only be
possible if you are authenticated on behalf of a user or org.

Prerequisites

In order to follow this guide, you must have:

* A GitHub App created as described {{{https://developer.github.com/apps/building-github-apps/creating-a-github-app/}here}}

* A Private Key must be configured in your GitHub App as described {{{https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/#generating-a-private-key}here}}

* A User or an organisation that has already installed your GitHub App as described {{{https://developer.github.com/apps/installing-github-apps/}here}}

[]

What next?

* Authenticating as a GitHub App via the {{{/githubappjwtauth.html}JWT Authentication}}

* Authenticating as an installation via the {{{/githubappappinsttokenauth.html}App Installation Token}}

[]
135 changes: 135 additions & 0 deletions src/site/apt/githubappjwtauth.apt
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
GitHub App Authentication via JWT token

In order to authenticate to GitHub as a GitHub App, you must use the JWT token authentication mechanism. This can be
easily achieved with this library by obtaining a <<<GitHub>>> instance like this:

+-----+
GitHub github = new GitHubBuilder().withJwtToken("my_jwt_token").build();
+-----+

Authenticating as a GitHub App lets you do a couple of things:

* You can retrieve high-level management information about your GitHub App.

* You can request access tokens for an installation of the app.

[]

Where do I get the JWT token from?

To generate the JWT token required to authenticate as a GitHub app you have to:

* Sign the JWT token using the private key you configured on your GitHub app as described {{{https://developer.github.com/apps/building-github-apps/authenticating-with-github-apps/#generating-a-private-key}here}}

* Encode it using the <<<RS256>>> algorithm.

[]

GitHub checks that the request is authenticated by verifying the token with the app's stored public key.

Converting the private key into a Java friendly format

<<Note:>> GitHub let's you download the GitHub App private key in the <<<PEM>>> format which isn't natively supported
by the JVM unless you leverage a third-party library such as {{{https://www.bouncycastle.org/}BouncyCastle}}. In this
guide we will convert it to <<<DER>>> using the <<<openssl>>> utility.

+-----+
openssl pkcs8 -topk8 -inform PEM -outform DER -in ~/github-api-app.private-key.pem -out ~/github-api-app.private-key.der -nocrypt
+-----+

How can I generate the JWT token?

Once you have the private key converted to the <<<DER>>> format, you will need 2 more things before you are able to
generate JWT tokens:

<<GitHub App Id:>>

You can obtain the GitHub App Id from your app settings webpage as shown below:

[images/Github_App_Id.png] Github_App_Id

<<JWT library:>>

In order to generate the JWT, you will have to likely use a JWT library.
In this guide we will use {{{https://github.com/jwtk/jjwt}jjwt}} to that matter.

Having said that, add on your <<<pom.xml>>> the following dependencies:

+-----+
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.10.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.10.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.10.5</version>
<scope>runtime</scope>
</dependency>
+-----+


Now we have everything we need so let's generate the JWT token:

+-----+
static PrivateKey get(String filename) throws Exception {
byte[] keyBytes = Files.toByteArray(new File(filename));

PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
return kf.generatePrivate(spec);
}

static String createJWT(String githubAppId, long ttlMillis) throws Exception {
//The JWT signature algorithm we will be using to sign the token
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.RS256;

long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis);

//We will sign our JWT with our private key
Key signingKey = get("github-api-app.private-key.der");

//Let's set the JWT Claims
JwtBuilder builder = Jwts.builder()
.setIssuedAt(now)
.setIssuer(githubAppId)
.signWith(signingKey, signatureAlgorithm);

//if it has been specified, let's add the expiration
if (ttlMillis > 0) {
long expMillis = nowMillis + ttlMillis;
Date exp = new Date(expMillis);
builder.setExpiration(exp);
}

//Builds the JWT and serializes it to a compact, URL-safe string
return builder.compact();
}

public static void main(String[] args) throws Exception {
String jwtToken = createJWT("44435", 600000); //sdk-github-api-app-test
GitHub gitHubApp = new GitHubBuilder().withJwtToken(jwtToken).build();
}
+-----+

How do I get a specific app installation?

+-----+
String jwtToken = createJWT("44435", 600000); //sdk-github-api-app-test
GitHub gitHubApp = new GitHubBuilder().withJwtToken(jwtToken).build();
GHAppInstallation appInstallation = gitHubApp.getApp().getInstallationById(111111); // Installation Id
+-----+

What next?

* Authenticating as an installation via the {{{/githubappappinsttokenauth.html}App Installation Token}}

[]
8 changes: 4 additions & 4 deletions src/site/apt/index.apt
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,10 @@ jwt=my_jwt_token

+-----+
// if you are using the default configuration file
GitHub github = new GitHubBuilder().fromPropertyFile().build();
GitHub github = GitHubBuilder.fromPropertyFile().build();

// if you need to use a separate configuration file
GitHub github = new GitHubBuilder().fromPropertyFile("location/my_custom_github.properties").build();
GitHub github = GitHubBuilder.fromPropertyFile("location/my_custom_github.properties").build();
+-----+

* Environmental variables
Expand Down Expand Up @@ -132,7 +132,7 @@ export GITHUB_JWT=my_jwt_token
Once exported, you can obtain a <<<GitHub>>> instance using:

+-----+
GitHub github = new GitHubBuilder().fromEnvironment().build();
GitHub github = GitHubBuilder.fromEnvironment().build();
+-----+


Expand All @@ -148,7 +148,7 @@ Pluggable HTTP client

+-----+
Cache cache = new Cache(cacheDirectory, 10 * 1024 * 1024); // 10MB cache
GitHub gitHub = GitHubBuilder.fromCredentials()
GitHub gitHub = GitHubBuilder.fromEnvironment()
.withConnector(new OkHttpConnector(new OkUrlFactory(new OkHttpClient().setCache(cache))))
.build();
+-----+
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/site/resources/images/Github_App_Id.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 9 additions & 3 deletions src/site/site.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,21 @@
<version>1.2</version>
</skin>


<body>
<menu name="Git Hub API for Java">
<item name="Introduction" href="/index.html"/>
<item name="Download" href="http://mvnrepository.com/artifact/${project.groupId}/${project.artifactId}"/>
<item name="Introduction" href="/index.html"/>
<item name="Download" href="http://mvnrepository.com/artifact/${project.groupId}/${project.artifactId}"/>
<item name="Source code" href="https://github.com/github-api/${project.artifactId}"/>
<item name="Mailing List" href="https://groups.google.com/forum/#!forum/github-api"/>
</menu>

<menu name="Guides">
<item name="GitHub App Auth Flow" href="/githubappflow.html">
<item name="JWT Authentication" href="/githubappjwtauth.html"/>
<item name="App Installation Token " href="/githubappappinsttokenauth.html"/>
</item>
</menu>

<menu name="References">
<item name="Javadoc" href="apidocs/index.html"/>
</menu>
Expand Down