Skip to content

Commit

Permalink
Use auth.service_account in service account authentication guide.
Browse files Browse the repository at this point in the history
Add advanced usage documentation stub.
Move Authlib example to advanced usage docs.
  • Loading branch information
burnash committed Apr 28, 2020
1 parent 326667c commit 17360bd
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 65 deletions.
54 changes: 54 additions & 0 deletions docs/advanced.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
Advanced Usage
==============

Custom Authentication
---------------------

Using Authlib
~~~~~~~~~~~~~

Using ``Authlib`` instead of ``google-auth``. Authlib has an ``AssertionSession`` which can automatically refresh tokens.::

import json
from gspread import Client
from authlib.client import AssertionSession

def create_assertion_session(conf_file, scopes, subject=None):
with open(conf_file, 'r') as f:
conf = json.load(f)

token_url = conf['token_uri']
issuer = conf['client_email']
key = conf['private_key']
key_id = conf.get('private_key_id')

header = {'alg': 'RS256'}
if key_id:
header['kid'] = key_id

# Google puts scope in payload
claims = {'scope': ' '.join(scopes)}
return AssertionSession(
grant_type=AssertionSession.JWT_BEARER_GRANT_TYPE,
token_url=token_url,
issuer=issuer,
audience=token_url,
claims=claims,
subject=subject,
key=key,
header=header,
)

scopes = [
'https://www.googleapis.com/auth/spreadsheets',
'https://www.googleapis.com/auth/drive',
]
session = create_assertion_session('your-google-conf.json', scopes)
gc = Client(None, session)

wks = gc.open("Where is the money Lebowski?").sheet1

wks.update_acell('B2', "it's down there somewhere, let me take another look.")

# Fetch a cell range
cell_list = wks.range('A1:B7')
8 changes: 8 additions & 0 deletions docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,14 @@ Usage

user-guide

Advanced
--------

.. toctree::
:maxdepth: 2

advanced


API Documentation
---------------------------
Expand Down
97 changes: 32 additions & 65 deletions docs/oauth2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,27 +56,49 @@ Remeber the path to the downloaded credentials file. Also, in the next step you'

6. Very important! Go to your spreadsheet and share it with a *client_email* from the step above. Just like you do with any other Google account. If you don't do this, you'll get a ``gspread.exceptions.SpreadsheetNotFound`` exception when trying to access this spreadsheet from your application or a script.

7. Create a Python file and pass the path to the downloaded file to ``from_service_account_file()`` method. Same as in the example below:
7. Move the downloaded file to ``~/.config/gspread/service_account.json``. Windows users should put this file to ``%APPDATA%\gspread\service_account.json``.

8. Create a new Python file with this code:

::

import gspread
from google.oauth2.service_account import Credentials

scopes = ['https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive']
gc = gspread.service_account()

credentials = Credentials.from_service_account_file('path/to/the/downloaded/file.json', scopes=scopes)
sh = gc.open("Example spreadsheet")

gc = gspread.authorize(credentials)
print(sh.sheet1.get('A1'))

wks = gc.open("Where is the money Lebowski?").sheet1
Ta-da!

.. NOTE::
If you want to store the credentials file somewhere else, specify the path to `service_account.json` in :meth:`~gspread.auth.service_account`:
::
gc = gspread.service_account(filename='path/to/the/downloaded/file.json')

print(wks.get('A1'))
Make sure you store the credentials file in a safe place.

Ta-da!

Make sure you store the credentials file in a safe place.
For the curious, under the hood :meth:`~gspread.auth.service_account` loads your credentials and authorizes gspread. Similarly to the code
that has been used for authentication prio to the gspread version 3.6:

::

from google.oauth2.service_account import Credentials

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

credentials = Credentials.from_service_account_file(
'path/to/the/downloaded/file.json',
scopes=scopes
)

gc = gspread.authorize(credentials)


.. NOTE::
Older versions of gspread have used `oauth2client <https://github.com/google/oauth2client>`_. Google has
Expand Down Expand Up @@ -122,58 +144,3 @@ You only need to do authorization in the browser once, following runs will reuse
.. NOTE::
The user interface of Google Developers Console may be different when you're reading this. If you find that this document is out of sync with the actual UI please fix this. Improvements to the documentation are always welcome.
Click **Edit on GitHub** in the top right corner of the page, make it better and submit a PR.


Advanced Usage: Custom Authentication
-------------------------------------

Using Authlib
~~~~~~~~~~~~~

Using ``Authlib`` instead of ``oauth2client``. Authlib has an ``AssertionSession`` which can automatically refresh tokens. With Authlib, you don't have to call ``.login()``::

import json
from gspread import Client
from authlib.client import AssertionSession

def create_assertion_session(conf_file, scopes, subject=None):
with open(conf_file, 'r') as f:
conf = json.load(f)

token_url = conf['token_uri']
issuer = conf['client_email']
key = conf['private_key']
key_id = conf.get('private_key_id')

header = {'alg': 'RS256'}
if key_id:
header['kid'] = key_id

# Google puts scope in payload
claims = {'scope': ' '.join(scopes)}
return AssertionSession(
grant_type=AssertionSession.JWT_BEARER_GRANT_TYPE,
token_url=token_url,
issuer=issuer,
audience=token_url,
claims=claims,
subject=subject,
key=key,
header=header,
)

scopes = [
'https://spreadsheets.google.com/feeds',
'https://www.googleapis.com/auth/drive',
]
session = create_assertion_session('your-google-conf.json', scopes)
gc = Client(None, session)

wks = gc.open("Where is the money Lebowski?").sheet1

wks.update_acell('B2', "it's down there somewhere, let me take another look.")

# Fetch a cell range
cell_list = wks.range('A1:B7')

Remember, you don't need to call ``.login()`` since there is no ``auth``.

0 comments on commit 17360bd

Please sign in to comment.