Google Service Account Authentication For Python API Calls: A Simple Example
Summary: Create a Google Cloud service account, configure credentials, and make authenticated API calls from Python using three approaches — explicit key file loading, Application Default Credentials, and manual token extraction with standard
requests.
| Key | Value |
|---|---|
| Python version | 3.12 |
| google-auth version | 2.x |
| requests version | 2.x |
| OS target | Ubuntu 24.04 LTS |
| Example API | Google Sheets API v4 |
| API scope | https://www.googleapis.com/auth/spreadsheets.readonly |
| Service account key file | ~/.config/gcloud/service-account-key.json |
| Working directory | ~/projects/google-auth-demo |
0. Prerequisites
- A Google Cloud account with a project (the free tier works)
- Python
3.12or later installed pipavailable in your terminal- Access to the Google Cloud Console at
https://console.cloud.google.com
Note: Service accounts are designed for server-to-server communication — your application talks directly to a Google API without user interaction. If you need to act on behalf of a human user with their consent, use OAuth 2.0 user credentials instead.
1. Create a Service Account and Download the Key
Open the Google Cloud Console and navigate to IAM & Admin > Service Accounts.
https://console.cloud.google.com/iam-admin/serviceaccounts
- Select your project from the project dropdown at the top of the page.
- Click Create Service Account.
- Give it a descriptive name like
sheets-reader. - For the role, select Viewer (or a more specific role for your use case).
- Click Done to create the account.
Now generate a JSON key file:
- Click the service account you just created.
- Go to the Keys tab.
- Click Add Key > Create new key.
- Select JSON and click Create.
Your browser downloads a JSON file. Move it to a secure location.
mkdir -p ~/.config/gcloud
mv ~/Downloads/your-project-abc123.json ~/.config/gcloud/service-account-key.json
chmod 600 ~/.config/gcloud/service-account-key.jsonCode language: Shell Session (shell)
The chmod 600 command restricts the file so only your user account can read it.
Warning: Never commit this key file to version control. Add the path to your
.gitignoreand treat it like a password.
The key file contains fields like these (with your project’s values filled in):
{
"type": "service_account",
"project_id": "<YOUR_PROJECT_ID>",
"private_key_id": "<YOUR_PRIVATE_KEY_ID>",
"private_key": "<YOUR_PRIVATE_KEY>",
"client_email": "<NAME>@<YOUR_PROJECT_ID>.iam.gserviceaccount.com",
"client_id": "<YOUR_CLIENT_ID>",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "<YOUR_CERT_URL>"
}Code language: JSON / JSON with Comments (json)
The client_email field is important — you need it to share resources (like spreadsheets) with the service account.
2. Enable the API and Share a Test Resource
Before making API calls, enable the API you want to use.
- In the Google Cloud Console, go to APIs & Services > Library.
- Search for Google Sheets API and click Enable.
Now share a Google Sheet with your service account so it can read data:
- Open any Google Sheet in your browser.
- Click Share.
- Paste the
client_emailfrom your key file (it looks like[email protected]). - Set the permission to Viewer and click Send.
Copy the spreadsheet ID from the URL. In a URL like https://docs.google.com/spreadsheets/d/1aBcDeFgHiJkLmNoPqRsTuVwXyZ/edit, the spreadsheet ID is the string between /d/ and /edit.
Tip: Every Google API has its own scope string that defines what permissions you are requesting. You can find the required scopes in the API’s documentation or its Discovery Document — a JSON specification that describes the API’s endpoints, methods, and auth requirements. For example, the Google Sheets read-only scope is
https://www.googleapis.com/auth/spreadsheets.readonly.
3. Set Up the Python Environment
Create a project directory with a virtual environment.
mkdir -p ~/projects/google-auth-demo
cd ~/projects/google-auth-demo
python -m venv .venv
source .venv/bin/activateCode language: Shell Session (shell)
Install the required packages.
pip install google-auth requestsCode language: Shell Session (shell)
google-auth handles credential loading and token management. requests provides the HTTP client that AuthorizedSession wraps.
4. Approach 1 — Explicit Credentials with AuthorizedSession
This is the most straightforward approach. You point directly at the key file, and AuthorizedSession handles token refresh and authorization headers automatically.
Create a file called auth_explicit.py.
from google.oauth2 import service_account
from google.auth.transport.requests import AuthorizedSession
SERVICE_ACCOUNT_FILE = "/home/user/.config/gcloud/service-account-key.json"
SCOPES = ["https://www.googleapis.com/auth/spreadsheets.readonly"]
SPREADSHEET_ID = "<YOUR_SPREADSHEET_ID>"
CELL_RANGE = "Sheet1!A1:C10"
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES
)
session = AuthorizedSession(credentials)
url = f"https://sheets.googleapis.com/v4/spreadsheets/{SPREADSHEET_ID}/values/{CELL_RANGE}"
response = session.get(url)
print(response.status_code)
print(response.json())Code language: Python (python)
Run it.
python auth_explicit.pyCode language: Shell Session (shell)
200
{‘range’: ‘Sheet1!A1:C10’, ‘majorDimension’: ‘ROWS’, ‘values’: [[‘Name’, ‘Age’, ‘City’], …]}
AuthorizedSession inherits from requests.Session. It automatically refreshes expired tokens and injects the Authorization header into every request. You can call .get(), .post(), .put(), and .delete() exactly as you would with a standard requests.Session.
| Component | What it does |
|---|---|
from_service_account_file() | Loads the private key from the JSON file and creates a Credentials object |
scopes | Tells Google which API permissions your application needs |
AuthorizedSession | Wraps requests.Session with automatic token management and auth headers |
5. Approach 2 — Application Default Credentials
Application Default Credentials (ADC) let your code find credentials automatically without hardcoding a file path. This is the recommended approach when deploying to Google Cloud because GCP provides credentials to your code through the environment.
For local development, set the GOOGLE_APPLICATION_CREDENTIALS environment variable to point at your key file.
export GOOGLE_APPLICATION_CREDENTIALS=/home/user/.config/gcloud/service-account-key.jsonCode language: Shell Session (shell)
Create a file called auth_adc.py.
import google.auth
from google.auth.transport.requests import AuthorizedSession
SCOPES = ["https://www.googleapis.com/auth/spreadsheets.readonly"]
SPREADSHEET_ID = "<YOUR_SPREADSHEET_ID>"
CELL_RANGE = "Sheet1!A1:C10"
credentials, project = google.auth.default(scopes=SCOPES)
session = AuthorizedSession(credentials)
url = f"https://sheets.googleapis.com/v4/spreadsheets/{SPREADSHEET_ID}/values/{CELL_RANGE}"
response = session.get(url)
print(response.status_code)
print(response.json())Code language: Python (python)
Run it.
python auth_adc.pyCode language: Shell Session (shell)
The code is nearly identical to Approach 1 — the only difference is how credentials are loaded. google.auth.default() searches for credentials in this order:
- The
GOOGLE_APPLICATION_CREDENTIALSenvironment variable. - The default service account attached to a GCP resource (Compute Engine, Cloud Run, Cloud Functions).
- The user credentials from
gcloud auth application-default login.
This means the same code works on your laptop (via the environment variable) and in production (via the attached service account) without any changes.
Tip: On GCP, skip the key file entirely. Attach a service account to your Compute Engine instance or Cloud Run service, and
google.auth.default()picks it up automatically — no file to manage, no secret to rotate.
6. Approach 3 — Manual Token Extraction with Standard Requests
Sometimes you need full control over the HTTP request — custom headers, specific retry logic, or integration with a library that expects raw tokens. In this case, extract the access token from the credentials and build a standard requests call yourself.
Create a file called auth_manual.py.
import google.auth
import google.auth.transport.requests
from requests import Request, Session
SCOPES = ["https://www.googleapis.com/auth/spreadsheets.readonly"]
SPREADSHEET_ID = "<YOUR_SPREADSHEET_ID>"
CELL_RANGE = "Sheet1!A1:C10"
credentials, project = google.auth.default(scopes=SCOPES)
request_adapter = google.auth.transport.requests.Request()
credentials.refresh(request_adapter)
print(f"Token (first 20 chars): {credentials.token[:20]}...")
url = f"https://sheets.googleapis.com/v4/spreadsheets/{SPREADSHEET_ID}/values/{CELL_RANGE}"
api_request = Request(
"GET",
url,
headers={"Authorization": f"Bearer {credentials.token}"},
)
session = Session()
prepared = session.prepare_request(api_request)
response = session.send(prepared)
print(response.status_code)
print(response.json())Code language: Python (python)
Run it.
export GOOGLE_APPLICATION_CREDENTIALS=/home/user/.config/gcloud/service-account-key.json
python auth_manual.pyCode language: Shell Session (shell)
Token (first 20 chars): ya29.c.b0AXv0zTPa2x…
200
{‘range’: ‘Sheet1!A1:C10’, ‘majorDimension’: ‘ROWS’, ‘values’: [[‘Name’, ‘Age’, ‘City’], …]}
Here is what each step does:
| Step | Code | Purpose |
|---|---|---|
| Load credentials | google.auth.default(scopes=SCOPES) | Gets credentials from ADC |
| Refresh token | credentials.refresh(request_adapter) | Exchanges the private key for a short-lived access token |
| Read token | credentials.token | The Bearer token string for HTTP headers |
| Build request | Request("GET", url, headers=...) | A standard requests.Request with the token in the Authorization header |
| Send request | session.send(prepared) | Sends the prepared request using a plain requests.Session |
Warning: Access tokens expire after approximately one hour. If your application runs longer than that, call
credentials.refresh()again to get a new token.AuthorizedSession(Approaches 1 and 2) handles this renewal automatically.
7. Choose the Right Approach
| Approach | Best for | Credential loading | Request handling |
|---|---|---|---|
| Explicit + AuthorizedSession | Scripts, local tools, known key file location | from_service_account_file() | Automatic |
| ADC + AuthorizedSession | Production on GCP, portable code | google.auth.default() | Automatic |
| Manual token + standard requests | Custom HTTP logic, non-requests libraries, debugging | google.auth.default() + refresh() | Manual |
For most applications, start with ADC + AuthorizedSession (Approach 2). Your code stays portable — the same script works on your laptop and in production without changes.
Use Explicit credentials (Approach 1) when you need to load a specific key file regardless of environment, or when you manage multiple service accounts in the same application.
Use Manual token extraction (Approach 3) when you need the raw access token — for example, when passing it to a library that manages its own HTTP calls, or when debugging authentication issues.
Tip: These examples use the Google Sheets API, but the authentication patterns are identical for any Google API — Drive, BigQuery, Cloud Storage, Display & Video 360, or any other service. Change the scope and endpoint URL, and the auth code stays the same.
Summary
You created a Google Cloud service account, downloaded its JSON key file, and used it to make authenticated Python API calls three different ways.
- Approach 1 loads the key file explicitly with
from_service_account_file()and pairs it withAuthorizedSessionfor automatic token management. - Approach 2 uses Application Default Credentials via
google.auth.default()so the same code runs locally and on GCP without changes. - Approach 3 extracts the raw access token with
credentials.refresh()and uses it in a standardrequestsprepared request for full HTTP control. AuthorizedSessioninherits fromrequests.Sessionand handles token refresh and auth headers automatically.- Access tokens expire after approximately one hour —
AuthorizedSessionrenews them for you, but manual token users must callcredentials.refresh()again. - Never commit key files to version control — use environment variables or GCP’s built-in credential injection instead.
