UNPKG

@saas-ui/supabase

Version:

Saas UI Supabase Auth integration

1 lines 10.6 kB
{"version":3,"sources":["../src/supabase.ts"],"sourcesContent":["import type {\n AuthParams,\n AuthOptions,\n AuthStateChangeCallback,\n AuthProviderProps,\n} from '@saas-ui/auth-provider'\n\nimport type {\n AuthChangeEvent,\n AuthResponse,\n OAuthResponse,\n Provider,\n Session,\n User,\n SupabaseClient,\n VerifyEmailOtpParams,\n VerifyMobileOtpParams,\n SignOut,\n} from '@supabase/supabase-js'\n\ninterface RecoveryParams {\n access_token?: string\n refresh_token?: string\n expires_in?: string\n token_type?: string\n type?: string\n}\n\ninterface OtpParams extends AuthParams {\n otp: string\n}\n\ninterface SupabaseServiceAuthOptions {\n loginOptions?: {\n data?: object\n /** A URL to send the user to after they are confirmed. */\n redirectTo?: string\n /** A space-separated list of scopes granted to the OAuth application. */\n scopes?: string\n /** An object of query params */\n queryParams?: { [key: string]: string }\n\n /** Verification token received when the user completes the captcha on the site. */\n captchaToken?: string\n /** The redirect url embedded in the email link */\n emailRedirectTo?: string\n /** If set to false, this method will not create a new user. Defaults to true. */\n shouldCreateUser?: boolean\n }\n signupOptions?: {\n emailRedirectTo?: string\n /**\n * A custom data object to store the user's metadata. This maps to the `auth.users.user_metadata` column.\n *\n * The `data` should be a JSON object that includes user-specific info, such as their first and last name.\n */\n data?: object\n /** Verification token received when the user completes the captcha on the site. */\n captchaToken?: string\n }\n verifyOptions?: {\n /** A URL to send the user to after they are confirmed. */\n redirectTo?: string\n /** Verification token received when the user completes the captcha on the site. */\n captchaToken?: string\n }\n resetPasswordOptions?: {\n redirectTo?: string\n captchaToken?: string\n }\n}\n\nexport const createAuthService = <Client extends SupabaseClient>(\n supabase: Client,\n serviceOptions?: SupabaseServiceAuthOptions\n): AuthProviderProps<User> => {\n const onLogin = async (\n params: AuthParams,\n authOptions?: AuthOptions<{\n data?: object\n captchaToken?: string\n scopes?: string\n }>\n ) => {\n const options = {\n ...serviceOptions?.loginOptions,\n ...authOptions,\n emailRedirectTo: authOptions?.redirectTo,\n }\n\n function authenticate() {\n const { email, password, provider, phone } = params\n if (email && password) {\n return supabase.auth.signInWithPassword({\n email,\n password,\n options,\n })\n } else if (email) {\n return supabase.auth.signInWithOtp({ email, options })\n } else if (provider) {\n return supabase.auth.signInWithOAuth({\n provider: provider as Provider,\n options,\n })\n } else if (phone && password) {\n return supabase.auth.signInWithPassword({ phone, password, options })\n } else if (phone) {\n return supabase.auth.signInWithOtp({ phone, options })\n }\n throw new Error('Could not find correct authentication method')\n }\n const resp = await authenticate()\n\n if (resp.error) {\n throw resp.error\n }\n\n if (isOauthResponse(resp)) {\n // do nothing, supabase will redirect\n return\n }\n\n return resp.data.user\n }\n\n const onSignup = async (\n params: AuthParams,\n authOptions?: AuthOptions<{\n captchaToken?: string\n emailRedirectTo?: string\n data?: object\n }>\n ) => {\n async function signup() {\n const { email, phone, password } = params\n const options = {\n ...serviceOptions?.signupOptions,\n ...authOptions,\n emailRedirectTo: authOptions?.redirectTo,\n }\n if (email && password) {\n return await supabase.auth.signUp({\n email,\n password,\n options,\n })\n } else if (phone && password) {\n return await supabase.auth.signUp({\n phone,\n password,\n options,\n })\n } else if (email) {\n return supabase.auth.signInWithOtp({ email, options })\n } else if (phone) {\n return supabase.auth.signInWithOtp({ phone, options })\n }\n }\n\n const resp = await signup()\n\n if (resp?.error) {\n throw resp.error\n }\n\n return resp?.data.user\n }\n\n const onVerifyOtp = async (\n params: OtpParams,\n options?: AuthOptions<{ captchaToken?: string }>\n ) => {\n const { email, phone, otp, type } = params\n\n if (email) {\n const verify: VerifyEmailOtpParams = {\n email,\n token: otp,\n type: type || 'signup',\n options: {\n ...serviceOptions?.verifyOptions,\n ...options,\n },\n }\n const resp = await supabase.auth.verifyOtp(verify)\n if (resp.error) {\n throw resp.error\n }\n return Boolean(resp.data.session)\n }\n\n if (phone) {\n const verify: VerifyMobileOtpParams = {\n phone,\n token: otp,\n type: type || 'sms',\n options: {\n ...serviceOptions?.verifyOptions,\n ...options,\n },\n }\n const resp = await supabase.auth.verifyOtp(verify)\n if (resp.error) {\n throw resp.error\n }\n return Boolean(resp.data.session)\n }\n\n throw new Error('You need to provide either email or phone')\n }\n\n const onLogout = async (options?: AuthOptions<SignOut>) => {\n return await supabase.auth.signOut(options)\n }\n\n const onAuthStateChange = (callback: AuthStateChangeCallback<User>) => {\n const { data } = supabase.auth.onAuthStateChange(\n (event: AuthChangeEvent, session: Session | null) => {\n callback(session?.user)\n }\n )\n\n return () => data?.subscription.unsubscribe()\n }\n\n const onLoadUser = async () => {\n const { data, error } = await supabase.auth.getUser()\n if (error) {\n throw error\n }\n return data.user\n }\n\n const onGetToken = async () => {\n const { data, error } = await supabase.auth.getSession()\n if (error) {\n throw error\n }\n return data.session?.access_token || null\n }\n\n const onResetPassword = async (\n { email }: Required<Pick<AuthParams, 'email'>>,\n options?: AuthOptions\n ) => {\n const { error } = await supabase.auth.resetPasswordForEmail(email, {\n ...serviceOptions?.resetPasswordOptions,\n ...options,\n })\n if (error) {\n throw error\n }\n }\n\n const onUpdatePassword = async ({\n password,\n }: Required<Pick<AuthParams, 'password'>>) => {\n const { error } = await supabase.auth.updateUser({\n password,\n })\n if (error) {\n throw error\n }\n }\n\n return {\n onLogin,\n onSignup,\n onVerifyOtp,\n onLogout,\n onAuthStateChange,\n onLoadUser,\n onGetToken,\n onResetPassword,\n onUpdatePassword,\n }\n}\n\nfunction isOauthResponse(\n response: AuthResponse | OAuthResponse\n): response is OAuthResponse {\n return Boolean((response as OAuthResponse).data?.provider)\n}\n"],"mappings":"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","names":[]}