fastai / ghapi

A delightful and complete interface to GitHub's amazing API
https://ghapi.fast.ai/
Apache License 2.0
527 stars 57 forks source link

fix apps.* endpoints that require jwt_token #88

Closed ffalor closed 2 years ago

ffalor commented 2 years ago

Adds jwt_token attribute to GhApi to allow users to call app endpoints that require a jwt token instead of a pat/access_key

closes #85

This should fix and allow you to authenticate to the following endpoints:

And probably more, these were just the ones I quickly tested.

For example:

jwt = create_jwt(app_id, private_key)

app_api = GhApi(jwt_token=jwt)

print("List Installations")
installations = app_api.apps.list_installations()
print(installations)

print("Get Access Token")
id = installations[0]['id']
print(app_api.apps.create_installation_access_token(id))
List Installations

[- id: 1111
- account: 
  - login: ffalor
  - id: 1
  - node_id: MDQ6VXNlcjM1MTQ0MTQx
  #etc...]

Get Access Token
- token: ghs_324324234234
- expires_at: 2021-08-21T11:40:36Z
- permissions: 
  - administration: read
  - contents: read
  - issues: write
  - metadata: read
- repository_selection: all

Not 100% what all I can update since from my understanding this project is auto generated. I did not see any tests to update. Please let me know what would need to change in order to add the ability to provide a jwt_token.

Reopen of #87 had to fix line ending changes and auto formatting.

review-notebook-app[bot] commented 2 years ago

Check out this pull request on  ReviewNB

See visual diffs & provide feedback on Jupyter Notebooks.


Powered by ReviewNB

ffalor commented 2 years ago

I didn't run nbdev_build_docs I'm assuming the docs will need to be updated since I added a new attribute, but the contributing guide just says to run nbdev_install_git_hooks

I did update the notebooks and run nbdev_build_lib to generate the changes to core.py

This is my first contribution to a project that uses nbdev, sorry if I'm not doing this correctly.

AlexandreODelisle commented 2 years ago

@ffalor , it might just be my understanding, but you can pass the auth to the apps.* endpoints by providing a custom headers to the function.

def app_headers(app_id:str, private_key:str) -> dict:

    time_since_epoch_in_seconds = int(time.time())

    payload = {
      'iat': time_since_epoch_in_seconds,
      'exp': time_since_epoch_in_seconds + (10 * 60),
      'iss': app_id
    }

    actual_jwt = jwt.encode(payload, private_key, algorithm='RS256')
    headers = {"Authorization": "Bearer {}".format(actual_jwt),
               "Accept": "application/vnd.github.machine-man-preview+json"}

    return headers

_ = GitHub(token=os.getenv("GH_PAT_TOKEN"))
token = _.api.apps.create_installation_access_token(installation_id=installation_id, headers=app_headers(app_id=app_id, private_key=private_key))
gh = GitHub(token=token['token'])
print(gh.api.orgs.list_members(org="my_org"))

Keep in mind installation_id and app_id are not the same thing..

Ref on the JWT: https://gist.github.com/pelson/47c0c89a3522ed8da5cc305afc2562b0?short_path=a324ade

ffalor commented 2 years ago

Thanks for the reply, I'll have to look into the custom headers that info is not in the documentation.

But one thing to note, app_id and installation_id are not the same thing. A github app will always have a single app_id, but installation_id is unique for each installation.

For example:

If i had a github app and two organizations install it. The app_id will be the same, but each org will have a unique installation_id. There are many reasons for this, but the main reason is so the access_token that is created will only have permissions to alter and get resources from that one installation.

AlexandreODelisle commented 2 years ago

indeed I missed a word there. They are the not the same thing. thanks just corrected.

jph00 commented 2 years ago

Fantastic - many thanks for this contribution. You might want to do a followup PR which adds a bit of documentation to the notebook to let people know this exists, and show an example, if you're open to that.