pythontwo-factor-authenticationgithub3.py

Why does github3.py ask for a second authentication factor twice?


I'm using github3.py to access my organization's Github account, and we have two-factor authentication enabled. I'm starting by listing the repositories. Here's the code:

import os

import github3

USER = os.environ['GITHUB_USERNAME']
PASS = os.environ['GITHUB_PASSWORD']

try:
    # Python 2
    prompt = raw_input
except NameError:
    # Python 3
    prompt = input

def get_second_factor():
    print("Authenticator called")
    code = ''
    while not code:
        # The user could accidentally press Enter before being ready
        code = prompt('Enter 2FA code: ')
        print("Received code:", code)
    return code

gh = github3.login(USER, PASS, two_factor_callback=get_second_factor)

org = gh.organization("<ORGNAME>")
for repo in org.iter_repos(type="all"):
    print(repo.ssh_url)

Unfortunately it seems that not only does the call to github3.login trigger a request for the second factor, the call to org.iter_repos triggers a second request.

Is this expected behaviour? How do I ensure that a program only tries 2FA the first time it's required?


Solution

  • So the short answer is that to avoid needing to enter second factor codes, you can create a "Personal Access Token" by accessing your settings on the website. When you have that you can pass that as the token parameter to github3.login.

    The long answer is that calling login doesn't call this but instead calling organization and iter_repos triggers the two 2FA requests. In fact if you have more than 100 repositories, you'll be asked for it for every hundred repositories after that. The reason is that the GitHub API prompts you for a second factor token every time you make a request to the API. This means that each time github3.py makes a request to the API, we receive a specific response that is a challenge. When that happens, we repeat the request with the token you enter. So in order to avoid having to enter this multiple times, you'll need to use a personal access token.