|
| 1 | +GitHub App Authentication via JWT token |
| 2 | + |
| 3 | + In order to authenticate to GitHub as a GitHub App, you must use the JWT token authentication mechanism. This can be |
| 4 | + easily achieved with this library by obtaining a <<<GitHub>>> instance like this: |
| 5 | + |
| 6 | ++-----+ |
| 7 | +GitHub github = new GitHubBuilder().withJwtToken("my_jwt_token").build(); |
| 8 | ++-----+ |
| 9 | + |
| 10 | + Authenticating as a GitHub App lets you do a couple of things: |
| 11 | + |
| 12 | + * You can retrieve high-level management information about your GitHub App. |
| 13 | + |
| 14 | + * You can request access tokens for an installation of the app. |
| 15 | + |
| 16 | + [] |
| 17 | + |
| 18 | +Where do I get the JWT token from? |
| 19 | + |
| 20 | + To generate the JWT token required to authenticate as a GitHub app you have to: |
| 21 | + |
| 22 | + * 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}} |
| 23 | + |
| 24 | + * Encode it using the <<<RS256>>> algorithm. |
| 25 | + |
| 26 | + [] |
| 27 | + |
| 28 | + GitHub checks that the request is authenticated by verifying the token with the app's stored public key. |
| 29 | + |
| 30 | +Converting the private key into a Java friendly format |
| 31 | + |
| 32 | + <<Note:>> GitHub let's you download the GitHub App private key in the <<<PEM>>> format which isn't natively supported |
| 33 | + by the JVM unless you leverage a third-party library such as {{{https://www.bouncycastle.org/}BouncyCastle}}. In this |
| 34 | + guide we will convert it to <<<DER>>> using the <<<openssl>>> utility. |
| 35 | + |
| 36 | ++-----+ |
| 37 | +openssl pkcs8 -topk8 -inform PEM -outform DER -in ~/github-api-app.private-key.pem -out ~/github-api-app.private-key.der -nocrypt |
| 38 | ++-----+ |
| 39 | + |
| 40 | +How can I generate the JWT token? |
| 41 | + |
| 42 | + Once you have the private key converted to the <<<DER>>> format, you will need 2 more things before you are able to |
| 43 | + generate JWT tokens: |
| 44 | + |
| 45 | + <<GitHub App Id:>> |
| 46 | + |
| 47 | + You can obtain the GitHub App Id from your app settings webpage as shown below: |
| 48 | + |
| 49 | +[images/Github_App_Id.png] Github_App_Id |
| 50 | + |
| 51 | + <<JWT library:>> |
| 52 | + |
| 53 | + In order to generate the JWT, you will have to likely use a JWT library. |
| 54 | + In this guide we will use {{{https://github.com/jwtk/jjwt}jjwt}} to that matter. |
| 55 | + |
| 56 | + Having said that, add on your <<<pom.xml>>> the following dependencies: |
| 57 | + |
| 58 | ++-----+ |
| 59 | +<dependency> |
| 60 | + <groupId>io.jsonwebtoken</groupId> |
| 61 | + <artifactId>jjwt-api</artifactId> |
| 62 | + <version>0.10.5</version> |
| 63 | +</dependency> |
| 64 | +<dependency> |
| 65 | + <groupId>io.jsonwebtoken</groupId> |
| 66 | + <artifactId>jjwt-impl</artifactId> |
| 67 | + <version>0.10.5</version> |
| 68 | + <scope>runtime</scope> |
| 69 | +</dependency> |
| 70 | +<dependency> |
| 71 | + <groupId>io.jsonwebtoken</groupId> |
| 72 | + <artifactId>jjwt-jackson</artifactId> |
| 73 | + <version>0.10.5</version> |
| 74 | + <scope>runtime</scope> |
| 75 | +</dependency> |
| 76 | ++-----+ |
| 77 | + |
| 78 | + |
| 79 | + Now we have everything we need so let's generate the JWT token: |
| 80 | + |
| 81 | ++-----+ |
| 82 | +static PrivateKey get(String filename) throws Exception { |
| 83 | + byte[] keyBytes = Files.toByteArray(new File(filename)); |
| 84 | + |
| 85 | + PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(keyBytes); |
| 86 | + KeyFactory kf = KeyFactory.getInstance("RSA"); |
| 87 | + return kf.generatePrivate(spec); |
| 88 | +} |
| 89 | + |
| 90 | +static String createJWT(String githubAppId, long ttlMillis) throws Exception { |
| 91 | + //The JWT signature algorithm we will be using to sign the token |
| 92 | + SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.RS256; |
| 93 | + |
| 94 | + long nowMillis = System.currentTimeMillis(); |
| 95 | + Date now = new Date(nowMillis); |
| 96 | + |
| 97 | + //We will sign our JWT with our private key |
| 98 | + Key signingKey = get("github-api-app.private-key.der"); |
| 99 | + |
| 100 | + //Let's set the JWT Claims |
| 101 | + JwtBuilder builder = Jwts.builder() |
| 102 | + .setIssuedAt(now) |
| 103 | + .setIssuer(githubAppId) |
| 104 | + .signWith(signingKey, signatureAlgorithm); |
| 105 | + |
| 106 | + //if it has been specified, let's add the expiration |
| 107 | + if (ttlMillis > 0) { |
| 108 | + long expMillis = nowMillis + ttlMillis; |
| 109 | + Date exp = new Date(expMillis); |
| 110 | + builder.setExpiration(exp); |
| 111 | + } |
| 112 | + |
| 113 | + //Builds the JWT and serializes it to a compact, URL-safe string |
| 114 | + return builder.compact(); |
| 115 | +} |
| 116 | + |
| 117 | +public static void main(String[] args) throws Exception { |
| 118 | + String jwtToken = createJWT("44435", 600000); //sdk-github-api-app-test |
| 119 | + GitHub gitHubApp = new GitHubBuilder().withJwtToken(jwtToken).build(); |
| 120 | +} |
| 121 | ++-----+ |
| 122 | + |
| 123 | +How do I get a specific app installation? |
| 124 | + |
| 125 | ++-----+ |
| 126 | +String jwtToken = createJWT("44435", 600000); //sdk-github-api-app-test |
| 127 | +GitHub gitHubApp = new GitHubBuilder().withJwtToken(jwtToken).build(); |
| 128 | +GHAppInstallation appInstallation = gitHubApp.getApp().getInstallationById(111111); // Installation Id |
| 129 | ++-----+ |
| 130 | + |
| 131 | +What next? |
| 132 | + |
| 133 | + * Authenticating as an installation via the {{{/githubappappinsttokenauth.html}App Installation Token}} |
| 134 | + |
| 135 | + [] |
0 commit comments