Skip to content

Update docs for Generating a JWT for GitHub App  #30360

Description

@jed-exotic

Code of Conduct

What article on docs.github.com is affected?

https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app#example-using-python-to-generate-a-jwt

What part(s) of the article would you like to see updated?

Example: Using Python to generate a JWT

The Note: may be updated to mention both PyJWT and jwt. Both Python modules use the same namespace, and if the Python environment where this is being run has PyJWT installed, the script does not work.

To fix this, we introduce two functions from the cryptography module, and before the script runs the loaded jwt module has its attributes evaluated to determine whether it's PyJWT or jwt. The condition may be improved upon, but I've tested the following that works:

isPyJwt = hasattr(jwt,"name") and hasattr(jwt,"PyJWT")

The remaining changes can be identified by looking for the conditions that reference isPyJwt.

Updated script:

#!/usr/bin/env python3
import jwt
import time
import sys
from cryptography.hazmat.primitives.serialization import load_pem_private_key
from cryptography.hazmat.backends import default_backend

# Determine what module JWT is coming from (PyJWT and jwt share the same namespace)
isPyJwt = hasattr(jwt,"__name__") and hasattr(jwt,"PyJWT")

# Get PEM file path
if len(sys.argv) > 1:
    pem = sys.argv[1]
else:
    pem = input("Enter path of private PEM file: ")

# Get the App ID
if len(sys.argv) > 2:
    app_id = sys.argv[2]
else:
    app_id = input("Enter your APP ID: ")

# Open PEM
with open(pem, 'rb') as pem_file:
    if isPyJwt:
        signing_key = load_pem_private_key(pem_file.read(), None, default_backend())
    else:
        signing_key = jwt.jwk_from_pem(pem_file.read())

payload = {
    # Issued at time
    'iat': int(time.time()),
    # JWT expiration time (10 minutes maximum)
    'exp': int(time.time()) + 600,
    # GitHub App's identifier
    'iss': app_id
}

# Create JWT
if isPyJwt:
    encoded_jwt = jwt.encode(payload, signing_key, algorithm='RS256')
else:
    jwt_instance = jwt.JWT()
    encoded_jwt = jwt_instance.encode(payload, signing_key, alg='RS256')

print(f"{encoded_jwt}")

Additional information

This has been tested in two scenarios - one in which the system only has only PyJWT, and the other that has the jwt module installed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    contentThis issue or pull request belongs to the Docs Content teamgithub appsContent related to GitHub Appshelp wantedAnyone is welcome to open a pull request to fix this issue

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions