|
@@ -59,7 +59,7 @@ export interface ShopRenterOrder {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// Get valid access token (with automatic refresh)
|
|
|
|
|
|
|
+// Get valid access token (with automatic refresh or client_credentials)
|
|
|
export async function getValidAccessToken(storeId: string): Promise<string> {
|
|
export async function getValidAccessToken(storeId: string): Promise<string> {
|
|
|
const supabaseUrl = Deno.env.get('SUPABASE_URL')!
|
|
const supabaseUrl = Deno.env.get('SUPABASE_URL')!
|
|
|
const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
|
|
const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!
|
|
@@ -77,6 +77,35 @@ export async function getValidAccessToken(storeId: string): Promise<string> {
|
|
|
throw new Error('ShopRenter store not found')
|
|
throw new Error('ShopRenter store not found')
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ // Check if api_key contains a client_id (32 hex chars) instead of a token
|
|
|
|
|
+ // Client credentials are typically 32 hex characters
|
|
|
|
|
+ const isClientId = store.api_key && /^[a-f0-9]{32}$/i.test(store.api_key)
|
|
|
|
|
+
|
|
|
|
|
+ if (isClientId && store.api_secret) {
|
|
|
|
|
+ console.log('[ShopRenter] Detected client credentials, obtaining access token via client_credentials flow')
|
|
|
|
|
+
|
|
|
|
|
+ // Use client_credentials flow to get access token
|
|
|
|
|
+ const tokenData = await getTokenWithClientCredentials(store.store_name, store.api_key, store.api_secret)
|
|
|
|
|
+
|
|
|
|
|
+ // Update store with the new access token
|
|
|
|
|
+ await supabase
|
|
|
|
|
+ .from('stores')
|
|
|
|
|
+ .update({
|
|
|
|
|
+ api_key: tokenData.access_token,
|
|
|
|
|
+ api_secret: tokenData.refresh_token || store.api_secret,
|
|
|
|
|
+ alt_data: {
|
|
|
|
|
+ ...store.alt_data,
|
|
|
|
|
+ expires_at: new Date(Date.now() + (tokenData.expires_in * 1000)).toISOString(),
|
|
|
|
|
+ client_id: store.api_key, // Store original client_id for reference
|
|
|
|
|
+ client_secret: store.api_secret // Store original client_secret for reference
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ .eq('id', storeId)
|
|
|
|
|
+
|
|
|
|
|
+ console.log('[ShopRenter] Access token obtained and stored successfully')
|
|
|
|
|
+ return tokenData.access_token
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// Check if we have tokens in api_key/api_secret (legacy)
|
|
// Check if we have tokens in api_key/api_secret (legacy)
|
|
|
if (store.api_key) {
|
|
if (store.api_key) {
|
|
|
const expiresAt = store.alt_data?.expires_at
|
|
const expiresAt = store.alt_data?.expires_at
|
|
@@ -117,6 +146,41 @@ export async function getValidAccessToken(storeId: string): Promise<string> {
|
|
|
throw new Error('No access token found for ShopRenter store')
|
|
throw new Error('No access token found for ShopRenter store')
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// Get access token using client_credentials grant
|
|
|
|
|
+async function getTokenWithClientCredentials(shopname: string, clientId: string, clientSecret: string) {
|
|
|
|
|
+ const tokenUrl = `https://oauth.app.shoprenter.net/${shopname}/app/token`
|
|
|
|
|
+
|
|
|
|
|
+ console.log(`[ShopRenter] Requesting token for ${shopname} using client_credentials`)
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const response = await fetch(tokenUrl, {
|
|
|
|
|
+ method: 'POST',
|
|
|
|
|
+ headers: {
|
|
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
|
|
+ 'Accept': 'application/json'
|
|
|
|
|
+ },
|
|
|
|
|
+ body: JSON.stringify({
|
|
|
|
|
+ grant_type: 'client_credentials',
|
|
|
|
|
+ client_id: clientId,
|
|
|
|
|
+ client_secret: clientSecret
|
|
|
|
|
+ })
|
|
|
|
|
+ })
|
|
|
|
|
+
|
|
|
|
|
+ if (!response.ok) {
|
|
|
|
|
+ const errorData = await response.text()
|
|
|
|
|
+ console.error('[ShopRenter] Token request error:', errorData)
|
|
|
|
|
+ throw new Error(`Failed to get access token: ${response.status} ${errorData}`)
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const data = await response.json()
|
|
|
|
|
+ console.log(`[ShopRenter] Access token obtained for ${shopname}`)
|
|
|
|
|
+ return data
|
|
|
|
|
+ } catch (error) {
|
|
|
|
|
+ console.error('[ShopRenter] Token request error:', error)
|
|
|
|
|
+ throw new Error('Failed to get access token via client_credentials')
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// Refresh access token
|
|
// Refresh access token
|
|
|
async function refreshAccessToken(shopname: string, refreshToken: string) {
|
|
async function refreshAccessToken(shopname: string, refreshToken: string) {
|
|
|
const clientId = Deno.env.get('SHOPRENTER_CLIENT_ID')
|
|
const clientId = Deno.env.get('SHOPRENTER_CLIENT_ID')
|