0
# Authentication Integration
1
2
The Google API Python Client provides authentication helper functions that seamlessly integrate with google-auth and oauth2client libraries, enabling credential management, scope handling, and request authentication.
3
4
## Capabilities
5
6
### Credential Management
7
8
Helper functions for obtaining and managing authentication credentials.
9
10
```python { .api }
11
def default_credentials():
12
"""
13
Get default credentials from the environment.
14
15
Uses Application Default Credentials (ADC) to find credentials from:
16
1. GOOGLE_APPLICATION_CREDENTIALS environment variable
17
2. User credentials from gcloud auth application-default login
18
3. Service account attached to Google Cloud resource
19
4. Google Cloud SDK default credentials
20
21
Returns:
22
tuple: (credentials, project_id) where credentials is a Credentials
23
object and project_id is the default project ID
24
25
Raises:
26
DefaultCredentialsError: When no valid credentials are found
27
"""
28
29
def with_scopes(credentials, scopes):
30
"""
31
Add OAuth2 scopes to credentials if the credentials support scoping.
32
33
Args:
34
credentials: OAuth2 credentials object (google-auth or oauth2client)
35
scopes (list or str): List of OAuth2 scope URLs or single scope string
36
37
Returns:
38
Credentials: Credentials object with scopes applied, or original
39
credentials if scoping is not supported
40
"""
41
42
def apply_credentials(credentials, headers):
43
"""
44
Apply authentication credentials to HTTP request headers.
45
46
Args:
47
credentials: OAuth2 credentials object
48
headers (dict): HTTP headers dictionary to modify in-place
49
50
Raises:
51
RefreshError: When credential refresh fails
52
TransportError: When credential application fails
53
"""
54
```
55
56
### Authentication Utilities
57
58
Utility functions for working with different authentication flows and credential types.
59
60
```python { .api }
61
def refresh_credentials(credentials):
62
"""
63
Refresh expired credentials.
64
65
Args:
66
credentials: OAuth2 credentials object to refresh
67
68
Returns:
69
Credentials: Refreshed credentials object
70
71
Raises:
72
RefreshError: When credential refresh fails
73
"""
74
75
def credentials_from_authorized_user_info(info, scopes=None):
76
"""
77
Create credentials from authorized user info dictionary.
78
79
Args:
80
info (dict): Dictionary containing authorized user information
81
scopes (list, optional): List of OAuth2 scopes to apply
82
83
Returns:
84
Credentials: OAuth2 credentials object
85
"""
86
87
def credentials_from_service_account_info(info, scopes=None):
88
"""
89
Create credentials from service account info dictionary.
90
91
Args:
92
info (dict): Dictionary containing service account information
93
scopes (list, optional): List of OAuth2 scopes to apply
94
95
Returns:
96
Credentials: Service account credentials object
97
"""
98
```
99
100
## Usage Examples
101
102
### Application Default Credentials
103
104
```python
105
from googleapiclient import discovery
106
from googleapiclient._auth import default_credentials
107
108
# Get default credentials from environment
109
credentials, project = default_credentials()
110
111
# Build service with default credentials
112
service = discovery.build('gmail', 'v1', credentials=credentials)
113
114
# Use the service
115
messages = service.users().messages().list(userId='me').execute()
116
print(f"Project: {project}")
117
print(f"Messages: {len(messages.get('messages', []))}")
118
```
119
120
### Adding Scopes to Credentials
121
122
```python
123
from googleapiclient._auth import default_credentials, with_scopes
124
125
# Get default credentials
126
credentials, project = default_credentials()
127
128
# Define required scopes
129
gmail_scopes = [
130
'https://www.googleapis.com/auth/gmail.readonly',
131
'https://www.googleapis.com/auth/gmail.send'
132
]
133
134
# Add scopes to credentials
135
scoped_credentials = with_scopes(credentials, gmail_scopes)
136
137
# Build service with scoped credentials
138
service = discovery.build('gmail', 'v1', credentials=scoped_credentials)
139
```
140
141
### Manual Credential Application
142
143
```python
144
from googleapiclient._auth import apply_credentials
145
import httplib2
146
147
# Get credentials
148
credentials, _ = default_credentials()
149
150
# Create HTTP client
151
http = httplib2.Http()
152
153
# Prepare request headers
154
headers = {
155
'Content-Type': 'application/json',
156
'User-Agent': 'MyApp/1.0'
157
}
158
159
# Apply credentials to headers
160
apply_credentials(credentials, headers)
161
162
# Headers now contain Authorization header
163
print(headers.get('authorization')) # Bearer <access_token>
164
```
165
166
### Service Account Authentication
167
168
```python
169
from google.oauth2 import service_account
170
from googleapiclient import discovery
171
from googleapiclient._auth import with_scopes
172
173
# Load service account credentials from file
174
credentials = service_account.Credentials.from_service_account_file(
175
'path/to/service-account-key.json'
176
)
177
178
# Add required scopes
179
scopes = ['https://www.googleapis.com/auth/gmail.readonly']
180
scoped_credentials = with_scopes(credentials, scopes)
181
182
# Build service
183
service = discovery.build('gmail', 'v1', credentials=scoped_credentials)
184
```
185
186
### OAuth2 User Credentials
187
188
```python
189
from google.auth.transport.requests import Request
190
from google.oauth2.credentials import Credentials
191
from google_auth_oauthlib.flow import InstalledAppFlow
192
from googleapiclient import discovery
193
import os
194
195
def get_authenticated_service():
196
"""Get authenticated Gmail service using OAuth2 flow."""
197
scopes = ['https://www.googleapis.com/auth/gmail.readonly']
198
creds = None
199
200
# Load existing credentials
201
if os.path.exists('token.json'):
202
creds = Credentials.from_authorized_user_file('token.json', scopes)
203
204
# If no valid credentials, run OAuth flow
205
if not creds or not creds.valid:
206
if creds and creds.expired and creds.refresh_token:
207
creds.refresh(Request())
208
else:
209
flow = InstalledAppFlow.from_client_secrets_file(
210
'credentials.json', scopes)
211
creds = flow.run_local_server(port=0)
212
213
# Save credentials for next run
214
with open('token.json', 'w') as token:
215
token.write(creds.to_json())
216
217
return discovery.build('gmail', 'v1', credentials=creds)
218
219
# Use the authenticated service
220
service = get_authenticated_service()
221
```
222
223
### Credential Refresh Handling
224
225
```python
226
from googleapiclient._auth import default_credentials, apply_credentials
227
from google.auth.exceptions import RefreshError
228
from googleapiclient.errors import HttpError
229
import httplib2
230
231
def make_authenticated_request(uri, method='GET', body=None):
232
"""Make an authenticated HTTP request with automatic credential refresh."""
233
credentials, _ = default_credentials()
234
235
try:
236
# Prepare headers
237
headers = {'Content-Type': 'application/json'}
238
apply_credentials(credentials, headers)
239
240
# Make request
241
http = httplib2.Http()
242
response, content = http.request(
243
uri, method=method, body=body, headers=headers
244
)
245
246
return response, content
247
248
except RefreshError as e:
249
print(f"Credential refresh failed: {e}")
250
raise
251
except HttpError as e:
252
if e.status_code == 401:
253
print("Authentication failed - credentials may be invalid")
254
raise
255
256
# Usage
257
response, content = make_authenticated_request(
258
'https://gmail.googleapis.com/gmail/v1/users/me/messages'
259
)
260
```
261
262
### Multi-Credential Management
263
264
```python
265
from googleapiclient import discovery
266
from googleapiclient._auth import with_scopes
267
from google.oauth2 import service_account
268
import google.auth
269
270
class CredentialManager:
271
"""Manage multiple credential types for different services."""
272
273
def __init__(self):
274
self.credentials = {}
275
self.services = {}
276
277
def add_default_credentials(self, name, scopes=None):
278
"""Add Application Default Credentials."""
279
creds, project = google.auth.default()
280
if scopes:
281
creds = with_scopes(creds, scopes)
282
self.credentials[name] = creds
283
return creds
284
285
def add_service_account(self, name, key_file, scopes=None):
286
"""Add service account credentials."""
287
creds = service_account.Credentials.from_service_account_file(key_file)
288
if scopes:
289
creds = with_scopes(creds, scopes)
290
self.credentials[name] = creds
291
return creds
292
293
def get_service(self, cred_name, service_name, version):
294
"""Get an authenticated service using named credentials."""
295
if cred_name not in self.credentials:
296
raise ValueError(f"No credentials found for {cred_name}")
297
298
service_key = f"{cred_name}:{service_name}:{version}"
299
if service_key not in self.services:
300
self.services[service_key] = discovery.build(
301
service_name, version,
302
credentials=self.credentials[cred_name]
303
)
304
305
return self.services[service_key]
306
307
# Usage
308
cred_manager = CredentialManager()
309
310
# Add different credential types
311
cred_manager.add_default_credentials(
312
'user_gmail',
313
['https://www.googleapis.com/auth/gmail.readonly']
314
)
315
316
cred_manager.add_service_account(
317
'service_drive',
318
'service-account.json',
319
['https://www.googleapis.com/auth/drive']
320
)
321
322
# Get services with different credentials
323
gmail_service = cred_manager.get_service('user_gmail', 'gmail', 'v1')
324
drive_service = cred_manager.get_service('service_drive', 'drive', 'v3')
325
```
326
327
### Testing with Mock Credentials
328
329
```python
330
from googleapiclient import discovery
331
from googleapiclient._auth import apply_credentials
332
import unittest.mock
333
334
class MockCredentials:
335
"""Mock credentials for testing."""
336
337
def __init__(self, token='mock_token'):
338
self.token = token
339
self.expired = False
340
341
def refresh(self, request):
342
"""Mock credential refresh."""
343
pass
344
345
def apply(self, headers, token=None):
346
"""Apply mock token to headers."""
347
headers['authorization'] = f'Bearer {self.token}'
348
349
def test_service_with_mock_credentials():
350
"""Test service creation with mock credentials."""
351
mock_creds = MockCredentials('test_token')
352
353
# Test header application
354
headers = {}
355
mock_creds.apply(headers)
356
assert headers['authorization'] == 'Bearer test_token'
357
358
# Test service building (with HTTP mock)
359
from googleapiclient.http import HttpMock
360
http_mock = HttpMock()
361
362
with unittest.mock.patch('googleapiclient._auth.default_credentials') as mock_default:
363
mock_default.return_value = (mock_creds, 'test-project')
364
365
service = discovery.build('gmail', 'v1', http=http_mock)
366
# Service created successfully with mock credentials
367
368
# Run test
369
test_service_with_mock_credentials()
370
print("Mock credential test passed")
371
```
372
373
### Credential Storage and Persistence
374
375
```python
376
from googleapiclient._auth import default_credentials
377
from google.oauth2.credentials import Credentials
378
import json
379
import os
380
381
class CredentialStore:
382
"""Store and retrieve credentials securely."""
383
384
def __init__(self, store_path='credentials_store.json'):
385
self.store_path = store_path
386
self.credentials = {}
387
self.load_credentials()
388
389
def load_credentials(self):
390
"""Load credentials from storage."""
391
if os.path.exists(self.store_path):
392
try:
393
with open(self.store_path, 'r') as f:
394
data = json.load(f)
395
396
for name, cred_data in data.items():
397
if cred_data['type'] == 'authorized_user':
398
self.credentials[name] = Credentials.from_authorized_user_info(
399
cred_data['info']
400
)
401
except (json.JSONDecodeError, KeyError, ValueError):
402
print("Warning: Could not load stored credentials")
403
404
def save_credentials(self):
405
"""Save credentials to storage."""
406
data = {}
407
for name, creds in self.credentials.items():
408
if hasattr(creds, 'to_json'):
409
data[name] = {
410
'type': 'authorized_user',
411
'info': json.loads(creds.to_json())
412
}
413
414
with open(self.store_path, 'w') as f:
415
json.dump(data, f, indent=2)
416
417
def add_credentials(self, name, credentials):
418
"""Add credentials to store."""
419
self.credentials[name] = credentials
420
self.save_credentials()
421
422
def get_credentials(self, name):
423
"""Get credentials by name."""
424
return self.credentials.get(name)
425
426
# Usage
427
store = CredentialStore()
428
429
# Add default credentials
430
creds, _ = default_credentials()
431
store.add_credentials('default', creds)
432
433
# Retrieve later
434
stored_creds = store.get_credentials('default')
435
service = discovery.build('gmail', 'v1', credentials=stored_creds)
436
```