A python client library for Google Play Services OAuth.
npx @tessl/cli install tessl/pypi-gpsoauth@2.0.0A 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.
pip install gpsoauthimport gpsoauthFor accessing specific utilities:
from gpsoauth.google import construct_signature, key_from_b64, parse_auth_response, key_to_struct
from gpsoauth.util import bytes_to_int, int_to_bytesimport gpsoauth
# Account credentials and device identifier
email = 'example@gmail.com'
password = 'my-password'
android_id = '0123456789abcdef'
# Step 1: Perform master login to get master token
master_response = gpsoauth.perform_master_login(email, password, android_id)
master_token = master_response['Token']
# Step 2: Use master token to get service-specific auth token
auth_response = gpsoauth.perform_oauth(
email, master_token, android_id,
service='sj',
app='com.google.android.music',
client_sig='38918a453d07199354f8b19af05ec6562ced5788'
)
auth_token = auth_response['Auth']
# Use auth_token in Authorization header: "GoogleLogin auth={auth_token}"For cases where BadAuthentication errors occur with the master login flow:
import gpsoauth
email = 'example@gmail.com'
android_id = '0123456789abcdef'
oauth_token = '...' # Obtained from https://accounts.google.com/EmbeddedSetup
# Exchange web OAuth token for master token
master_response = gpsoauth.exchange_token(email, oauth_token, android_id)
master_token = master_response['Token']
# Continue with oauth flow as above
auth_response = gpsoauth.perform_oauth(
email, master_token, android_id,
service='sj',
app='com.google.android.music',
client_sig='38918a453d07199354f8b19af05ec6562ced5788'
)Primary authentication method that performs the initial Google account login to obtain a master token.
def perform_master_login(
email: str,
password: str,
android_id: str,
service: str = "ac2dm",
device_country: str = "us",
operator_country: str = "us",
lang: str = "en",
sdk_version: int = 17,
proxy: MutableMapping[str, str] | None = None,
client_sig: str = "38918a453d07199354f8b19af05ec6562ced5788"
) -> dict[str, str]:
"""
Perform a master login, which is what Android does when you first add
a Google account.
Parameters:
- email: Google account email address
- password: Google account password
- android_id: Android device identifier (16-character hex string)
- service: Service type for authentication (default: "ac2dm")
- device_country: Device country code (default: "us")
- operator_country: Operator country code (default: "us")
- lang: Language code (default: "en")
- sdk_version: Android SDK version number (default: 17)
- proxy: Optional proxy configuration dictionary
- client_sig: Client signature hash for app identification
Returns:
dict: Authentication response containing keys like:
- 'Auth': Master authentication token
- 'Token': OAuth refresh token
- 'Email': Account email
- 'SID': Session ID
- 'LSID': Long-term session ID
- Other account metadata fields
"""Alternative authentication method for exchanging web OAuth tokens when the master login flow fails.
def exchange_token(
email: str,
token: str,
android_id: str,
service: str = "ac2dm",
device_country: str = "us",
operator_country: str = "us",
lang: str = "en",
sdk_version: int = 17,
proxy: MutableMapping[str, str] | None = None,
client_sig: str = "38918a453d07199354f8b19af05ec6562ced5788"
) -> dict[str, str]:
"""
Exchanges a web oauth_token for a master token.
Parameters:
- email: Google account email address
- token: OAuth token obtained from web authentication flow
- android_id: Android device identifier (16-character hex string)
- service: Service type for authentication (default: "ac2dm")
- device_country: Device country code (default: "us")
- operator_country: Operator country code (default: "us")
- lang: Language code (default: "en")
- sdk_version: Android SDK version number (default: 17)
- proxy: Optional proxy configuration dictionary
- client_sig: Client signature hash for app identification
Returns:
dict: Authentication response with same structure as perform_master_login
"""Uses a master token to obtain service-specific authentication tokens for accessing Google APIs.
def perform_oauth(
email: str,
master_token: str,
android_id: str,
service: str,
app: str,
client_sig: str,
device_country: str = "us",
operator_country: str = "us",
lang: str = "en",
sdk_version: int = 17,
proxy: MutableMapping[str, str] | None = None
) -> dict[str, str]:
"""
Use a master token from master_login to perform OAuth to a specific Google service.
Parameters:
- email: Google account email address
- master_token: Master token from perform_master_login or exchange_token
- android_id: Android device identifier (16-character hex string)
- service: Target Google service identifier (e.g., 'sj' for Google Music)
- app: Application package name (e.g., 'com.google.android.music')
- client_sig: Client signature hash for the target application
- device_country: Device country code (default: "us")
- operator_country: Operator country code (default: "us")
- lang: Language code (default: "en")
- sdk_version: Android SDK version number (default: 17)
- proxy: Optional proxy configuration dictionary
Returns:
dict: Service authentication response containing:
- 'Auth': Service-specific authentication token
- 'SID': Session ID
- 'LSID': Long-term session ID
- Other service-specific metadata
"""Low-level cryptographic functions for signature construction and key handling.
def construct_signature(email: str, password: str, key: RsaKey) -> bytes:
"""
Construct encrypted password signature for authentication.
Parameters:
- email: Account email address
- password: Account password
- key: RSA public key for encryption
Returns:
bytes: Base64-encoded encrypted signature
"""
def key_from_b64(b64_key: bytes) -> RsaKey:
"""
Extract RSA key from base64-encoded key data.
Parameters:
- b64_key: Base64-encoded key bytes
Returns:
RsaKey: Parsed RSA key object
"""
def key_to_struct(key: RsaKey) -> bytes:
"""
Convert RSA key to binary struct format.
Parameters:
- key: RSA key object
Returns:
bytes: Binary key structure
"""
def parse_auth_response(text: str) -> dict[str, str]:
"""
Parse Google authentication response text into dictionary.
Parameters:
- text: Raw authentication response text
Returns:
dict: Parsed key-value pairs from response
"""Utility functions for converting between bytes and integers in cryptographic operations.
def bytes_to_int(bytes_seq: bytes) -> int:
"""
Convert bytes sequence to integer using big-endian encoding.
Parameters:
- bytes_seq: Byte sequence to convert
Returns:
int: Converted integer value
"""
def int_to_bytes(num: int, pad_multiple: int = 1) -> bytes:
"""
Convert integer to bytes with optional padding.
Parameters:
- num: Integer to convert (must be non-negative)
- pad_multiple: Padding multiple for byte alignment (default: 1)
Returns:
bytes: Big-endian byte representation
Raises:
ValueError: If num is negative
"""__version__: str
# Package version string
B64_KEY_7_3_29: bytes
# Base64-encoded Google Play Services key (version 7.3.29)
ANDROID_KEY_7_3_29: RsaKey
# Parsed RSA key from Google Play Services
AUTH_URL: str
# Google authentication endpoint URL ("https://android.clients.google.com/auth")
USER_AGENT: str
# User agent string for HTTP requests ("GoogleAuth/1.4")
CIPHERS: list[str]
# List of allowed SSL cipher suites for Google authentication
SSL_DEFAULT_CIPHERS: str | None
# Default SSL ciphers (version-dependent, may be None)class SSLContext(ssl.SSLContext):
"""
SSL context wrapper that prevents ALPN protocol issues.
"""
def set_alpn_protocols(self, alpn_protocols: Iterable[str]) -> None:
"""
Override to prevent 403 Bad Authentication errors.
ALPN headers cause Google to return authentication failures.
"""
class AuthHTTPAdapter(requests.adapters.HTTPAdapter):
"""
HTTP adapter with custom TLS settings for Google authentication.
"""
def init_poolmanager(self, *args: Any, **kwargs: Any) -> None:
"""
Initialize connection pool with secure SSL settings optimized for Google.
Uses secure defaults but disables ssl.OP_NO_TICKET to prevent 403 errors.
"""from collections.abc import MutableMapping
from typing import Any, Iterable
from Cryptodome.PublicKey.RSA import RsaKey
import ssl
import requests.adapters
# Type aliases and imports used in API signatures
RsaKey = Cryptodome.PublicKey.RSA.RsaKey # RSA public key object from pycryptodomex
MutableMapping = collections.abc.MutableMapping # Generic mapping type for proxy parametersThe library may raise various exceptions during authentication:
requests library (connection errors, timeouts, etc.)exchange_token flowint_to_bytes for negative input valuesWhen 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.