mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
## What kind of change does this PR introduce? After users have set up a new MFA (first or not), we must: - check whether recovery codes have already been generated - if there are none, generate recovery codes and display them, "forcing" users to copy them - if already generated, show them how many are still available > [!NOTE] > The _Delete my recovery codes_ button in last screenshot only appear on local and staging environments ## How to test - On an account that doesn't have recovery codes generated yet and has an MFA added - You should see an admonition suggesting to generate the codes ## Screenshots <img width="729" height="306" alt="image" src="https://github.com/user-attachments/assets/79ba3870-4ef8-4571-9fd6-36eed20c9c24" /> <img width="550" height="356" alt="image" src="https://github.com/user-attachments/assets/1632611a-996a-470d-b6cd-a4693b0f4602" /> <img width="719" height="205" alt="image" src="https://github.com/user-attachments/assets/73cef611-05cf-4fac-bbd2-243f9b28e48d" /> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added support for generating, copying, and confirming MFA recovery codes. - Added recovery-code status visibility, including remaining and exhausted codes. - Added the ability to delete recovery codes with confirmation. - Added clear loading, success, and error states for recovery-code actions. - Recovery-code status refreshes after codes are generated or deleted. - **Bug Fixes** - Recovery-code notices now remain visible when all codes have been used. - Recovery-code dialogs can now be closed after generation errors. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
66 lines
2.6 KiB
TypeScript
66 lines
2.6 KiB
TypeScript
import { AuthError, type CustomOAuthProvider } from '@supabase/auth-js'
|
|
import { useQuery } from '@tanstack/react-query'
|
|
|
|
import { oAuthCustomProvidersKeys } from './keys'
|
|
import { useAuthConfigQuery } from '@/data/auth/auth-config-query'
|
|
import { useProjectApiUrl } from '@/data/config/project-endpoint-query'
|
|
import { handleError } from '@/data/fetchers'
|
|
import { createProjectSupabaseClient } from '@/lib/project-supabase-client'
|
|
import type { ResponseError, UseCustomQueryOptions } from '@/types'
|
|
|
|
export type OAuthCustomProvidersVariables = {
|
|
projectRef: string | undefined
|
|
page?: number
|
|
}
|
|
|
|
export async function getOAuthCustomProviders({
|
|
projectRef,
|
|
clientEndpoint,
|
|
}: OAuthCustomProvidersVariables & { clientEndpoint: string | undefined }) {
|
|
if (!projectRef) throw new Error('Project reference is required')
|
|
if (!clientEndpoint) throw new Error('Client endpoint is required')
|
|
|
|
const supabaseClient = await createProjectSupabaseClient(projectRef, clientEndpoint)
|
|
|
|
const { data, error } = await supabaseClient.auth.admin.customProviders.listProviders()
|
|
|
|
if (error) {
|
|
// Non-JSON responses from the API indicate custom providers aren't enabled.
|
|
// Different browsers/SDK versions produce different JSON parse error messages,
|
|
// so we check broadly for JSON parse indicators.
|
|
if (/JSON\.parse|Unexpected token|unexpected.*character/i.test(error.message)) {
|
|
handleError(new AuthError('Custom providers are not enabled for this project'))
|
|
} else {
|
|
handleError(error)
|
|
}
|
|
}
|
|
return data.providers as CustomOAuthProvider[]
|
|
}
|
|
|
|
export type OAuthCustomProvidersData = Awaited<ReturnType<typeof getOAuthCustomProviders>>
|
|
export type OAuthCustomProvidersError = ResponseError
|
|
|
|
export const useOAuthCustomProvidersQuery = <TData = OAuthCustomProvidersData>(
|
|
{ projectRef }: OAuthCustomProvidersVariables,
|
|
{
|
|
enabled = true,
|
|
...options
|
|
}: UseCustomQueryOptions<OAuthCustomProvidersData, OAuthCustomProvidersError, TData> = {}
|
|
) => {
|
|
const { hostEndpoint: clientEndpoint } = useProjectApiUrl({ projectRef })
|
|
const { data: authConfig, isSuccess: isSuccessConfig } = useAuthConfigQuery({ projectRef })
|
|
const isOAuthCustomProvidersEnabled = !!authConfig?.CUSTOM_OAUTH_ENABLED
|
|
|
|
return useQuery<OAuthCustomProvidersData, OAuthCustomProvidersError, TData>({
|
|
queryKey: oAuthCustomProvidersKeys.list(projectRef, clientEndpoint),
|
|
queryFn: () => getOAuthCustomProviders({ projectRef, clientEndpoint }),
|
|
enabled:
|
|
enabled &&
|
|
typeof projectRef !== 'undefined' &&
|
|
!!clientEndpoint &&
|
|
isSuccessConfig &&
|
|
isOAuthCustomProvidersEnabled,
|
|
...options,
|
|
})
|
|
}
|