Skip to content

Commit

Permalink
Simplified OAuth2 flow (#762)
Browse files Browse the repository at this point in the history
* Add `gspread.auth` module. 
`gspread.auth.oauth()` uses `InstalledAppFlow` from `google_auth_oauthlib` to implement OAuth 2.0 Authorization flow for installed applications.

* Handle configuration dir path for Windows as well

* Update test requirements
  • Loading branch information
burnash authored Apr 17, 2020
1 parent a2f64eb commit e89978f
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 2 deletions.
1 change: 1 addition & 0 deletions gspread/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
__author__ = 'Anton Burnashev'


from .auth import oauth
from .client import Client
from .models import Spreadsheet, Worksheet, Cell

Expand Down
102 changes: 102 additions & 0 deletions gspread/auth.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# -*- coding: utf-8 -*-

"""
gspread.auth
~~~~~~~~~~~~
Simple authentication with OAuth.
"""

import os
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow

from .client import Client

DEFAULT_SCOPES = [
'https://www.googleapis.com/auth/spreadsheets',
'https://www.googleapis.com/auth/drive'
]

READONLY_SCOPES = [
'https://www.googleapis.com/auth/spreadsheets.readonly',
'https://www.googleapis.com/auth/drive.readonly'
]


def get_config_dir(config_dir_name='gspread', os_is_windows=os.name == 'nt'):
"""Construct a config dir path.
By default:
* `%APPDATA%\gspread` on Windows
* `~/.config/gspread` everywhere else
"""
if os_is_windows:
return os.path.join(
os.environ["APPDATA"],
config_dir_name
)
else:
return os.path.join(
os.path.expanduser('~'),
'.config',
config_dir_name
)


DEFAULT_CONFIG_DIR = get_config_dir()

DEFAULT_CREDENTIALS_FILENAME = os.path.join(
DEFAULT_CONFIG_DIR,
'credentials.json'
)
DEFAULT_AUTHORIZED_USER_FILENAME = os.path.join(
DEFAULT_CONFIG_DIR,
'authorized_user.json'
)


def _create_installed_app_flow(scopes):
return InstalledAppFlow.from_client_secrets_file(
DEFAULT_CREDENTIALS_FILENAME,
scopes
)


def local_server_flow(scopes, port=0):
flow = _create_installed_app_flow(scopes)
return flow.run_local_server(port=port)


def console_flow(scopes):
flow = _create_installed_app_flow(scopes)
return flow.run_console()


def load_credentials(filename=DEFAULT_AUTHORIZED_USER_FILENAME):
if os.path.exists(filename):
return Credentials.from_authorized_user_file(filename)

return None


def store_credentials(
creds,
filename=DEFAULT_AUTHORIZED_USER_FILENAME,
strip='token'
):
with open(filename, 'w') as f:
f.write(creds.to_json(strip))


def oauth(scopes=DEFAULT_SCOPES, flow=local_server_flow):
creds = load_credentials()

if not creds:
creds = flow(scopes=scopes)
store_credentials(creds)

client = Client(auth=creds)
return client
6 changes: 5 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ def read(filename):
author_email='[email protected]',
url='https://github.com/burnash/gspread',
keywords=['spreadsheets', 'google-spreadsheets'],
install_requires=['requests>=2.2.1', 'google-auth'],
install_requires=[
'requests>=2.2.1',
'google-auth>=1.12.0',
'google-auth-oauthlib>=0.4.1'
],
python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*',
classifiers=[
"Programming Language :: Python",
Expand Down
2 changes: 1 addition & 1 deletion test-requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
nose
requests[security]
google-auth
google-auth-oauthlib>=0.4.1
betamax==0.8.1
-e git+https://github.com/burnash/betamax-json-body-serializer.git#egg=betamax_json_body_serializer

0 comments on commit e89978f

Please sign in to comment.