# ATXP Auth Architecture ## Account Types ### 1. Main Account (User) - Registered via Privy OIDC (email/SIWE on accounts.atxp.ai) - Has full JWT session - Can use: CLI, MCP Proxy, Abundance, all ATXP services - Balance: real $ (can be funded via Stripe/crypto) - Example: `atxp_acct_nSO1rOHTKXeymKun41GSD` ([REDACTED-NAME]@gmail.com) ### 2. Agent Account (Sub-Account) - Registered via `npx atxp agent register` CLI command - No JWT session — only OAuth client credentials + connection_token - **CANNOT use**: CLI commands (`/sign did not return jwt`), Abundance - **CAN use**: MCP servers directly via curl (confirmed 2026-06-24, all 43 agent accounts) - Balance: $0 IOU (billing transparent — passes through to parent account) - Example: `atxp_acct_t6eRB3plKp3pRuRAJHhSF` (atxp_acct_*@atxp.email) ## Auth Protocols ### MCP Proxy - URL format: `https://accounts.atxp.ai?connection_token=TOKEN&account_id=ID&server=SERVER` - Token in URL query param (not Authorization header) - Works ONLY with Main Account tokens - Content-Type: application/json - Accept: application/json, text/event-stream - Response: SSE `data: {...}` or plain JSON ### Direct MCP Server Access (via curl) **CRITICAL**: Requires `Accept: application/json, text/event-stream` header. Without it, returns "Not Acceptable" error. ```bash curl -s -X POST "https://email.mcp.atxp.ai/" \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -H "Authorization: Bearer https://accounts.atxp.ai?connection_token=TOKEN&account_id=ACCOUNT_ID" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"email_check_inbox","arguments":{}}}' ``` Works with BOTH main accounts ($10+) and agent accounts ($0 IOU). Response format: SSE `event: message\ndata: {...}` ### Privy OIDC - Client ID: `client-WY6L6ApVtkaEUHas1qqZ4fFKtQuUF67ghGYyd82oa5PTw` - App ID: `cma1jnfkk01mml20n6fyvsmll` - Used by accounts.atxp.ai and auth.atxp.ai - Supports: email magic link, Google OAuth, SIWE (web3) ### OAuth Cache Structure File: `~/.atxp/oauth-cache.json` ```json { "clientCredentials": { "https://auth.atxp.ai": { "clientId": "[REDACTED-KEY]", "clientSecret": "fd73c7065abddf...", "redirectUri": "http://localhost:3000/unused-dummy-atxp-callback" } }, "pkceValues": { "atxp:{account_id}:{random_state}": { "url": "https://{service}.mcp.atxp.ai/", "codeVerifier": "...", "codeChallenge": "...", "resourceUrl": "https://{service}.mcp.atxp.ai/" } }, "accessTokens": { "atxp:{account_id}:{resource_url}": { "resourceUrl": "https://{service}.mcp.atxp.ai/", "accessToken": "...", "refreshToken": "...", "expiresAt": 1782261829702 } } } ``` ### CLI Auth Config File: `~/.atxp/config` ``` ATXP_CONNECTION=https://accounts.atxp.ai?connection_token=TOKEN ``` Note: config only stores connection_token, NOT account_id. For MCP Proxy you need both. ## auth.atxp.ai API - Root `GET https://auth.atxp.ai/` — returns `{"error":"unauthorized"}` (expects Bearer token) - `GET /authorize` — OIDC authorize endpoint - Requires: client_id, redirect_uri, response_type=code, scope, state, code_challenge, code_challenge_method - Without proper PKCE params: `{"error":"invalid_request","error_description":"Missing required parameter: client_id"}` - The auth.atxp.ai server runs on Render (x-render-origin-server header) - CSP includes Privy, WalletConnect, Solana RPC, Stripe, PostHog ## Registration Flow (`npx atxp agent register`) 1. CLI sends POST to accounts.atxp.ai with OAuth2 client credentials 2. Server creates agent account linked to parent's billing 3. Returns: connection_token + account_id + wallet address 4. Token format: short alphanumeric (e.g., QlzvgHTUcT3qZIncmCgjX) 5. Account ID format: `atxp_acct_*` (24 chars) 6. Wallet: 0x... Ethereum address on Base network 7. Email: auto-generated `atxp_acct_*@atxp.email` (no inbox access) ## MCP Server List (9 servers, 68 tools) | Server | Tools | Type | |--------|:-----:|------| | image.mcp.atxp.ai | 3 | Image gen | | search.mcp.atxp.ai | 1 | Web search | | music.mcp.atxp.ai | 2 | Music gen | | video.mcp.atxp.ai | 2 | Video gen | | x-live-search.mcp.atxp.ai | 3 | X/Twitter | | email.mcp.atxp.ai | 10 | Email | | phone.mcp.atxp.ai | 12 | SMS/voice | | paas.mcp.atxp.ai | 31 | PaaS | | git.mcp.atxp.ai | 4 | Git | ## MCP Pricing Model (per tool call) | Tool | Cost | Notes | |------|------|-------| | email_check_inbox | FREE | | | email_get_message | FREE | | | email_search | FREE | | | email_mark_as_read | FREE | | | email_delete | FREE | | | email_get_attachment | FREE | | | email_send_email | $0.01 | Requires payment approval | | email_reply | $0.01 | Requires payment approval | | email_claim_username | $1.00 | | | phone_check_sms | FREE | | | phone_get_sms | FREE | | | phone_mark_read | FREE | | | phone_get_attachment | FREE | | | phone_check_calls | FREE | | | phone_get_call | FREE | | | phone_search | FREE | | | phone_register | $2.00 | Requires payment approval | | phone_send_sms | $0.05 | Requires payment approval | | phone_call | $0.10 | Requires payment approval | | image_create_image | $0.201 | Requires payment approval | | search_search | $0.01 | Requires payment approval | **Payment approval flow**: When a paid tool is called, returns error with `paymentRequestUrl`. User must visit URL and approve payment (via ATXP internal transfer, crypto, or Stripe). After approval, tool call succeeds.