A python client library for Google Play Services OAuth.
npx @tessl/cli install tessl/pypi-gpsoauth@2.0.00
# GPSOAuth
1
2
A Python client library for Google Play Services OAuth that enables programmatic authentication with Google services using the "master token" flow. This library implements the authentication protocol that allows Python applications to pose as Google apps and obtain OAuth tokens for various Google services without interactive authentication.
3
4
## Package Information
5
6
- **Package Name**: gpsoauth
7
- **Language**: Python
8
- **Installation**: `pip install gpsoauth`
9
10
## Core Imports
11
12
```python
13
import gpsoauth
14
```
15
16
For accessing specific utilities:
17
18
```python
19
from gpsoauth.google import construct_signature, key_from_b64, parse_auth_response, key_to_struct
20
from gpsoauth.util import bytes_to_int, int_to_bytes
21
```
22
23
## Basic Usage
24
25
### Master Login Flow (Primary Method)
26
27
```python
28
import gpsoauth
29
30
# Account credentials and device identifier
31
email = 'example@gmail.com'
32
password = 'my-password'
33
android_id = '0123456789abcdef'
34
35
# Step 1: Perform master login to get master token
36
master_response = gpsoauth.perform_master_login(email, password, android_id)
37
master_token = master_response['Token']
38
39
# Step 2: Use master token to get service-specific auth token
40
auth_response = gpsoauth.perform_oauth(
41
email, master_token, android_id,
42
service='sj',
43
app='com.google.android.music',
44
client_sig='38918a453d07199354f8b19af05ec6562ced5788'
45
)
46
auth_token = auth_response['Auth']
47
48
# Use auth_token in Authorization header: "GoogleLogin auth={auth_token}"
49
```
50
51
### Alternative Token Exchange Flow
52
53
For cases where `BadAuthentication` errors occur with the master login flow:
54
55
```python
56
import gpsoauth
57
58
email = 'example@gmail.com'
59
android_id = '0123456789abcdef'
60
oauth_token = '...' # Obtained from https://accounts.google.com/EmbeddedSetup
61
62
# Exchange web OAuth token for master token
63
master_response = gpsoauth.exchange_token(email, oauth_token, android_id)
64
master_token = master_response['Token']
65
66
# Continue with oauth flow as above
67
auth_response = gpsoauth.perform_oauth(
68
email, master_token, android_id,
69
service='sj',
70
app='com.google.android.music',
71
client_sig='38918a453d07199354f8b19af05ec6562ced5788'
72
)
73
```
74
75
## Capabilities
76
77
### Master Authentication
78
79
Primary authentication method that performs the initial Google account login to obtain a master token.
80
81
```python { .api }
82
def perform_master_login(
83
email: str,
84
password: str,
85
android_id: str,
86
service: str = "ac2dm",
87
device_country: str = "us",
88
operator_country: str = "us",
89
lang: str = "en",
90
sdk_version: int = 17,
91
proxy: MutableMapping[str, str] | None = None,
92
client_sig: str = "38918a453d07199354f8b19af05ec6562ced5788"
93
) -> dict[str, str]:
94
"""
95
Perform a master login, which is what Android does when you first add
96
a Google account.
97
98
Parameters:
99
- email: Google account email address
100
- password: Google account password
101
- android_id: Android device identifier (16-character hex string)
102
- service: Service type for authentication (default: "ac2dm")
103
- device_country: Device country code (default: "us")
104
- operator_country: Operator country code (default: "us")
105
- lang: Language code (default: "en")
106
- sdk_version: Android SDK version number (default: 17)
107
- proxy: Optional proxy configuration dictionary
108
- client_sig: Client signature hash for app identification
109
110
Returns:
111
dict: Authentication response containing keys like:
112
- 'Auth': Master authentication token
113
- 'Token': OAuth refresh token
114
- 'Email': Account email
115
- 'SID': Session ID
116
- 'LSID': Long-term session ID
117
- Other account metadata fields
118
"""
119
```
120
121
### Token Exchange Authentication
122
123
Alternative authentication method for exchanging web OAuth tokens when the master login flow fails.
124
125
```python { .api }
126
def exchange_token(
127
email: str,
128
token: str,
129
android_id: str,
130
service: str = "ac2dm",
131
device_country: str = "us",
132
operator_country: str = "us",
133
lang: str = "en",
134
sdk_version: int = 17,
135
proxy: MutableMapping[str, str] | None = None,
136
client_sig: str = "38918a453d07199354f8b19af05ec6562ced5788"
137
) -> dict[str, str]:
138
"""
139
Exchanges a web oauth_token for a master token.
140
141
Parameters:
142
- email: Google account email address
143
- token: OAuth token obtained from web authentication flow
144
- android_id: Android device identifier (16-character hex string)
145
- service: Service type for authentication (default: "ac2dm")
146
- device_country: Device country code (default: "us")
147
- operator_country: Operator country code (default: "us")
148
- lang: Language code (default: "en")
149
- sdk_version: Android SDK version number (default: 17)
150
- proxy: Optional proxy configuration dictionary
151
- client_sig: Client signature hash for app identification
152
153
Returns:
154
dict: Authentication response with same structure as perform_master_login
155
"""
156
```
157
158
### Service OAuth
159
160
Uses a master token to obtain service-specific authentication tokens for accessing Google APIs.
161
162
```python { .api }
163
def perform_oauth(
164
email: str,
165
master_token: str,
166
android_id: str,
167
service: str,
168
app: str,
169
client_sig: str,
170
device_country: str = "us",
171
operator_country: str = "us",
172
lang: str = "en",
173
sdk_version: int = 17,
174
proxy: MutableMapping[str, str] | None = None
175
) -> dict[str, str]:
176
"""
177
Use a master token from master_login to perform OAuth to a specific Google service.
178
179
Parameters:
180
- email: Google account email address
181
- master_token: Master token from perform_master_login or exchange_token
182
- android_id: Android device identifier (16-character hex string)
183
- service: Target Google service identifier (e.g., 'sj' for Google Music)
184
- app: Application package name (e.g., 'com.google.android.music')
185
- client_sig: Client signature hash for the target application
186
- device_country: Device country code (default: "us")
187
- operator_country: Operator country code (default: "us")
188
- lang: Language code (default: "en")
189
- sdk_version: Android SDK version number (default: 17)
190
- proxy: Optional proxy configuration dictionary
191
192
Returns:
193
dict: Service authentication response containing:
194
- 'Auth': Service-specific authentication token
195
- 'SID': Session ID
196
- 'LSID': Long-term session ID
197
- Other service-specific metadata
198
"""
199
```
200
201
### Cryptographic Utilities
202
203
Low-level cryptographic functions for signature construction and key handling.
204
205
```python { .api }
206
def construct_signature(email: str, password: str, key: RsaKey) -> bytes:
207
"""
208
Construct encrypted password signature for authentication.
209
210
Parameters:
211
- email: Account email address
212
- password: Account password
213
- key: RSA public key for encryption
214
215
Returns:
216
bytes: Base64-encoded encrypted signature
217
"""
218
219
def key_from_b64(b64_key: bytes) -> RsaKey:
220
"""
221
Extract RSA key from base64-encoded key data.
222
223
Parameters:
224
- b64_key: Base64-encoded key bytes
225
226
Returns:
227
RsaKey: Parsed RSA key object
228
"""
229
230
def key_to_struct(key: RsaKey) -> bytes:
231
"""
232
Convert RSA key to binary struct format.
233
234
Parameters:
235
- key: RSA key object
236
237
Returns:
238
bytes: Binary key structure
239
"""
240
241
def parse_auth_response(text: str) -> dict[str, str]:
242
"""
243
Parse Google authentication response text into dictionary.
244
245
Parameters:
246
- text: Raw authentication response text
247
248
Returns:
249
dict: Parsed key-value pairs from response
250
"""
251
```
252
253
### Data Conversion Utilities
254
255
Utility functions for converting between bytes and integers in cryptographic operations.
256
257
```python { .api }
258
def bytes_to_int(bytes_seq: bytes) -> int:
259
"""
260
Convert bytes sequence to integer using big-endian encoding.
261
262
Parameters:
263
- bytes_seq: Byte sequence to convert
264
265
Returns:
266
int: Converted integer value
267
"""
268
269
def int_to_bytes(num: int, pad_multiple: int = 1) -> bytes:
270
"""
271
Convert integer to bytes with optional padding.
272
273
Parameters:
274
- num: Integer to convert (must be non-negative)
275
- pad_multiple: Padding multiple for byte alignment (default: 1)
276
277
Returns:
278
bytes: Big-endian byte representation
279
280
Raises:
281
ValueError: If num is negative
282
"""
283
```
284
285
## Constants and Configuration
286
287
```python { .api }
288
__version__: str
289
# Package version string
290
291
B64_KEY_7_3_29: bytes
292
# Base64-encoded Google Play Services key (version 7.3.29)
293
294
ANDROID_KEY_7_3_29: RsaKey
295
# Parsed RSA key from Google Play Services
296
297
AUTH_URL: str
298
# Google authentication endpoint URL ("https://android.clients.google.com/auth")
299
300
USER_AGENT: str
301
# User agent string for HTTP requests ("GoogleAuth/1.4")
302
303
CIPHERS: list[str]
304
# List of allowed SSL cipher suites for Google authentication
305
306
SSL_DEFAULT_CIPHERS: str | None
307
# Default SSL ciphers (version-dependent, may be None)
308
```
309
310
## Custom Classes
311
312
```python { .api }
313
class SSLContext(ssl.SSLContext):
314
"""
315
SSL context wrapper that prevents ALPN protocol issues.
316
"""
317
def set_alpn_protocols(self, alpn_protocols: Iterable[str]) -> None:
318
"""
319
Override to prevent 403 Bad Authentication errors.
320
ALPN headers cause Google to return authentication failures.
321
"""
322
323
class AuthHTTPAdapter(requests.adapters.HTTPAdapter):
324
"""
325
HTTP adapter with custom TLS settings for Google authentication.
326
"""
327
def init_poolmanager(self, *args: Any, **kwargs: Any) -> None:
328
"""
329
Initialize connection pool with secure SSL settings optimized for Google.
330
Uses secure defaults but disables ssl.OP_NO_TICKET to prevent 403 errors.
331
"""
332
```
333
334
## Types
335
336
```python { .api }
337
from collections.abc import MutableMapping
338
from typing import Any, Iterable
339
from Cryptodome.PublicKey.RSA import RsaKey
340
import ssl
341
import requests.adapters
342
343
# Type aliases and imports used in API signatures
344
RsaKey = Cryptodome.PublicKey.RSA.RsaKey # RSA public key object from pycryptodomex
345
MutableMapping = collections.abc.MutableMapping # Generic mapping type for proxy parameters
346
```
347
348
## Error Handling
349
350
The library may raise various exceptions during authentication:
351
352
- **HTTP-related exceptions**: From the `requests` library (connection errors, timeouts, etc.)
353
- **Authentication failures**: Returned as error details in the response dictionary rather than exceptions
354
- **BadAuthentication errors**: May require using the alternative `exchange_token` flow
355
- **ValueError**: Raised by `int_to_bytes` for negative input values
356
357
When authentication fails, check the response dictionary for error details rather than catching exceptions. If you encounter `BadAuthentication` errors with `perform_master_login`, try the alternative flow using `exchange_token` with a web OAuth token obtained from the Google embedded setup page.
358
359
## Dependencies
360
361
- **pycryptodomex** (>= 3.0): Cryptographic operations for signature construction
362
- **requests** (>= 2.0.0): HTTP client for authentication requests
363
- **urllib3** (>= 1.26.0): Connection pooling and SSL handling