diff --git a/apps/studio/data/oauth-custom-providers/custom-provider-admin-request.ts b/apps/studio/data/oauth-custom-providers/custom-provider-admin-request.ts deleted file mode 100644 index 7c2c583c307..00000000000 --- a/apps/studio/data/oauth-custom-providers/custom-provider-admin-request.ts +++ /dev/null @@ -1,83 +0,0 @@ -import { getOrRefreshTemporaryApiKey } from '@/data/api-keys/temp-api-keys-utils' -import { handleError } from '@/data/fetchers' - -/** - * Keeps the structural `custom:` prefix literal while still encoding the - * user-controlled slug, e.g. `custom:naver` -> `custom:naver`, - * `custom:my provider` -> `custom:my%20provider`. - */ -function encodeCustomProviderIdentifier(identifier: string) { - const slug = identifier.replace(/^custom:/i, '') - return `custom:${encodeURIComponent(slug)}` -} - -function extractErrorMessage(payload: unknown, fallback: string) { - if (payload && typeof payload === 'object') { - if ('msg' in payload && typeof payload.msg === 'string') return payload.msg - if ('message' in payload && typeof payload.message === 'string') return payload.message - if ('error_description' in payload && typeof payload.error_description === 'string') { - return payload.error_description - } - } - return fallback -} - -/** - * Performs a raw request against the GoTrue custom-providers admin endpoint. - * - * We bypass the auth-js SDK's `customProviders.updateProvider` / `deleteProvider` - * helpers here because they run the identifier through `encodeURIComponent` - * (supabase-js#2383), which turns the required `custom:` prefix into `custom%3A`. - * The GoTrue endpoint does not decode the path segment, so the encoded colon - * fails its `identifier must start with 'custom:'` validation. - * - * TODO: remove this and return to the SDK helpers once GoTrue decodes the - * custom-provider path segment (supabase-js#2383). - */ -export async function customProviderAdminRequest({ - method, - projectRef, - clientEndpoint, - identifier, - body, -}: { - method: 'PUT' | 'DELETE' - projectRef: string - clientEndpoint: string - identifier: string - body?: unknown -}) { - const { apiKey } = await getOrRefreshTemporaryApiKey(projectRef) - const path = encodeCustomProviderIdentifier(identifier) - - const response = await fetch(`${clientEndpoint}/auth/v1/admin/custom-providers/${path}`, { - method, - headers: { - apikey: apiKey, - Authorization: `Bearer ${apiKey}`, - 'Content-Type': 'application/json', - }, - ...(body !== undefined ? { body: JSON.stringify(body) } : {}), - }) - - if (!response.ok) { - let payload: unknown - try { - payload = await response.json() - } catch { - // response had no JSON body - } - handleError({ - message: extractErrorMessage(payload, `Request failed with status ${response.status}`), - code: response.status, - }) - } - - if (method === 'DELETE') return null - - try { - return await response.json() - } catch { - return null - } -} diff --git a/apps/studio/data/oauth-custom-providers/oauth-custom-provider-delete-mutation.ts b/apps/studio/data/oauth-custom-providers/oauth-custom-provider-delete-mutation.ts index b3335b6f0ce..384e801151a 100644 --- a/apps/studio/data/oauth-custom-providers/oauth-custom-provider-delete-mutation.ts +++ b/apps/studio/data/oauth-custom-providers/oauth-custom-provider-delete-mutation.ts @@ -1,8 +1,9 @@ import { useMutation, useQueryClient } from '@tanstack/react-query' import { toast } from 'sonner' -import { customProviderAdminRequest } from './custom-provider-admin-request' import { oAuthCustomProvidersKeys } from './keys' +import { handleError } from '@/data/fetchers' +import { createProjectSupabaseClient } from '@/lib/project-supabase-client' import type { ResponseError, UseCustomMutationOptions } from '@/types' export type OAuthCustomProviderDeleteVariables = { @@ -20,12 +21,10 @@ export async function deleteOAuthCustomProvider({ if (!clientEndpoint) throw new Error('Client endpoint is required') if (!identifier) throw new Error('Provider identifier is required') - await customProviderAdminRequest({ - method: 'DELETE', - projectRef, - clientEndpoint, - identifier, - }) + const supabaseClient = await createProjectSupabaseClient(projectRef, clientEndpoint) + const { error } = await supabaseClient.auth.admin.customProviders.deleteProvider(identifier) + + if (error) handleError(error) return null } diff --git a/apps/studio/data/oauth-custom-providers/oauth-custom-provider-update-mutation.ts b/apps/studio/data/oauth-custom-providers/oauth-custom-provider-update-mutation.ts index 41b892b1f6e..9caf8c212dc 100644 --- a/apps/studio/data/oauth-custom-providers/oauth-custom-provider-update-mutation.ts +++ b/apps/studio/data/oauth-custom-providers/oauth-custom-provider-update-mutation.ts @@ -2,8 +2,9 @@ import type { UpdateCustomProviderParams } from '@supabase/auth-js' import { useMutation, useQueryClient } from '@tanstack/react-query' import { toast } from 'sonner' -import { customProviderAdminRequest } from './custom-provider-admin-request' import { oAuthCustomProvidersKeys } from './keys' +import { handleError } from '@/data/fetchers' +import { createProjectSupabaseClient } from '@/lib/project-supabase-client' import type { ResponseError, UseCustomMutationOptions } from '@/types' export type OAuthCustomProviderUpdateVariables = UpdateCustomProviderParams & { @@ -22,13 +23,14 @@ export async function updateOAuthCustomProvider({ if (!clientEndpoint) throw new Error('Client endpoint is required') if (!identifier) throw new Error('Provider identifier is required') - return customProviderAdminRequest({ - method: 'PUT', - projectRef, - clientEndpoint, + const supabaseClient = await createProjectSupabaseClient(projectRef, clientEndpoint) + const { data, error } = await supabaseClient.auth.admin.customProviders.updateProvider( identifier, - body: params, - }) + params + ) + + if (error) handleError(error) + return data! } type OAuthCustomProviderUpdateData = Awaited>