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

fix: Support Deno 2 #8

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.vscode
42 changes: 32 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# GitHub App auth for Deno

A minimal Deno library and a CLI app to authenticate as a GitHub App installation.
A minimal Deno library and a CLI app to authenticate as a GitHub App
installation.

## Usage

Expand All @@ -17,15 +18,31 @@ Then you can use it as `github_app_auth ...`.
#### Expected inputs

- `app-id`: you can find it in the application settings
- `private-key`: Base64-encoded content of the private key `.pem` file you got when you created the app
- `installation-id`: organization or user installation ID you want to get access to
- `repositories` (optional, trail-arg): list of repositories to give access to; if not provided, it will be all repositories that the installation can access
- `private-key`: Base64-encoded content of the private key `.pem` file you got
when you created the app, converted into pkcs8 format
- `installation-id`: organization or user installation ID you want to get access
to
- `repositories` (optional, trail-arg): list of repositories to give access to;
if not provided, it will be all repositories that the installation can access

See the [API endpoint documentation](https://docs.github.com/en/rest/reference/apps#create-an-installation-access-token-for-an-app) for more info.
See the
[API endpoint documentation](https://docs.github.com/en/rest/reference/apps#create-an-installation-access-token-for-an-app)
for more info.

#### Converting the GitHub Private Key

The private key that github generates is a `pkcs1` format key but Deno only
supports `pkcs8`. To convert it you can use openssl:

```sh
openssl pkcs8 -topk8 -inform PEM -outform PEM -nocrypt -in ~/Downloads/example.2024-11-12.private-key.pem -out private-key.key
```

#### GitHub API URL

If you need to change the default GitHub API URL, you can do it by setting the `GITHUB_API_URL` env var and adding `--allow-env=GITHUB_API_URL` when you install the script:
If you need to change the default GitHub API URL, you can do it by setting the
`GITHUB_API_URL` env var and adding `--allow-env=GITHUB_API_URL` when you
install the script:

```shell
export GITHUB_API_URL='...'
Expand All @@ -36,14 +53,16 @@ Or use `--allow-net --allow-env` for simplicity.

#### Examples

Given app ID, private key and then installation ID it will create a new installation access token and print it to the standard output:
Given app ID, private key and then installation ID it will create a new
installation access token and print it to the standard output:

```shell
$ github_app_auth 123456 $(base64 < private-key.pem) 12345678
ghs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

If you don't know the installation ID, you can run it with only the first two arguments and get a list of the app installations:
If you don't know the installation ID, you can run it with only the first two
arguments and get a list of the app installations:

```shell
$ github_app_auth 123456 $(base64 < private-key.pem)
Expand All @@ -53,7 +72,9 @@ $ github_app_auth 123456 $(base64 < private-key.pem)
...
```

You can use generated tokens to make requests on behalf on the app. Here are some examples using GitHub's official CLI `gh`, but you can also do it with `curl` or any other tool by adding the `Authorization: token ...` header.
You can use generated tokens to make requests on behalf on the app. Here are
some examples using GitHub's official CLI `gh`, but you can also do it with
`curl` or any other tool by adding the `Authorization: token ...` header.

```shell
$ GITHUB_TOKEN=$(github_app_auth 123456 $(base64 < private-key.pem) 12345678)
Expand All @@ -73,4 +94,5 @@ $ gh api repos/:owner/repo1/releases
...
```

Check out [`gh api` docs](https://cli.github.com/manual/gh_api) for more examples and full feature list.
Check out [`gh api` docs](https://cli.github.com/manual/gh_api) for more
examples and full feature list.
29 changes: 26 additions & 3 deletions jwt.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,36 @@
import { create, getNumericDate } from "https://deno.land/x/[email protected]/mod.ts";
import { create, getNumericDate } from "jsr:@zaubrik/djwt@^v3.0.2";
import { decodeBase64 } from "jsr:@std/encoding@^1.0.5";

function pemToBinary(pem: string): Uint8Array {
const base64 = pem
.replace(/-----[A-Z ]*-----/g, "")
.replace(/\s+/g, "");
return decodeBase64(base64);
}

export async function appJwt(
appId: string,
pkcs8PrivateKey: string,
): Promise<string> {
const buffer = pemToBinary(pkcs8PrivateKey);
const key = await crypto.subtle.importKey(
"pkcs8",
buffer,
{
name: "RSASSA-PKCS1-v1_5",
hash: { name: "SHA-256" },
},
true,
["sign"],
);

export function appJwt(appId: string, privateKey: string): Promise<string> {
return create(
{ alg: "RS256", typ: "JWT" },
{
iss: appId, // issuer
iat: getNumericDate(0), // issued at time (now)
exp: getNumericDate(5 * 60), // expiration time (in 5 minutes)
},
atob(privateKey),
key,
);
}
Loading