(account: string, code: string, pkce: PkceCodes)
| 103 | } |
| 104 | |
| 105 | async function exchangeCodeForToken(account: string, code: string, pkce: PkceCodes) { |
| 106 | const response = await fetch(`https://${account}.snowflakecomputing.com/oauth/token-request`, { |
| 107 | method: "POST", |
| 108 | headers: { |
| 109 | ...authHeaders(), |
| 110 | Authorization: authBasicHeader(), |
| 111 | }, |
| 112 | body: new URLSearchParams({ |
| 113 | grant_type: "authorization_code", |
| 114 | code, |
| 115 | redirect_uri: callbackUrl(), |
| 116 | client_id: OAUTH_CLIENT_ID, |
| 117 | code_verifier: pkce.verifier, |
| 118 | }).toString(), |
| 119 | }) |
| 120 | |
| 121 | if (!response.ok) { |
| 122 | const detail = await response.text().catch(() => "") |
| 123 | throw new Error(`Snowflake token exchange failed (${response.status})${detail ? `: ${detail}` : ""}`) |
| 124 | } |
| 125 | |
| 126 | const token = (await response.json()) as TokenResponse |
| 127 | if (!token.access_token) throw new Error("Snowflake token response did not include access_token") |
| 128 | if (!token.refresh_token) { |
| 129 | throw new Error( |
| 130 | "Snowflake token response did not include refresh_token. Ensure integration issues refresh tokens and scope includes refresh_token.", |
| 131 | ) |
| 132 | } |
| 133 | return token |
| 134 | } |
| 135 | |
| 136 | async function refreshAccessToken(account: string, refreshToken: string) { |
| 137 | const response = await fetch(`https://${account}.snowflakecomputing.com/oauth/token-request`, { |
no test coverage detected