(
pkce: PkceCodes,
state: string,
nonce: string,
options: XaiAuthPluginOptions = {},
)
| 116 | } |
| 117 | |
| 118 | export function buildAuthorizeUrl( |
| 119 | pkce: PkceCodes, |
| 120 | state: string, |
| 121 | nonce: string, |
| 122 | options: XaiAuthPluginOptions = {}, |
| 123 | ): string { |
| 124 | // `plan=generic` opts the consent screen into xAI's generic OAuth plan tier; |
| 125 | // without it, accounts.x.ai rejects loopback OAuth from non-allowlisted |
| 126 | // clients. `referrer=opencode` lets xAI attribute opencode-originated |
| 127 | // logins in their OAuth server logs (best-effort attribution while we |
| 128 | // continue to reuse the Grok-CLI client_id). |
| 129 | const params = new URLSearchParams({ |
| 130 | response_type: "code", |
| 131 | client_id: CLIENT_ID, |
| 132 | redirect_uri: REDIRECT_URI, |
| 133 | scope: SCOPE, |
| 134 | code_challenge: pkce.challenge, |
| 135 | code_challenge_method: "S256", |
| 136 | state, |
| 137 | nonce, |
| 138 | plan: "generic", |
| 139 | referrer: "opencode", |
| 140 | }) |
| 141 | return `${options.authorizeUrl ?? AUTHORIZE_URL}?${params.toString()}` |
| 142 | } |
| 143 | |
| 144 | async function exchangeCodeForTokens( |
| 145 | code: string, |
no outgoing calls
no test coverage detected