reformatted to PAT from oauth

This commit is contained in:
aadamgough
2025-12-03 23:46:55 -08:00
parent 342c4a2081
commit 89ba330846
20 changed files with 53 additions and 564 deletions

View File

@@ -69,7 +69,6 @@ export async function getOAuthToken(userId: string, providerId: string): Promise
accessTokenExpiresAt: account.accessTokenExpiresAt,
accountId: account.accountId,
providerId: account.providerId,
password: account.password, // Include password field for Snowflake OAuth credentials
})
.from(account)
.where(and(eq(account.userId, userId), eq(account.providerId, providerId)))
@@ -96,25 +95,8 @@ export async function getOAuthToken(userId: string, providerId: string): Promise
)
try {
// Extract account URL and OAuth credentials for Snowflake
let metadata: { accountUrl?: string; clientId?: string; clientSecret?: string } | undefined
if (providerId === 'snowflake' && credential.accountId) {
metadata = { accountUrl: credential.accountId }
// Extract clientId and clientSecret from the password field (stored as JSON)
if (credential.password) {
try {
const oauthCredentials = JSON.parse(credential.password)
metadata.clientId = oauthCredentials.clientId
metadata.clientSecret = oauthCredentials.clientSecret
} catch (e) {
logger.error('Failed to parse Snowflake OAuth credentials', { error: e })
}
}
}
// Use the existing refreshOAuthToken function
const refreshResult = await refreshOAuthToken(providerId, credential.refreshToken!, metadata)
const refreshResult = await refreshOAuthToken(providerId, credential.refreshToken!)
if (!refreshResult) {
logger.error(`Failed to refresh token for user ${userId}, provider ${providerId}`, {
@@ -197,27 +179,9 @@ export async function refreshAccessTokenIfNeeded(
if (shouldRefresh) {
logger.info(`[${requestId}] Token expired, attempting to refresh for credential`)
try {
// Extract account URL and OAuth credentials for Snowflake
let metadata: { accountUrl?: string; clientId?: string; clientSecret?: string } | undefined
if (credential.providerId === 'snowflake' && credential.accountId) {
metadata = { accountUrl: credential.accountId }
// Extract clientId and clientSecret from the password field (stored as JSON)
if (credential.password) {
try {
const oauthCredentials = JSON.parse(credential.password)
metadata.clientId = oauthCredentials.clientId
metadata.clientSecret = oauthCredentials.clientSecret
} catch (e) {
logger.error('Failed to parse Snowflake OAuth credentials', { error: e })
}
}
}
const refreshedToken = await refreshOAuthToken(
credential.providerId,
credential.refreshToken!,
metadata
credential.refreshToken!
)
if (!refreshedToken) {
@@ -289,28 +253,7 @@ export async function refreshTokenIfNeeded(
}
try {
// Extract account URL and OAuth credentials for Snowflake
let metadata: { accountUrl?: string; clientId?: string; clientSecret?: string } | undefined
if (credential.providerId === 'snowflake' && credential.accountId) {
metadata = { accountUrl: credential.accountId }
// Extract clientId and clientSecret from the password field (stored as JSON)
if (credential.password) {
try {
const oauthCredentials = JSON.parse(credential.password)
metadata.clientId = oauthCredentials.clientId
metadata.clientSecret = oauthCredentials.clientSecret
} catch (e) {
logger.error('Failed to parse Snowflake OAuth credentials', { error: e })
}
}
}
const refreshResult = await refreshOAuthToken(
credential.providerId,
credential.refreshToken!,
metadata
)
const refreshResult = await refreshOAuthToken(credential.providerId, credential.refreshToken!)
if (!refreshResult) {
logger.error(`[${requestId}] Failed to refresh token for credential`)

View File

@@ -1,92 +0,0 @@
import { type NextRequest, NextResponse } from 'next/server'
import { getSession } from '@/lib/auth'
import { createLogger } from '@/lib/logs/console/logger'
import { generateCodeChallenge, generateCodeVerifier } from '@/lib/oauth/pkce'
import { getBaseUrl } from '@/lib/urls/utils'
const logger = createLogger('SnowflakeAuthorize')
export const dynamic = 'force-dynamic'
/**
* Initiates Snowflake OAuth flow
* Expects credentials to be posted in the request body (accountUrl, clientId, clientSecret)
*/
export async function POST(request: NextRequest) {
try {
const session = await getSession()
if (!session?.user?.id) {
logger.warn('Unauthorized Snowflake OAuth attempt')
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}
const body = await request.json()
const { accountUrl, clientId, clientSecret } = body
if (!accountUrl || !clientId || !clientSecret) {
logger.error('Missing required Snowflake OAuth parameters', {
hasAccountUrl: !!accountUrl,
hasClientId: !!clientId,
hasClientSecret: !!clientSecret,
})
return NextResponse.json(
{ error: 'accountUrl, clientId, and clientSecret are required' },
{ status: 400 }
)
}
// Parse and clean the account URL
let cleanAccountUrl = accountUrl.replace(/^https?:\/\//, '')
cleanAccountUrl = cleanAccountUrl.replace(/\/$/, '')
if (!cleanAccountUrl.includes('snowflakecomputing.com')) {
cleanAccountUrl = `${cleanAccountUrl}.snowflakecomputing.com`
}
const baseUrl = getBaseUrl()
const redirectUri = `${baseUrl}/api/auth/snowflake/callback`
// Generate PKCE values
const codeVerifier = generateCodeVerifier()
const codeChallenge = await generateCodeChallenge(codeVerifier)
// Store user-provided credentials in the state (will be used in callback)
const state = Buffer.from(
JSON.stringify({
userId: session.user.id,
accountUrl: cleanAccountUrl,
clientId,
clientSecret,
timestamp: Date.now(),
codeVerifier,
})
).toString('base64url')
// Construct Snowflake-specific authorization URL
const authUrl = new URL(`https://${cleanAccountUrl}/oauth/authorize`)
authUrl.searchParams.set('client_id', clientId)
authUrl.searchParams.set('response_type', 'code')
authUrl.searchParams.set('redirect_uri', redirectUri)
// Add scope parameter to specify a safe role (not ACCOUNTADMIN or SECURITYADMIN)
authUrl.searchParams.set('scope', 'refresh_token session:role:PUBLIC')
authUrl.searchParams.set('state', state)
// Add PKCE parameters for security and compatibility with OAUTH_ENFORCE_PKCE
authUrl.searchParams.set('code_challenge', codeChallenge)
authUrl.searchParams.set('code_challenge_method', 'S256')
logger.info('Initiating Snowflake OAuth flow with user-provided credentials (PKCE)', {
userId: session.user.id,
accountUrl: cleanAccountUrl,
hasClientId: !!clientId,
hasClientSecret: !!clientSecret,
redirectUri,
hasPkce: true,
})
return NextResponse.json({
authUrl: authUrl.toString(),
})
} catch (error) {
logger.error('Error initiating Snowflake authorization:', error)
return NextResponse.json({ error: 'Internal server error' }, { status: 500 })
}
}

View File

@@ -1,218 +0,0 @@
import { and, eq } from 'drizzle-orm'
import { type NextRequest, NextResponse } from 'next/server'
import { getSession } from '@/lib/auth'
import { createLogger } from '@/lib/logs/console/logger'
import { getBaseUrl } from '@/lib/urls/utils'
import { db } from '@/../../packages/db'
import { account } from '@/../../packages/db/schema'
const logger = createLogger('SnowflakeCallback')
export const dynamic = 'force-dynamic'
/**
* Handles Snowflake OAuth callback
*/
export async function GET(request: NextRequest) {
try {
const session = await getSession()
if (!session?.user?.id) {
logger.warn('Unauthorized Snowflake OAuth callback')
return NextResponse.redirect(`${getBaseUrl()}/workspace?error=unauthorized`)
}
const { searchParams } = new URL(request.url)
const code = searchParams.get('code')
const state = searchParams.get('state')
const error = searchParams.get('error')
const errorDescription = searchParams.get('error_description')
// Handle OAuth errors
if (error) {
logger.error('Snowflake OAuth error', { error, errorDescription })
return NextResponse.redirect(
`${getBaseUrl()}/workspace?error=snowflake_${error}&description=${encodeURIComponent(errorDescription || '')}`
)
}
if (!code || !state) {
logger.error('Missing code or state in callback')
return NextResponse.redirect(`${getBaseUrl()}/workspace?error=snowflake_invalid_callback`)
}
// Decode state to get account URL, credentials, and code verifier
let stateData: {
userId: string
accountUrl: string
clientId: string
clientSecret: string
timestamp: number
codeVerifier: string
}
try {
stateData = JSON.parse(Buffer.from(state, 'base64url').toString())
logger.info('Decoded state successfully', {
userId: stateData.userId,
accountUrl: stateData.accountUrl,
hasClientId: !!stateData.clientId,
hasClientSecret: !!stateData.clientSecret,
age: Date.now() - stateData.timestamp,
hasCodeVerifier: !!stateData.codeVerifier,
})
} catch (e) {
logger.error('Invalid state parameter', { error: e, state })
return NextResponse.redirect(`${getBaseUrl()}/workspace?error=snowflake_invalid_state`)
}
// Verify the user matches
if (stateData.userId !== session.user.id) {
logger.error('User ID mismatch in state', {
stateUserId: stateData.userId,
sessionUserId: session.user.id,
})
return NextResponse.redirect(`${getBaseUrl()}/workspace?error=snowflake_user_mismatch`)
}
// Verify state is not too old (15 minutes)
if (Date.now() - stateData.timestamp > 15 * 60 * 1000) {
logger.error('State expired', {
age: Date.now() - stateData.timestamp,
})
return NextResponse.redirect(`${getBaseUrl()}/workspace?error=snowflake_state_expired`)
}
// Use user-provided credentials from state
const clientId = stateData.clientId
const clientSecret = stateData.clientSecret
if (!clientId || !clientSecret) {
logger.error('Missing client credentials in state')
return NextResponse.redirect(`${getBaseUrl()}/workspace?error=snowflake_missing_credentials`)
}
// Exchange authorization code for tokens
const tokenUrl = `https://${stateData.accountUrl}/oauth/token-request`
const redirectUri = `${getBaseUrl()}/api/auth/snowflake/callback`
const tokenParams = new URLSearchParams({
grant_type: 'authorization_code',
code,
redirect_uri: redirectUri,
client_id: clientId,
client_secret: clientSecret,
code_verifier: stateData.codeVerifier,
})
logger.info('Exchanging authorization code for tokens (with PKCE)', {
tokenUrl,
redirectUri,
clientId,
hasCode: !!code,
hasClientSecret: !!clientSecret,
hasCodeVerifier: !!stateData.codeVerifier,
paramsLength: tokenParams.toString().length,
})
const tokenResponse = await fetch(tokenUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: tokenParams.toString(),
})
if (!tokenResponse.ok) {
const errorText = await tokenResponse.text()
logger.error('Failed to exchange code for token', {
status: tokenResponse.status,
statusText: tokenResponse.statusText,
error: errorText,
tokenUrl,
redirectUri,
})
// Try to parse error as JSON for better diagnostics
try {
const errorJson = JSON.parse(errorText)
logger.error('Snowflake error details:', errorJson)
} catch (e) {
logger.error('Error text (not JSON):', errorText)
}
return NextResponse.redirect(
`${getBaseUrl()}/workspace?error=snowflake_token_exchange_failed&details=${encodeURIComponent(errorText)}`
)
}
const tokens = await tokenResponse.json()
logger.info('Token exchange for Snowflake successful', {
hasAccessToken: !!tokens.access_token,
hasRefreshToken: !!tokens.refresh_token,
expiresIn: tokens.expires_in,
scope: tokens.scope,
})
if (!tokens.access_token) {
logger.error('No access token in response', { tokens })
return NextResponse.redirect(`${getBaseUrl()}/workspace?error=snowflake_no_access_token`)
}
// Store the account and tokens in the database
const existing = await db.query.account.findFirst({
where: and(eq(account.userId, session.user.id), eq(account.providerId, 'snowflake')),
})
const now = new Date()
const expiresAt = tokens.expires_in
? new Date(now.getTime() + tokens.expires_in * 1000)
: new Date(now.getTime() + 10 * 60 * 1000) // Default 10 minutes
// Store user-provided OAuth credentials securely
// We use the password field to store a JSON object with clientId and clientSecret
// and idToken to store the accountUrl for easier retrieval
const oauthCredentials = JSON.stringify({
clientId: stateData.clientId,
clientSecret: stateData.clientSecret,
})
const accountData = {
userId: session.user.id,
providerId: 'snowflake',
accountId: stateData.accountUrl, // Store the Snowflake account URL here
accessToken: tokens.access_token,
refreshToken: tokens.refresh_token || null,
idToken: stateData.accountUrl, // Store accountUrl for easier access
password: oauthCredentials, // Store clientId and clientSecret as JSON
accessTokenExpiresAt: expiresAt,
scope: tokens.scope || null,
updatedAt: now,
}
if (existing) {
await db.update(account).set(accountData).where(eq(account.id, existing.id))
logger.info('Updated existing Snowflake account', {
userId: session.user.id,
accountUrl: stateData.accountUrl,
})
} else {
await db.insert(account).values({
...accountData,
id: `snowflake_${session.user.id}_${Date.now()}`,
createdAt: now,
})
logger.info('Created new Snowflake account', {
userId: session.user.id,
accountUrl: stateData.accountUrl,
})
}
return NextResponse.redirect(`${getBaseUrl()}/workspace?snowflake_connected=true`)
} catch (error) {
logger.error('Error in Snowflake callback:', error)
return NextResponse.redirect(`${getBaseUrl()}/workspace?error=snowflake_callback_failed`)
}
}

View File

@@ -226,9 +226,6 @@ const SCOPE_DESCRIPTIONS: Record<string, string> = {
'webhooks:read': 'Read your Pipedrive webhooks',
'webhooks:full': 'Full access to manage your Pipedrive webhooks',
w_member_social: 'Access your LinkedIn profile',
// Box scopes
root_readwrite: 'Read and write all files and folders in your Box account',
root_readonly: 'Read all files and folders in your Box account',
// Shopify scopes (write_* implicitly includes read access)
write_products: 'Read and manage your Shopify products',
write_orders: 'Read and manage your Shopify orders',
@@ -273,13 +270,6 @@ export function OAuthRequiredModal({
serviceId,
newScopes = [],
}: OAuthRequiredModalProps) {
const [snowflakeAccountUrl, setSnowflakeAccountUrl] = useState('')
const [snowflakeClientId, setSnowflakeClientId] = useState('')
const [snowflakeClientSecret, setSnowflakeClientSecret] = useState('')
const [accountUrlError, setAccountUrlError] = useState('')
const [clientIdError, setClientIdError] = useState('')
const [clientSecretError, setClientSecretError] = useState('')
const effectiveServiceId = serviceId || getServiceIdFromScopes(provider, requiredScopes)
const { baseProvider } = parseProvider(provider)
const baseProviderConfig = OAUTH_PROVIDERS[baseProvider]
@@ -310,67 +300,6 @@ export function OAuthRequiredModal({
try {
const providerId = getProviderIdFromServiceId(effectiveServiceId)
// Special handling for Snowflake - requires account URL, client ID, and client secret
if (providerId === 'snowflake') {
let hasError = false
if (!snowflakeAccountUrl.trim()) {
setAccountUrlError('Account URL is required')
hasError = true
}
if (!snowflakeClientId.trim()) {
setClientIdError('Client ID is required')
hasError = true
}
if (!snowflakeClientSecret.trim()) {
setClientSecretError('Client Secret is required')
hasError = true
}
if (hasError) {
return
}
onClose()
logger.info('Initiating Snowflake OAuth with user credentials:', {
accountUrl: snowflakeAccountUrl,
hasClientId: !!snowflakeClientId,
hasClientSecret: !!snowflakeClientSecret,
})
// Call the authorize endpoint with user credentials
try {
const response = await fetch('/api/auth/snowflake/authorize', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
accountUrl: snowflakeAccountUrl,
clientId: snowflakeClientId,
clientSecret: snowflakeClientSecret,
}),
})
if (!response.ok) {
throw new Error('Failed to initiate Snowflake OAuth')
}
const data = await response.json()
// Redirect to Snowflake authorization page
window.location.href = data.authUrl
} catch (error) {
logger.error('Error initiating Snowflake OAuth:', error)
// TODO: Show error to user
}
return
}
onClose()
logger.info('Linking OAuth2:', {
@@ -401,7 +330,7 @@ export function OAuthRequiredModal({
return (
<Modal open={isOpen} onOpenChange={(open) => !open && onClose()}>
<ModalContent className='w-[460px]'>
<ModalContent className='w-[460px]'>
<ModalHeader>Connect {providerName}</ModalHeader>
<ModalBody>
<div className='flex flex-col gap-[16px]'>

View File

@@ -7,7 +7,7 @@ export const SnowflakeBlock: BlockConfig<SnowflakeResponse> = {
type: 'snowflake',
name: 'Snowflake',
description: 'Execute queries on Snowflake data warehouse',
authMode: AuthMode.OAuth,
authMode: AuthMode.ApiKey,
longDescription:
'Integrate Snowflake into your workflow. Execute SQL queries, insert, update, and delete rows, list databases, schemas, and tables, and describe table structures in your Snowflake data warehouse.',
docsLink: 'https://docs.sim.ai/tools/snowflake',
@@ -36,6 +36,7 @@ export const SnowflakeBlock: BlockConfig<SnowflakeResponse> = {
value: () => 'execute_query',
},
{
<<<<<<< HEAD
id: 'credential',
title: 'Snowflake Account',
type: 'oauth-input',
@@ -45,10 +46,22 @@ export const SnowflakeBlock: BlockConfig<SnowflakeResponse> = {
required: true,
},
{
=======
>>>>>>> 8de761181 (reformatted to PAT from oauth)
id: 'accountUrl',
title: 'Account URL',
type: 'short-input',
placeholder: 'your-account.snowflakecomputing.com',
description: 'Your Snowflake account URL (e.g., xy12345.us-east-1.snowflakecomputing.com)',
required: true,
},
{
id: 'accessToken',
title: 'Personal Access Token',
type: 'short-input',
placeholder: 'Enter your Snowflake PAT',
description: 'Generate a PAT in Snowflake Snowsight',
password: true,
required: true,
},
{
@@ -376,11 +389,11 @@ Return ONLY the SQL query - no explanations, no markdown code blocks, no extra t
}
},
params: (params) => {
const { credential, operation, ...rest } = params
const { operation, ...rest } = params
// Build base params
// Build base params - use PAT directly as accessToken
const baseParams: Record<string, any> = {
credential,
accessToken: params.accessToken,
accountUrl: params.accountUrl,
}
@@ -559,11 +572,14 @@ Return ONLY the SQL query - no explanations, no markdown code blocks, no extra t
},
inputs: {
operation: { type: 'string', description: 'Operation to perform' },
credential: { type: 'string', description: 'Snowflake OAuth credential' },
accountUrl: {
type: 'string',
description: 'Snowflake account URL (e.g., xy12345.us-east-1.snowflakecomputing.com)',
},
accessToken: {
type: 'string',
description: 'Snowflake Personal Access Token (PAT)',
},
warehouse: { type: 'string', description: 'Warehouse name' },
role: { type: 'string', description: 'Role name' },
query: { type: 'string', description: 'SQL query to execute' },

View File

@@ -221,8 +221,6 @@ export const env = createEnv({
REDDIT_CLIENT_SECRET: z.string().optional(), // Reddit OAuth client secret
WEBFLOW_CLIENT_ID: z.string().optional(), // Webflow OAuth client ID
WEBFLOW_CLIENT_SECRET: z.string().optional(), // Webflow OAuth client secret
SNOWFLAKE_CLIENT_ID: z.string().optional(), // Snowflake OAuth client ID
SNOWFLAKE_CLIENT_SECRET: z.string().optional(), // Snowflake OAuth client secret
TRELLO_API_KEY: z.string().optional(), // Trello API Key
LINKEDIN_CLIENT_ID: z.string().optional(), // LinkedIn OAuth client ID
LINKEDIN_CLIENT_SECRET: z.string().optional(), // LinkedIn OAuth client secret

View File

@@ -30,7 +30,6 @@ import {
SalesforceIcon,
ShopifyIcon,
SlackIcon,
SnowflakeIcon,
TrelloIcon,
WealthboxIcon,
WebflowIcon,
@@ -111,6 +110,7 @@ export type OAuthService =
| 'zoom'
| 'wordpress'
| 'snowflake'
export interface OAuthProviderConfig {
id: OAuthProvider
name: string
@@ -1529,44 +1529,17 @@ function buildAuthRequest(
* This is a server-side utility function to refresh OAuth tokens
* @param providerId The provider ID (e.g., 'google-drive')
* @param refreshToken The refresh token to use
* @param metadata Optional metadata (e.g., accountUrl, clientId, clientSecret for Snowflake)
* @returns Object containing the new access token and expiration time in seconds, or null if refresh failed
*/
export async function refreshOAuthToken(
providerId: string,
refreshToken: string,
metadata?: { accountUrl?: string; clientId?: string; clientSecret?: string }
refreshToken: string
): Promise<{ accessToken: string; expiresIn: number; refreshToken: string } | null> {
try {
// Get the provider from the providerId (e.g., 'google-drive' -> 'google')
const provider = providerId.split('-')[0]
let config: ProviderAuthConfig
if (provider === 'snowflake' && metadata?.clientId && metadata?.clientSecret) {
config = {
tokenEndpoint: `https://${metadata.accountUrl}/oauth/token-request`,
clientId: metadata.clientId,
clientSecret: metadata.clientSecret,
useBasicAuth: false,
supportsRefreshTokenRotation: true,
}
logger.info('Using user-provided Snowflake OAuth credentials for token refresh', {
accountUrl: metadata.accountUrl,
hasClientId: !!metadata.clientId,
hasClientSecret: !!metadata.clientSecret,
})
} else {
config = getProviderAuthConfig(provider)
// For Snowflake without user credentials, use the account-specific token endpoint
if (provider === 'snowflake' && metadata?.accountUrl) {
config.tokenEndpoint = `https://${metadata.accountUrl}/oauth/token-request`
logger.info('Using Snowflake account-specific token endpoint', {
accountUrl: metadata.accountUrl,
})
}
}
const config = getProviderAuthConfig(provider)
// Build authentication request
const { headers, bodyParams } = buildAuthRequest(config, refreshToken)

View File

@@ -41,17 +41,12 @@ export const snowflakeDeleteRowsTool: ToolConfig<
description: 'Delete rows from a Snowflake table',
version: '1.0.0',
oauth: {
required: true,
provider: 'snowflake',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Snowflake',
description: 'Snowflake Personal Access Token (PAT)',
},
accountUrl: {
type: 'string',
@@ -113,7 +108,7 @@ export const snowflakeDeleteRowsTool: ToolConfig<
headers: (params: SnowflakeDeleteRowsParams) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
'X-Snowflake-Authorization-Token-Type': 'OAUTH',
'X-Snowflake-Authorization-Token-Type': 'PROGRAMMATIC_ACCESS_TOKEN',
}),
body: (params: SnowflakeDeleteRowsParams) => {
// Build DELETE SQL

View File

@@ -17,17 +17,12 @@ export const snowflakeDescribeTableTool: ToolConfig<
description: 'Get the schema and structure of a Snowflake table',
version: '1.0.0',
oauth: {
required: true,
provider: 'snowflake',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Snowflake',
description: 'Snowflake Personal Access Token (PAT)',
},
accountUrl: {
type: 'string',
@@ -76,7 +71,7 @@ export const snowflakeDescribeTableTool: ToolConfig<
headers: (params: SnowflakeDescribeTableParams) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
'X-Snowflake-Authorization-Token-Type': 'OAUTH',
'X-Snowflake-Authorization-Token-Type': 'PROGRAMMATIC_ACCESS_TOKEN',
}),
body: (params: SnowflakeDescribeTableParams) => {
const sanitizedDatabase = sanitizeIdentifier(params.database)

View File

@@ -21,17 +21,12 @@ export const snowflakeExecuteQueryTool: ToolConfig<
description: 'Execute a SQL query on your Snowflake data warehouse',
version: '1.0.0',
oauth: {
required: true,
provider: 'snowflake',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Snowflake',
description: 'Snowflake Personal Access Token (PAT)',
},
accountUrl: {
type: 'string',
@@ -86,7 +81,7 @@ export const snowflakeExecuteQueryTool: ToolConfig<
headers: (params: SnowflakeExecuteQueryParams) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
'X-Snowflake-Authorization-Token-Type': 'OAUTH',
'X-Snowflake-Authorization-Token-Type': 'PROGRAMMATIC_ACCESS_TOKEN',
}),
body: (params: SnowflakeExecuteQueryParams) => {
const requestBody: Record<string, any> = {

View File

@@ -56,17 +56,12 @@ export const snowflakeInsertRowsTool: ToolConfig<
description: 'Insert rows into a Snowflake table',
version: '1.0.0',
oauth: {
required: true,
provider: 'snowflake',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Snowflake',
description: 'Snowflake Personal Access Token (PAT)',
},
accountUrl: {
type: 'string',
@@ -134,7 +129,7 @@ export const snowflakeInsertRowsTool: ToolConfig<
headers: (params: SnowflakeInsertRowsParams) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
'X-Snowflake-Authorization-Token-Type': 'OAUTH',
'X-Snowflake-Authorization-Token-Type': 'PROGRAMMATIC_ACCESS_TOKEN',
}),
body: (params: SnowflakeInsertRowsParams) => {
// Validate inputs

View File

@@ -17,17 +17,12 @@ export const snowflakeListDatabasesTool: ToolConfig<
description: 'List all databases in your Snowflake account',
version: '1.0.0',
oauth: {
required: true,
provider: 'snowflake',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Snowflake',
description: 'Snowflake Personal Access Token (PAT)',
},
accountUrl: {
type: 'string',
@@ -58,7 +53,7 @@ export const snowflakeListDatabasesTool: ToolConfig<
headers: (params: SnowflakeListDatabasesParams) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
'X-Snowflake-Authorization-Token-Type': 'OAUTH',
'X-Snowflake-Authorization-Token-Type': 'PROGRAMMATIC_ACCESS_TOKEN',
}),
body: (params: SnowflakeListDatabasesParams) => {
const requestBody: Record<string, any> = {

View File

@@ -17,17 +17,12 @@ export const snowflakeListFileFormatsTool: ToolConfig<
description: 'List all file formats in a Snowflake schema',
version: '1.0.0',
oauth: {
required: true,
provider: 'snowflake',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Snowflake',
description: 'Snowflake Personal Access Token (PAT)',
},
accountUrl: {
type: 'string',
@@ -70,7 +65,7 @@ export const snowflakeListFileFormatsTool: ToolConfig<
headers: (params: SnowflakeListFileFormatsParams) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
'X-Snowflake-Authorization-Token-Type': 'OAUTH',
'X-Snowflake-Authorization-Token-Type': 'PROGRAMMATIC_ACCESS_TOKEN',
}),
body: (params: SnowflakeListFileFormatsParams) => {
const requestBody: Record<string, any> = {

View File

@@ -17,17 +17,12 @@ export const snowflakeListSchemasTool: ToolConfig<
description: 'List all schemas in a Snowflake database',
version: '1.0.0',
oauth: {
required: true,
provider: 'snowflake',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Snowflake',
description: 'Snowflake Personal Access Token (PAT)',
},
accountUrl: {
type: 'string',
@@ -64,7 +59,7 @@ export const snowflakeListSchemasTool: ToolConfig<
headers: (params: SnowflakeListSchemasParams) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
'X-Snowflake-Authorization-Token-Type': 'OAUTH',
'X-Snowflake-Authorization-Token-Type': 'PROGRAMMATIC_ACCESS_TOKEN',
}),
body: (params: SnowflakeListSchemasParams) => {
const sanitizedDatabase = sanitizeIdentifier(params.database)

View File

@@ -17,17 +17,12 @@ export const snowflakeListStagesTool: ToolConfig<
description: 'List all stages in a Snowflake schema',
version: '1.0.0',
oauth: {
required: true,
provider: 'snowflake',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Snowflake',
description: 'Snowflake Personal Access Token (PAT)',
},
accountUrl: {
type: 'string',
@@ -70,7 +65,7 @@ export const snowflakeListStagesTool: ToolConfig<
headers: (params: SnowflakeListStagesParams) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
'X-Snowflake-Authorization-Token-Type': 'OAUTH',
'X-Snowflake-Authorization-Token-Type': 'PROGRAMMATIC_ACCESS_TOKEN',
}),
body: (params: SnowflakeListStagesParams) => {
const requestBody: Record<string, any> = {

View File

@@ -17,17 +17,12 @@ export const snowflakeListTablesTool: ToolConfig<
description: 'List all tables in a Snowflake schema',
version: '1.0.0',
oauth: {
required: true,
provider: 'snowflake',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Snowflake',
description: 'Snowflake Personal Access Token (PAT)',
},
accountUrl: {
type: 'string',
@@ -70,7 +65,7 @@ export const snowflakeListTablesTool: ToolConfig<
headers: (params: SnowflakeListTablesParams) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
'X-Snowflake-Authorization-Token-Type': 'OAUTH',
'X-Snowflake-Authorization-Token-Type': 'PROGRAMMATIC_ACCESS_TOKEN',
}),
body: (params: SnowflakeListTablesParams) => {
const sanitizedDatabase = sanitizeIdentifier(params.database)

View File

@@ -14,17 +14,12 @@ export const snowflakeListViewsTool: ToolConfig<
description: 'List all views in a Snowflake schema',
version: '1.0.0',
oauth: {
required: true,
provider: 'snowflake',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Snowflake',
description: 'Snowflake Personal Access Token (PAT)',
},
accountUrl: {
type: 'string',
@@ -67,7 +62,7 @@ export const snowflakeListViewsTool: ToolConfig<
headers: (params: SnowflakeListViewsParams) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
'X-Snowflake-Authorization-Token-Type': 'OAUTH',
'X-Snowflake-Authorization-Token-Type': 'PROGRAMMATIC_ACCESS_TOKEN',
}),
body: (params: SnowflakeListViewsParams) => {
const requestBody: Record<string, any> = {

View File

@@ -17,17 +17,12 @@ export const snowflakeListWarehousesTool: ToolConfig<
description: 'List all warehouses in the Snowflake account',
version: '1.0.0',
oauth: {
required: true,
provider: 'snowflake',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Snowflake',
description: 'Snowflake Personal Access Token (PAT)',
},
accountUrl: {
type: 'string',
@@ -58,7 +53,7 @@ export const snowflakeListWarehousesTool: ToolConfig<
headers: (params: SnowflakeListWarehousesParams) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
'X-Snowflake-Authorization-Token-Type': 'OAUTH',
'X-Snowflake-Authorization-Token-Type': 'PROGRAMMATIC_ACCESS_TOKEN',
}),
body: (params: SnowflakeListWarehousesParams) => {
const requestBody: Record<string, any> = {

View File

@@ -63,17 +63,12 @@ export const snowflakeUpdateRowsTool: ToolConfig<
description: 'Update rows in a Snowflake table',
version: '1.0.0',
oauth: {
required: true,
provider: 'snowflake',
},
params: {
accessToken: {
type: 'string',
required: true,
visibility: 'hidden',
description: 'OAuth access token for Snowflake',
description: 'Snowflake Personal Access Token (PAT)',
},
accountUrl: {
type: 'string',
@@ -142,7 +137,7 @@ export const snowflakeUpdateRowsTool: ToolConfig<
headers: (params: SnowflakeUpdateRowsParams) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.accessToken}`,
'X-Snowflake-Authorization-Token-Type': 'OAUTH',
'X-Snowflake-Authorization-Token-Type': 'PROGRAMMATIC_ACCESS_TOKEN',
}),
body: (params: SnowflakeUpdateRowsParams) => {
// Validate inputs

View File

@@ -66,7 +66,7 @@ export async function executeSnowflakeStatement(
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
'X-Snowflake-Authorization-Token-Type': 'OAUTH',
'X-Snowflake-Authorization-Token-Type': 'PROGRAMMATIC_ACCESS_TOKEN',
},
body: JSON.stringify(requestBody),
})