How to authenticate to the GitHub REST API with PowerShell
Tags: powershell, devops, github
Published: 2024-01-03 16:51:05

The GitHub REST API is an essential tool to automate your GitHub repositories. You can use it to create issues, manage branches, create dashboards, or many other things. 
We can use PowerShell to automate all these tasks and create applications that automate to work for us. Let's see how to start.

For using the Rest API with PowerShell, we need to authenticate to the Rest API. You cannot do it using a Login/Password, it will not work, and you will get a 4XX HTTP error. 

There are 3 ways to authenticate to the Rest API, access token, GitHub App, and inside GitHub Action.

## Access token
Access token is the simple way to authenticate to the Rest API. You simply need to go to your GitHub account settings then Developer Settings (or simply go to this [URI](https://github.com/settings/apps)), and then create an access token. You can either choose the classic tokens (no restriction) or the fine-grained token where you can use fine-tuned permissions. 

I will create a classic token with the repo:status and write:discussion privileges.
To use the token follow the script here

```powershell
# This script illustrates how you can log in and perform a get action to Github Rest API with an access token 
# This script lists all repository names for a given organization

param(
    # The access token to the GitHub Rest API 
    [Parameter(Mandatory=$true)]
    [string]
    $accessToken, 

    [Parameter(Mandatory=$true)]
    [string]
    $orgaName
)

$authenticationToken = [System.Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$accessToken"))
    $headers = @{
        "Authorization" = [String]::Format("Basic {0}", $authenticationToken)
        "Content-Type"  = "application/json"
    }

$reposAPIUri = "https://api.github.com/orgs/$($orgaName)/repos"

$githubRepositories = Invoke-RestMethod -Method get -Uri $reposAPIUri -Headers $headers 

foreach ($respository in $githubRepositories) {
    write-host  $respository.name
}
```

The token is encoded in Base64  
[System.Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$accessToken")) 

Then formatted to give something like 
Authorization                  Basic <Encoded token>
End added to the http header for in the invoke-RestMethod cmdlet


## GitHub App 

Authentication with a GitHub App is more complex. First, you need to create a GitHub App by following the instructions on this [page](https://docs.github.com/en/apps/creating-github-apps/writing-code-for-a-github-app/quickstart). Once you have created your GitHub App you will need to create a client secret and a private key. Download the private key on your computer. And finally note the App ID. 

You will also need to install the application in your account and get the instance ID. 

To authenticate with a GitHub app you will need to authenticate first with the certificate and then generate a token to access the API. 
The certificate and the App ID will be used to create a JSON Web Token. This JWT will be used to create a JIT token for the GitHub Rest API request. 

To create the SWT I need a tool, there are no native tools to create a JWT in PwSh now, but you can use the powershell-jwt  module as I did here (install-module -name powershell-jwt)

With the access token, you can query the API by using the Authorization="token $token", note that you can also ask for a specific version of the API by using the X-GitHub-Api-Version

Note also that GitHub recommends using Accept="application/vnd.github+json" when interacting with the API.

```powershell
# This script illustrates how you can log in and perform a get action to Github Rest API with a GitHub App 
# this script list all issues 

param(
    # The access token to the GitHub Rest API 
    [Parameter(Mandatory=$true)]
    [string]
    $pathToGitHubAppKey, 

    [Parameter(Mandatory=$true)]
    [string]
    $instanceID, 

    [Parameter(Mandatory=$true)]
    [string]
    $appID, 

    [Parameter(Mandatory=$true)]
    [string]
    $organisation, 

    [Parameter(Mandatory=$true)]
    [string]
    $repository
)


# Get the private key content
$apiPemData = Get-Content -Path $pathToGitHubAppKey
$apiSecret = [System.Text.Encoding]::UTF8.GetBytes($apiPemData)

$exp = [int][double]::parse((Get-Date -Date $((Get-Date).addseconds(300).ToUniversalTime()) -UFormat %s)) 
$iat = [int][double]::parse((Get-Date -Date $((Get-Date).ToUniversalTime()) -UFormat %s)) 

# create a Json Web Tokken using new-jwt from the powershell-jwt module
$jwt = New-JWT -Algorithm "RS256" -Issuer $appID -ExpiryTimestamp $exp -SecretKey $apiSecret -PayloadClaims @{ "iat" = $iat}


# request a new tokken 
$headers = @{
    "Accept" = "application/vnd.github+json"
    "Authorization" = "Bearer $jwt"
}

$res = Invoke-WebRequest -Uri "https://api.github.com/app/installations/$($instanceID)/access_tokens" -Headers $headers -Method Post
$json_res = ConvertFrom-Json($res.Content)
$token = $json_res.token

 
# Querry the API to list all issues in a repository
$reposAPIUri = "https://api.github.com/repos/$'$organisation)/$($repository)/issues"

$headers = @{
    Accept="application/vnd.github+json"
    Authorization="token $token"
    "X-GitHub-Api-Version" = "2022-11-28"
}
$issuesList = Invoke-WebRequest -Uri $reposAPIUri  -Headers $headers

$issuesObject = ConvertFrom-Json($issuesList.content)

foreach ($issue in $issuesObject) { 
    $issue.title 
}
```

## GitHub Action workflow 

The last way to authenticate to the Rest API is to run your PowerShell script in GitHub Action. You can use the Token method or the GitHub method to authenticate to GitHub Rest API. But GitHub doesn’t recommend that. 
When you create a workflow for GithHub Action, GitHub creates a token,  GITHUB_TOKEN, that you can use in your script. 
The first step is to create the workflow with the main.yaml file 

```yaml 
name: Windows-wks

on: [push, pull_request]

jobs:
  validate:
    runs-on: windows-latest
    permissions: 
      issues: write
    env: 
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

    steps:
      - uses: actions/checkout@v1
      - name: Perform_Tests
        shell: pwsh
        run: .\githubAction-login.ps1
```

In the Job, you can setup permissions for the built-in token

```yaml
    permissions: 
      issues: write
```

Then I add the token to an environment variable 

```yaml 
    env: 
      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```

So, I can use it in the script like this 

```powershell
$stringTokken = $Env:GH_TOKEN

    $headers = @{
        "Accept" = "application/vnd.github+json"
        "Authorization" = "Bearer $stringTokken"
    }

$reposAPIUri = "https://api.github.com/repos/<ORGA>/<REPOS>/issues"

$githubRepositories = Invoke-RestMethod -Method get -Uri $reposAPIUri -Headers $headers 

foreach ($respository in $githubRepositories) {
    write-host  $respository.name
}
```

You can use the token as is, no need to encode it