Search code examples
pythongoogle-drive-apigoogle-api-python-client

Google Drive API will not run in development server due to Error 400/WinError 10048 errors


I'm integrating the Google Drive API in my Flask app, but I'm having trouble testing it locally in a development server.

Here is the code, from these Google docs:

SCOPES = ['https://www.googleapis.com/auth/drive']
CLIENT_SECRETS_FILE = 'credentials.json'
TOKEN_FILE = 'token.json'

def upload_file():
    creds = None

    if os.path.exists(TOKEN_FILE):
        creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)
    
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(CLIENT_SECRETS_FILE, SCOPES)
            creds = flow.run_local_server(port=0)

        with open(TOKEN_FILE, 'w') as token:
            token.write(creds.to_json())

(imports and subsequent Google Drive upload code not included for brevity)

The issue is, when I run this on a dynamic port as above, I get this error, due to the fact that the random port it chooses is not registered with GCloud:

Error 400: redirect_uri_mismatch

When I change the port to one that is registered in GCloud, such as 8080, it gives me this error:

OSError: [WinError 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted

Is there any way to test this in a development server or do I have to deploy it?

I instituted the Google Drive API per Google's documentation, verified that my credentials.json matches the information in GCloud, and used this function to try and upload a .docx to Google Drive. I expected it to upload a document, but it errored out on this line:

creds = flow.run_local_server(port=0)

Solution

  • Flask is for web applications. Your using code for an installed app hense the term InstalledAppFlow.

    @app.route('/authorize')
    def authorize():
        # Create flow instance to manage the OAuth 2.0 Authorization Grant Flow steps.
        flow = google_auth_oauthlib.flow.Flow.from_client_secrets_file(
            CLIENT_SECRETS_FILE, scopes=SCOPES)
    
        # The URI created here must exactly match one of the authorized redirect URIs
        # for the OAuth 2.0 client, which you configured in the API Console. If this
        # value doesn't match an authorized URI, you will get a 'redirect_uri_mismatch'
        # error.
        flow.redirect_uri = flask.url_for('oauth2callback', _external=True)
    
        authorization_url, state = flow.authorization_url(
            # Enable offline access so that you can refresh an access token without
            # re-prompting the user for permission. Recommended for web server apps.
            access_type='offline')
    
        # Store the state so the callback can verify the auth server response.
        flask.session['state'] = state
    
        return flask.redirect(authorization_url)