Files
autoreg-skills-max/skills/grok-autoreg/references/sso-to-oauth-conversion.md

123 lines
4.0 KiB
Markdown

# SSO → OAuth Conversion via Device Auth Flow
## Overview
Converts SSO session cookies (from GrokRegister) to OAuth access tokens via x.ai's OAuth device code flow. Uses DrissionPage to automate the browser authorization step.
## Prerequisites
- Python 3.11+ with `httpx`, `sqlite3`
- DrissionPage (`pip install DrissionPage`) — run with `python -s` to avoid Hermes venv path collisions
- Chrome installed at `C:\Program Files\Google\Chrome\Application\chrome.exe`
- gw46 gateway DB at `~/Documents/grok46gw/grok46_accounts.db`
## Script Location
`C:\Users\User\tmp\grok_register\grok-register\sso2oauth.py`
## Flow Detail
### Step 1: Start Device Code Flow
```
POST https://auth.x.ai/oauth2/device/code
Content-Type: application/x-www-form-urlencoded
client_id=b1a00492-073a-47ea-816f-4c329264a828&
scope=openid+profile+email+offline_access+grok-cli:access+api:access
Response:
{
"device_code": "...",
"user_code": "ABCD-1234",
"verification_uri": "https://accounts.x.ai/oauth2/device",
"verification_uri_complete": "https://accounts.x.ai/oauth2/device?user_code=ABCD-1234",
"interval": 5,
"expires_in": 600
}
```
### Step 2: Authorize Device with SSO (DrissionPage)
```python
from DrissionPage import ChromiumPage
page = ChromiumPage()
page.get("https://accounts.x.ai/sign-in")
page.run_js(f"""
document.cookie = "sso={sso_token}; domain=.accounts.x.ai; path=/; Secure;";
document.cookie = "sso={sso_token}; domain=.x.ai; path=/; Secure;";
""")
page.get(verification_uri_complete) # includes user_code in URL
# Click "Продолжить" (Continue) to submit the code
page.ele("tag:button@@text()=Продолжить").click()
# Wait for authorization page
# Click "Authorize" / "Разрешить"
page.ele("tag:button@@text()=Разрешить").click()
```
### Step 3: Poll for Token
```
POST https://auth.x.ai/oauth2/token
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:device_code&
device_code={device_code}&
client_id=b1a00492-073a-47ea-816f-4c329264a828
Response (200):
{
"access_token": "eyJ0eX...",
"refresh_token": "m9Vzs...",
"expires_in": 3600,
"scope": "openid profile email offline_access grok-cli:access api:access",
"id_token": "eyJ0eX..."
}
```
### Step 4: Store in SQLite
```sql
INSERT INTO accounts (email, access_token, refresh_token, expires_at, scope)
VALUES (?, ?, ?, ?, ?);
```
## Token Validation
The OAuth token JWT contains:
- `iss: https://auth.x.ai`
- `aud: b1a00492-073a-47ea-816f-4c329264a828` (correct client_id)
- `scope: openid profile email offline_access grok-cli:access api:access`
- `principal_type: User`
- `exp: <timestamp>` (6 hours from issue)
## Known Limitations
### 1. DrissionPage Concurrency (PageDisconnectedError)
DrissionPage [REDACTED-IP]b14 crashes with `PageDisconnectedError` (与页面的连接已断开) when multiple `ChromiumPage` instances are created in the same process. The background CDP event handler thread raises an unhandled exception. Cause is a shared CDP connection state across instances.
**Fix:** Force sequential processing (`--concurrent 1`). Split large batches into chunks of 10-15 with process restarts between chunks.
### 2. No API Credits
OAuth tokens are valid (authenticate correctly) but accounts have no API credits. All API calls return:
```json
{"code":"personal-team-blocked:spending-limit",
"error":"You have run out of credits or need a Grok subscription."}
```
The gw46 gateway shows `credentials: N` in health but every request fails with 402.
### 3. gw46 KeyPool Refresh
The gateway reads the DB only during startup. External DB writes (via `sso2oauth.py`) are invisible until restart:
```bash
taskkill /F /PID <PID>
cd ~/Documents/grok46gw && python gw46.py
```
## Session Performance (2026-08-13)
| Metric | Value |
|--------|-------|
| Accounts created | 171 |
| SSO → OAuth converted | 74 |
| Sequential time per account | ~10-15s |
| Total conversion time | ~12 min |
| Batch size before crash | ~10-15 |
| DrissionPage chunks | 5 (restart between) |
| Valid API tokens | 0 (all 402) |