-
Notifications
You must be signed in to change notification settings - Fork 21
GitHub Authentication Notes
These are notes from the November 2020 change in how we generate tokens for GitHub API authentication. See GitHub blog post for motivation.
We access git and github functionality two ways in abc-classroom
:
- Command-line git operations (e.g.
git commit
orgit clone
) implemented as pythonsubprocess
calls in the_call_git
function. This simply runs with the user's local git setup and SSH keys. - GitHub operations, implemented through the GitHub API. These are the ones that need to change for the upcoming deprecation.
In the abc-init
script, we set up GitHub API api authentication
by authenticating with a username and password, and use that authentication
to generate a personal access token. We save the token to a local file
and read it back in when we make an API call.
The other abc scripts access git and github actions as follows:
abc-quickstart
: no git or github steps
abc-new-template
and abc-update-template
use the following methods:
- init_and_commit : command-line git
- remote_repo_exists : GitHub API call
- create_repo : GitHub API call
- add_remote : command-line git
- push_to_github : local git action
abc-clone
uses only command-line git actions (calling pull_from_github
,
clone_repo
), as does abc-feedback
(calling commit_all_changes
and
push_to_github
)
So, the only two API calls that we use are:
create an organization repository - requires authentication
get-a-repository - this does not need authentication for public repos, but does for private repos (which is true in our case)
We are proceeding by creating a GitHub App for accessing the API, abc-classroom-bot
.
We install the app on the organization(s) that we need access to, and then
authenticate as a user that has read + write access to the organization repos.
The app is currently installed on earthlab-education (production) and
earth-analytics-edu (dev, the pig organization).
There are two types of authentication methods for a GitHub app. You can authenticate as the installed app (so actions are done on behalf of the app), or you can authenticate as a user (so actions are done on behalf of the user).
Installation-based authentication requires that the app has access to its private key in order to generate the JSON Web Token (JWT). It is unclear to me how to handle this with a command-line app that is installed on the user's computer (with a web-based app, you would have the private key on a server that is not accessible to the user.)
Therefore, I've gone with user-based authentication via the device flow process, which generates a 'user-to-server' access token. See the GitHub docs for user-based authentication. I am not using expiring user tokens at this point, as refreshing the token this would require the app to have access to the client secret (the private key).
The permissions are much more fine-grained than with a personal access token. With a personal access token (the method we are using now), the token allows you to anything through the API that you can do via the GitHub web interface.
With the GitHub App, you set the precise permissions that you need on each type of
resource (repos, issues, pull requests, etc). The app then only has access to a
resource when it is requested by the app and available to the
authenticated user.
The authentication workflow is as follows (when you run abc-init
):
- Try existing token: the app tries to read the token from the
.abc-classroom.tokens.yml
file in the user's home directory- if there is no file, it generates a new token
- if there is a token, it tests to see if it is valid by making a call to get the authenticated user. This returns a 404 if there is no authentication
- If the existing token is missing or invalid, we generate a new one:
- Step 1: Call
https://github.com/login/device/code
using theclient_id
of the GitHub App. This id is unique toabc-classroom-bot
and is hardcoded. This call returns adevice_code
to the app. - Step 2: Print a message to the user on the command line asking them to go to
https://github.com/login/device
in a web browser, enter a temporary user code, and then hit in the terminal when they have done so. - Step 3: Call
https://github.com/login/oauth/access_token
with thedevice_code
. If the user has successfully entered the user code, the app gets back an access_token. We write this to the file.abc-classroom.tokens.yml
.
- Step 1: Call
- Using the token: when making subsequent API calls, we use the access_token in the header of the call (currently by providing it as a parameter to methods in the gthub3 library, but this will likely change in the future to either the pygithub library or by implementing the calls using requests).