How to replace oauth2client with google-auth and google-auth-oauthlib
Recently I made an update for some legacy code and one of the tasks was to replace oauth2client. This library used to interact with OAuth2-protected resources related to Google API and deprecated since September 2018. The recomendation is to use google-auth and for OAuth 2 flow google-auth-oauthlib. The changes are simple.
If your code looks like this:
import httplib2
from oauth2client.client import GoogleCredentials, OAuth2Credentials
from oauth2client.service_account import ServiceAccountCredentials
credentials = OAuth2Credentials.from_json(credentials_json)
# to get list of domains
service = discovery.build("admin", "directory_v1", credentials=credentials)
request = service.domains().list(customer="my_customer")
result = request.execute()
# to get user signature
scopes = ["https://www.googleapis.com/auth/gmail.settings.basic"]
credentials = ServiceAccountCredentials.from_json_keyfile_name("google_config.json", scopes=scopes)
credentials = credentials.create_delegated(email)
service = discovery.build("gmail", "v1", credentials=credentials)
request = service.users().settings().sendAs().get(userId=email, sendAsEmail=email)
signature = request.execute()["signature"]
# to refresh
if credentials.access_token_expired:
credentials.refresh(httplib2.Http())
You’ll need only to replace credentials with version from google-auth.
from datetime import datetime
from google.oauth2.credentials import Credentials
from google.auth.transport.requests import Request
credentials_dict = json.loads(credentials_json) # credentials_json are credentials saved from oauth2client
credentials = google.oauth2.credentials.Credentials(
token=credentials_dict["access_token"],
refresh_token=credentials_dict["refresh_token"],
token_uri=credentials_dict["token_uri"],
client_id=credentials_dict["client_id"],
client_secret=credentials_dict["client_secret"],
scopes=credentials_dict["scopes"],
expiry=datetime.fromisoformat(credentials_dict["token_expiry"][:-1])
)
# to get list of domains - the same
service = discovery.build("admin", "directory_v1", credentials=credentials)
request = service.domains().list(customer="my_customer")
result = request.execute()
# to get user signature - almost the same
scopes = ["https://www.googleapis.com/auth/gmail.settings.basic"]
credentials = service_account.Credentials.from_service_account_file("google_config.json", scopes=scopes)
credentials = credentials.with_subject(email) # with_subject instead create_delegated
service = discovery.build("gmail", "v1", credentials=cred_serv2)
request = service.users().settings().sendAs().get(userId=email, sendAsEmail=email)
signature = request.execute()["signature"]
# to refresh
if credentials.expired:
credentials.refresh(Request()) # Request() instead httplib2.Http()
Authorization flow
Main steps with oauth2client:
import httplib2
from oauth2client.client import HttpAccessTokenRefreshError, OAuth2Credentials, OAuth2WebServerFlow
# init flow
scopes = [
"https://www.googleapis.com/auth/admin.directory.user.readonly",
"https://www.googleapis.com/auth/admin.directory.group.readonly",
"https://www.googleapis.com/auth/admin.directory.domain.readonly",
"https://www.googleapis.com/auth/admin.directory.userschema.readonly",
]
flow = OAuth2WebServerFlow(
client_id=GOOGLE_CLIENT_ID,
client_secret=GOOGLE_CLIENT_SECRET,
scope=scope,
redirect_uri=url_for("authorisation.google", _external=True),
access_type="offline",
prompt="consent",
# 1. redirect to google
...
auth_uri = flow.step1_get_authorize_url()
return redirect(auth_uri)
...
# 2. get credentials in auhtorisation.google route after redirect from google
...
auth_code = request.args.get("code")
credentials = flow.step2_exchange(auth_code)
...
With google_auth_oauthlib it’s mostly the same too:
from google.auth.exceptions import RefreshError
from google_auth_oauthlib.flow import Flow
# init flow
scopes = [
"https://www.googleapis.com/auth/admin.directory.user.readonly",
"https://www.googleapis.com/auth/admin.directory.group.readonly",
"https://www.googleapis.com/auth/admin.directory.domain.readonly",
"https://www.googleapis.com/auth/admin.directory.userschema.readonly",
]
redirect_uri = url_for("authorisation.google", _external=True)
flow = Flow.from_client_config(
{
"web": {
"client_id": GOOGLE_CLIENT_ID,
"client_secret": GOOGLE_CLIENT_SECRET,
"redirect_uris": [redirect_uri],
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token",
}
},
scopes=scopes,
)
flow.redirect_uri = redirect_uri
# 1. redirect to google
...
authorization_url, state = flow.authorization_url(access_type="offline", prompt="consent")
return redirect(authorization_url)
...
# 2. get credentials in auhtorisation.google route after redirect from google
...
authorization_response = request.url
flow.fetch_token(authorization_response=authorization_response)
credentials = flow.credentials
...
To test it without https you’ll need to set environment variable OAUTHLIB_INSECURE_TRANSPORT=1