Using Authlib with gspread

A guide on how to use Authlib in gspread instead of Google oauth2client.

There is a popular python library to communicate with Google Spreadsheets API, which is gspread. Here is a tip on how to use it with Authlib. Just like Google Analytics API and Google Cloud Storage, Google Spreadsheets is also an AssertionSession.

Why use Authlib

But why do you want to use Authlib instead of oauth2client?

  1. Authlib AssertionSession and gspread are both using requests, you don't have to use another http library
  2. Authib will automatically refresh access token, while oauth2client in gspread can't. (but oauth2client itself can)
  3. Unlike oauth2client, you know exactly what's going on in Authlib, it is a white box
  4. Oh, oauth2client is deprecated.

What is AssertionSession

Authlib has just released version 0.7. In this version, Authlib has provided a AssertionSession which is a client implementation of RFC7523. That has been said, Google's so called service account is actually JWT for Authorization Grants. You can get a bearer token with grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer and a JWT assertion.

POST /token.oauth2 HTTP/1.1
Host: authz.example.net
Content-Type: application/x-www-form-urlencoded

grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer
&assertion=eyJhbGciOiJFUzI1NiIsImtpZCI6IjE2In0.eyJpc3Mi[...omitted for brevity...]

And this is what AssertionSession is doing. It will get a valid OAuth token automatically, prepare a requests session for you to use. Yes, it is just a requests session.

How to use Authlib

Here is the simple code:

import json
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)

And then use this session in gspread:

from gspread import Client

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')

You can use it directly, there is no need to call .login() method.

Find more information on Authlib Documentation.