or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

auth.mdchannel.mddiscovery.mderrors.mdhttp.mdindex.mdmedia.mdmimeparse.mdmodel.mdschema.mdtesting.md

auth.mddocs/

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

```