yanyongyu / githubkit

The modern, all-batteries-included GitHub SDK for Python, including rest api, graphql, webhooks, like octokit!
MIT License
157 stars 21 forks source link

Feature: Support authenticating as a GitHub App with user access/refresh tokens #113

Open object-Object opened 6 days ago

object-Object commented 6 days ago

I'm writing an application that uses an expiring user access token to authenticate a GitHub App on behalf of a user. This process uses the OAuth web flow to generate an access token and refresh token; these are valid for 8 hours and 6 months, respectively. I want to store the access and refresh tokens so that users don't have to log in each time they use the app.

I see that githubkit has OAuthWebAuthStrategy, which is useful for the initial login; however, it seems like the access and refresh tokens are stored in private variables in OAuthWebAuth, and I don't see an obvious public way to access them or to force it to fetch them. I also couldn't find an AuthStrategy that takes an access or refresh token as the input.

Ideally, this is the sort of code I would like to be able to write:

# initial login
github = GitHub(OAuthWebAuthStrategy(client_id, client_secret, code))
access_token, refresh_token = github.get_app_user_access_token()

# subsequent usages
github = GitHub(AppUserAuthStrategy(client_id, client_secret, access_token, refresh_token))

GitHub app user auth flow docs:

https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-user-access-token-for-a-github-app#using-the-web-application-flow-to-generate-a-user-access-token

For comparison, here's how PyGithub's app user authentication works:

https://pygithub.readthedocs.io/en/stable/examples/Authentication.html#app-user-authentication

yanyongyu commented 6 days ago

Actually, the github app user access auth flow is a oauth workflow. Currently, you can do this as examples here:

from githubkit import GitHub

# auth as github app itself
g = GitHub(AppAuthStrategy(app_id, private_key, client_id, client_secret))

# switch to app user auth
user_github = g.with_auth(g.as_oauth_app().as_web_user(code))
object-Object commented 6 days ago

Right, but I don't have code anymore after the first login. Sorry, I think the example I gave maybe wasn't very good.

User logs into the app:

# initial login
github = GitHub(OAuthWebAuthStrategy(client_id, client_secret, code))
access_token, refresh_token = github.get_app_user_access_token()

write_tokens_to_database(user_id, access_token, refresh_token)

Later, maybe the next day and in a different part of the app, user uses the app without having to go through the OAuth web flow again:

# subsequent usages
access_token, refresh_token = read_tokens_from_database(user_id)

github = GitHub(AppUserAuthStrategy(client_id, client_secret, access_token, refresh_token))

So I think I wouldn't be able to use .as_web_user(code) for the second one, because I don't have code at that point, only the tokens I exchanged it for.

yanyongyu commented 6 days ago

I see... It seems i need to add a simple (token, expire token) auth strategy for oauth app. I'm also developping a github app and i disable the token expire for the user token :joy:. I can use the simple token auth strategy for stored user token.