Integrating a GitHub App with your repositories is a great way to automate tasks, monitor events, and enhance your workflow. However, before your app can interact with the GitHub API, it must authenticate securely. In this article, I’ll explain step by step how to authenticate a GitHub App in .NET using JSON Web Tokens (JWT).
What Do You Need Before Starting?
Before diving into the code, make sure you have the following:
-
Your GitHub App Set Up:
- If you don’t already have one, create a GitHub App via GitHub Developer Settings.
- Note down the App ID and download the private key (
.pem
).
-
A .NET Development Environment:
- Install the latest version of the .NET SDK.
- Use an editor like Visual Studio or Visual Studio Code.
-
Required Libraries:
- Install the following NuGet packages:
dotnet add package System.IdentityModel.Tokens.Jwt dotnet add package Microsoft.IdentityModel.Tokens
-
A Plan to Secure Your Private Key:
- Never store your private key directly in the code. Use services like Azure Key Vault, AWS Secrets Manager, or environment variables to keep it safe.
Step 1: Generate the JWT
The JWT (JSON Web Token) is a crucial piece for authenticating your GitHub App. It contains information such as the App ID and an expiration time and must be signed with your private key.
Code to Generate the JWT
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Cryptography;
using Microsoft.IdentityModel.Tokens;
public class GitHubJwtGenerator
{
private readonly string _privateKey;
private readonly int _appId;
public GitHubJwtGenerator(string privateKey, int appId)
{
_privateKey = privateKey;
_appId = appId;
}
public string GenerateJwt()
{
// Load private key
using var rsa = RSA.Create();
rsa.ImportFromPem(_privateKey.ToCharArray());
var securityKey = new RsaSecurityKey(rsa);
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.RsaSha256);
// JWT payload
var now = DateTimeOffset.UtcNow;
var tokenDescriptor = new SecurityTokenDescriptor
{
Issuer = _appId.ToString(),
IssuedAt = now.UtcDateTime,
Expires = now.AddMinutes(10).UtcDateTime, // Valid for 10 minutes
SigningCredentials = credentials
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
}
How to Use It
Load the private key from the .pem
file and generate the JWT:
var privateKey = System.IO.File.ReadAllText("path/to/private-key.pem");
int appId = 123456; // App ID
var jwtGenerator = new GitHubJwtGenerator(privateKey, appId);
string jwt = jwtGenerator.GenerateJwt();
Console.WriteLine("Generated JWT: " + jwt);
Note: Ensure the
.pem
file is not publicly accessible. Use restrictive permissions or secret management services.
Step 2: Get the Installation Token
With the JWT ready, you now need to use it to obtain an installation token, which allows you to perform specific actions on GitHub.
Code to Get the Token
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text.Json;
using System.Threading.Tasks;
public class GitHubAuthService
{
private readonly string _jwt;
public GitHubAuthService(string jwt)
{
_jwt = jwt;
}
public async Task<string> GetInstallationTokenAsync(long installationId)
{
using var httpClient = new HttpClient();
// Configure the authorisation header
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _jwt);
httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("MyGitHubApp", "1.0"));
// URL to get the token
var url = $"https://api.github.com/app/installations/{installationId}/access_tokens";
var response = await httpClient.PostAsync(url, null);
if (!response.IsSuccessStatusCode)
{
var error = await response.Content.ReadAsStringAsync();
throw new Exception($"Failed to get installation token: {error}");
}
var responseContent = await response.Content.ReadAsStringAsync();
var json = JsonDocument.Parse(responseContent);
return json.RootElement.GetProperty("token").GetString();
}
}
How to Use It
var installationId = 987654321; // Installation ID
var authService = new GitHubAuthService(jwt);
try
{
string installationToken = await authService.GetInstallationTokenAsync(installationId);
Console.WriteLine("Installation Access Token: " + installationToken);
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
Step 3: Use the Installation Token
With the installation token in hand, you can interact with the GitHub API. Here’s an example of how to list the repositories accessible by the installation:
Code to List Repositories
public async Task ListRepositoriesAsync(string installationToken)
{
using var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Token", installationToken);
httpClient.DefaultRequestHeaders.UserAgent.Add(new ProductInfoHeaderValue("MyGitHubApp", "1.0"));
var response = await httpClient.GetAsync("https://api.github.com/installation/repositories");
if (!response.IsSuccessStatusCode)
{
var error = await response.Content.ReadAsStringAsync();
throw new Exception($"Failed to list repositories: {error}");
}
var content = await response.Content.ReadAsStringAsync();
Console.WriteLine("Repositories: " + content);
}
Security Best Practices
- Protect your private key: Use secret management services like Azure Key Vault or environment variables.
- Short-lived tokens: Keep JWTs valid for 10 minutes or less.
- Minimal permissions: Ensure your GitHub App has only the permissions it strictly needs.
Conclusion
By following these steps, you can generate the JWT, obtain the installation token, and use it to interact with the GitHub API. With proper security practices, your integration will be reliable and secure.
Top comments (0)