feat: add support for 15 new OAuth providers including Apple, Microsoft, and TikTok (#34)
* feat: add support for 15 new OAuth providers including Apple, Microsoft, and TikTok * chore: remove unused OAuth providers from docs
This commit is contained in:
31
.env.example
31
.env.example
@@ -25,4 +25,35 @@ DISCORD_CLIENT_ID=
|
|||||||
DISCORD_CLIENT_SECRET=
|
DISCORD_CLIENT_SECRET=
|
||||||
GITHUB_CLIENT_ID=
|
GITHUB_CLIENT_ID=
|
||||||
GITHUB_CLIENT_SECRET=
|
GITHUB_CLIENT_SECRET=
|
||||||
|
GITLAB_CLIENT_ID=
|
||||||
|
GITLAB_CLIENT_SECRET=
|
||||||
|
GITLAB_ISSUER=
|
||||||
|
MICROSOFT_CLIENT_ID=
|
||||||
|
MICROSOFT_CLIENT_SECRET=
|
||||||
|
TWITTER_CLIENT_ID=
|
||||||
|
TWITTER_CLIENT_SECRET=
|
||||||
|
KICK_CLIENT_ID=
|
||||||
|
KICK_CLIENT_SECRET=
|
||||||
|
ZOOM_CLIENT_ID=
|
||||||
|
ZOOM_CLIENT_SECRET=
|
||||||
|
DROPBOX_CLIENT_ID=
|
||||||
|
DROPBOX_CLIENT_SECRET=
|
||||||
|
VK_CLIENT_ID=
|
||||||
|
VK_CLIENT_SECRET=
|
||||||
|
LINKEDIN_CLIENT_ID=
|
||||||
|
LINKEDIN_CLIENT_SECRET=
|
||||||
|
REDDIT_CLIENT_ID=
|
||||||
|
REDDIT_CLIENT_SECRET=
|
||||||
|
ROBLOX_CLIENT_ID=
|
||||||
|
ROBLOX_CLIENT_SECRET=
|
||||||
|
SPOTIFY_CLIENT_ID=
|
||||||
|
SPOTIFY_CLIENT_SECRET=
|
||||||
|
TIKTOK_CLIENT_ID=
|
||||||
|
TIKTOK_CLIENT_SECRET=
|
||||||
|
TIKTOK_CLIENT_KEY=
|
||||||
|
TWITCH_CLIENT_ID=
|
||||||
|
TWITCH_CLIENT_SECRET=
|
||||||
|
APPLE_CLIENT_ID=
|
||||||
|
APPLE_CLIENT_SECRET=
|
||||||
|
APPLE_APP_BUNDLE_IDENTIFIER=
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ import { zodResolver } from "@hookform/resolvers/zod";
|
|||||||
import { useQuery } from "@tanstack/react-query";
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { FaDiscord, FaGithub, FaGoogle } from "react-icons/fa";
|
import { FaDiscord, FaGithub, FaGoogle, FaApple, FaMicrosoft, FaFacebook, FaSpotify, FaTwitch, FaTwitter, FaDropbox, FaLinkedin, FaGitlab, FaTiktok, FaReddit, FaVk } from "react-icons/fa";
|
||||||
|
import { SiRoblox, SiZoom } from "react-icons/si";
|
||||||
|
import { TbBrandKick } from "react-icons/tb";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import type { SocialProvider } from "better-auth/social-providers";
|
import type { SocialProvider } from "better-auth/social-providers";
|
||||||
|
|
||||||
@@ -21,6 +23,99 @@ interface AuthProps {
|
|||||||
|
|
||||||
const EmailSchema = z.object({ email: z.string().email() });
|
const EmailSchema = z.object({ email: z.string().email() });
|
||||||
|
|
||||||
|
const availableSocialProviders = {
|
||||||
|
google: {
|
||||||
|
id: "google",
|
||||||
|
name: "Google",
|
||||||
|
icon: FaGoogle,
|
||||||
|
},
|
||||||
|
github: {
|
||||||
|
id: "github",
|
||||||
|
name: "GitHub",
|
||||||
|
icon: FaGithub,
|
||||||
|
},
|
||||||
|
discord: {
|
||||||
|
id: "discord",
|
||||||
|
name: "Discord",
|
||||||
|
icon: FaDiscord,
|
||||||
|
},
|
||||||
|
apple: {
|
||||||
|
id: "apple",
|
||||||
|
name: "Apple",
|
||||||
|
icon: FaApple,
|
||||||
|
},
|
||||||
|
microsoft: {
|
||||||
|
id: "microsoft",
|
||||||
|
name: "Microsoft",
|
||||||
|
icon: FaMicrosoft,
|
||||||
|
},
|
||||||
|
facebook: {
|
||||||
|
id: "facebook",
|
||||||
|
name: "Facebook",
|
||||||
|
icon: FaFacebook,
|
||||||
|
},
|
||||||
|
spotify: {
|
||||||
|
id: "spotify",
|
||||||
|
name: "Spotify",
|
||||||
|
icon: FaSpotify,
|
||||||
|
},
|
||||||
|
twitch: {
|
||||||
|
id: "twitch",
|
||||||
|
name: "Twitch",
|
||||||
|
icon: FaTwitch,
|
||||||
|
},
|
||||||
|
twitter: {
|
||||||
|
id: "twitter",
|
||||||
|
name: "Twitter",
|
||||||
|
icon: FaTwitter,
|
||||||
|
},
|
||||||
|
dropbox: {
|
||||||
|
id: "dropbox",
|
||||||
|
name: "Dropbox",
|
||||||
|
icon: FaDropbox,
|
||||||
|
},
|
||||||
|
linkedin: {
|
||||||
|
id: "linkedin",
|
||||||
|
name: "LinkedIn",
|
||||||
|
icon: FaLinkedin,
|
||||||
|
},
|
||||||
|
gitlab: {
|
||||||
|
id: "gitlab",
|
||||||
|
name: "GitLab",
|
||||||
|
icon: FaGitlab,
|
||||||
|
},
|
||||||
|
tiktok: {
|
||||||
|
id: "tiktok",
|
||||||
|
name: "TikTok",
|
||||||
|
icon: FaTiktok,
|
||||||
|
},
|
||||||
|
reddit: {
|
||||||
|
id: "reddit",
|
||||||
|
name: "Reddit",
|
||||||
|
icon: FaReddit,
|
||||||
|
},
|
||||||
|
roblox: {
|
||||||
|
id: "roblox",
|
||||||
|
name: "Roblox",
|
||||||
|
icon: SiRoblox,
|
||||||
|
},
|
||||||
|
vk: {
|
||||||
|
id: "vk",
|
||||||
|
name: "VK",
|
||||||
|
icon: FaVk,
|
||||||
|
},
|
||||||
|
kick: {
|
||||||
|
id: "kick",
|
||||||
|
name: "Kick",
|
||||||
|
icon: TbBrandKick,
|
||||||
|
},
|
||||||
|
zoom: {
|
||||||
|
id: "zoom",
|
||||||
|
name: "Zoom",
|
||||||
|
icon: SiZoom,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
export function Auth({ setIsMagicLinkSent }: AuthProps) {
|
export function Auth({ setIsMagicLinkSent }: AuthProps) {
|
||||||
const [isLoginWithProviderPending, setIsLoginWithProviderPending] = useState<
|
const [isLoginWithProviderPending, setIsLoginWithProviderPending] = useState<
|
||||||
null | SocialProvider
|
null | SocialProvider
|
||||||
@@ -86,39 +181,21 @@ export function Auth({ setIsMagicLinkSent }: AuthProps) {
|
|||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
{socialProviders?.length !== 0 && (
|
{socialProviders?.length !== 0 && (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{socialProviders?.includes("google") && (
|
{Object.entries(availableSocialProviders).map(([key, provider]) => {
|
||||||
|
if (!socialProviders?.includes(key)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return (
|
||||||
<Button
|
<Button
|
||||||
onClick={() => handleLoginWithProvider("google")}
|
onClick={() => handleLoginWithProvider(key as SocialProvider)}
|
||||||
isLoading={isLoginWithProviderPending === "google"}
|
isLoading={isLoginWithProviderPending === key}
|
||||||
iconLeft={<FaGoogle />}
|
iconLeft={<provider.icon />}
|
||||||
fullWidth
|
fullWidth
|
||||||
size="lg"
|
size="lg"
|
||||||
>
|
>
|
||||||
Continue with Google
|
Continue with {provider.name}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)})}
|
||||||
{socialProviders?.includes("github") && (
|
|
||||||
<Button
|
|
||||||
onClick={() => handleLoginWithProvider("github")}
|
|
||||||
isLoading={isLoginWithProviderPending === "github"}
|
|
||||||
iconLeft={<FaGithub />}
|
|
||||||
fullWidth
|
|
||||||
size="lg"
|
|
||||||
>
|
|
||||||
Continue with GitHub
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{socialProviders?.includes("discord") && (
|
|
||||||
<Button
|
|
||||||
onClick={() => handleLoginWithProvider("discord")}
|
|
||||||
isLoading={isLoginWithProviderPending === "discord"}
|
|
||||||
iconLeft={<FaDiscord />}
|
|
||||||
fullWidth
|
|
||||||
size="lg"
|
|
||||||
>
|
|
||||||
Continue with Discord
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(onSubmit)}>
|
||||||
|
|||||||
@@ -25,6 +25,37 @@ export const env = createEnv({
|
|||||||
DISCORD_CLIENT_SECRET: z.string().optional(),
|
DISCORD_CLIENT_SECRET: z.string().optional(),
|
||||||
GITHUB_CLIENT_ID: z.string().optional(),
|
GITHUB_CLIENT_ID: z.string().optional(),
|
||||||
GITHUB_CLIENT_SECRET: z.string().optional(),
|
GITHUB_CLIENT_SECRET: z.string().optional(),
|
||||||
|
GITLAB_CLIENT_ID: z.string().optional(),
|
||||||
|
GITLAB_CLIENT_SECRET: z.string().optional(),
|
||||||
|
GITLAB_ISSUER: z.string().optional(),
|
||||||
|
MICROSOFT_CLIENT_ID: z.string().optional(),
|
||||||
|
MICROSOFT_CLIENT_SECRET: z.string().optional(),
|
||||||
|
TWITTER_CLIENT_ID: z.string().optional(),
|
||||||
|
TWITTER_CLIENT_SECRET: z.string().optional(),
|
||||||
|
KICK_CLIENT_ID: z.string().optional(),
|
||||||
|
KICK_CLIENT_SECRET: z.string().optional(),
|
||||||
|
ZOOM_CLIENT_ID: z.string().optional(),
|
||||||
|
ZOOM_CLIENT_SECRET: z.string().optional(),
|
||||||
|
DROPBOX_CLIENT_ID: z.string().optional(),
|
||||||
|
DROPBOX_CLIENT_SECRET: z.string().optional(),
|
||||||
|
VK_CLIENT_ID: z.string().optional(),
|
||||||
|
VK_CLIENT_SECRET: z.string().optional(),
|
||||||
|
LINKEDIN_CLIENT_ID: z.string().optional(),
|
||||||
|
LINKEDIN_CLIENT_SECRET: z.string().optional(),
|
||||||
|
REDDIT_CLIENT_ID: z.string().optional(),
|
||||||
|
REDDIT_CLIENT_SECRET: z.string().optional(),
|
||||||
|
ROBLOX_CLIENT_ID: z.string().optional(),
|
||||||
|
ROBLOX_CLIENT_SECRET: z.string().optional(),
|
||||||
|
SPOTIFY_CLIENT_ID: z.string().optional(),
|
||||||
|
SPOTIFY_CLIENT_SECRET: z.string().optional(),
|
||||||
|
TIKTOK_CLIENT_ID: z.string().optional(),
|
||||||
|
TIKTOK_CLIENT_SECRET: z.string().optional(),
|
||||||
|
TIKTOK_CLIENT_KEY: z.string().optional(),
|
||||||
|
TWITCH_CLIENT_ID: z.string().optional(),
|
||||||
|
TWITCH_CLIENT_SECRET: z.string().optional(),
|
||||||
|
APPLE_CLIENT_ID: z.string().optional(),
|
||||||
|
APPLE_CLIENT_SECRET: z.string().optional(),
|
||||||
|
APPLE_APP_BUNDLE_IDENTIFIER: z.string().optional(),
|
||||||
S3_ACCESS_KEY_ID: z.string().optional(),
|
S3_ACCESS_KEY_ID: z.string().optional(),
|
||||||
S3_SECRET_ACCESS_KEY: z.string().optional(),
|
S3_SECRET_ACCESS_KEY: z.string().optional(),
|
||||||
S3_REGION: z.string().optional(),
|
S3_REGION: z.string().optional(),
|
||||||
|
|||||||
@@ -31,6 +31,37 @@ services:
|
|||||||
- DISCORD_CLIENT_SECRET=${DISCORD_CLIENT_SECRET}
|
- DISCORD_CLIENT_SECRET=${DISCORD_CLIENT_SECRET}
|
||||||
- GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID}
|
- GITHUB_CLIENT_ID=${GITHUB_CLIENT_ID}
|
||||||
- GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET}
|
- GITHUB_CLIENT_SECRET=${GITHUB_CLIENT_SECRET}
|
||||||
|
- GITLAB_CLIENT_ID=${GITLAB_CLIENT_ID}
|
||||||
|
- GITLAB_CLIENT_SECRET=${GITLAB_CLIENT_SECRET}
|
||||||
|
- GITLAB_ISSUER=${GITLAB_ISSUER}
|
||||||
|
- MICROSOFT_CLIENT_ID=${MICROSOFT_CLIENT_ID}
|
||||||
|
- MICROSOFT_CLIENT_SECRET=${MICROSOFT_CLIENT_SECRET}
|
||||||
|
- TWITTER_CLIENT_ID=${TWITTER_CLIENT_ID}
|
||||||
|
- TWITTER_CLIENT_SECRET=${TWITTER_CLIENT_SECRET}
|
||||||
|
- KICK_CLIENT_ID=${KICK_CLIENT_ID}
|
||||||
|
- KICK_CLIENT_SECRET=${KICK_CLIENT_SECRET}
|
||||||
|
- ZOOM_CLIENT_ID=${ZOOM_CLIENT_ID}
|
||||||
|
- ZOOM_CLIENT_SECRET=${ZOOM_CLIENT_SECRET}
|
||||||
|
- DROPBOX_CLIENT_ID=${DROPBOX_CLIENT_ID}
|
||||||
|
- DROPBOX_CLIENT_SECRET=${DROPBOX_CLIENT_SECRET}
|
||||||
|
- VK_CLIENT_ID=${VK_CLIENT_ID}
|
||||||
|
- VK_CLIENT_SECRET=${VK_CLIENT_SECRET}
|
||||||
|
- LINKEDIN_CLIENT_ID=${LINKEDIN_CLIENT_ID}
|
||||||
|
- LINKEDIN_CLIENT_SECRET=${LINKEDIN_CLIENT_SECRET}
|
||||||
|
- REDDIT_CLIENT_ID=${REDDIT_CLIENT_ID}
|
||||||
|
- REDDIT_CLIENT_SECRET=${REDDIT_CLIENT_SECRET}
|
||||||
|
- ROBLOX_CLIENT_ID=${ROBLOX_CLIENT_ID}
|
||||||
|
- ROBLOX_CLIENT_SECRET=${ROBLOX_CLIENT_SECRET}
|
||||||
|
- SPOTIFY_CLIENT_ID=${SPOTIFY_CLIENT_ID}
|
||||||
|
- SPOTIFY_CLIENT_SECRET=${SPOTIFY_CLIENT_SECRET}
|
||||||
|
- TIKTOK_CLIENT_ID=${TIKTOK_CLIENT_ID}
|
||||||
|
- TIKTOK_CLIENT_SECRET=${TIKTOK_CLIENT_SECRET}
|
||||||
|
- TIKTOK_CLIENT_KEY=${TIKTOK_CLIENT_KEY}
|
||||||
|
- TWITCH_CLIENT_ID=${TWITCH_CLIENT_ID}
|
||||||
|
- TWITCH_CLIENT_SECRET=${TWITCH_CLIENT_SECRET}
|
||||||
|
- APPLE_CLIENT_ID=${APPLE_CLIENT_ID}
|
||||||
|
- APPLE_CLIENT_SECRET=${APPLE_CLIENT_SECRET}
|
||||||
|
- APPLE_APP_BUNDLE_IDENTIFIER=${APPLE_APP_BUNDLE_IDENTIFIER}
|
||||||
- S3_ACCESS_KEY_ID=${S3_ACCESS_KEY_ID}
|
- S3_ACCESS_KEY_ID=${S3_ACCESS_KEY_ID}
|
||||||
- S3_SECRET_ACCESS_KEY=${S3_SECRET_ACCESS_KEY}
|
- S3_SECRET_ACCESS_KEY=${S3_SECRET_ACCESS_KEY}
|
||||||
- S3_REGION=${S3_REGION}
|
- S3_REGION=${S3_REGION}
|
||||||
|
|||||||
31
turbo.json
31
turbo.json
@@ -74,6 +74,37 @@
|
|||||||
"DISCORD_CLIENT_SECRET",
|
"DISCORD_CLIENT_SECRET",
|
||||||
"GITHUB_CLIENT_ID",
|
"GITHUB_CLIENT_ID",
|
||||||
"GITHUB_CLIENT_SECRET",
|
"GITHUB_CLIENT_SECRET",
|
||||||
|
"GITLAB_CLIENT_ID",
|
||||||
|
"GITLAB_CLIENT_SECRET",
|
||||||
|
"GITLAB_ISSUER",
|
||||||
|
"MICROSOFT_CLIENT_ID",
|
||||||
|
"MICROSOFT_CLIENT_SECRET",
|
||||||
|
"TWITTER_CLIENT_ID",
|
||||||
|
"TWITTER_CLIENT_SECRET",
|
||||||
|
"KICK_CLIENT_ID",
|
||||||
|
"KICK_CLIENT_SECRET",
|
||||||
|
"ZOOM_CLIENT_ID",
|
||||||
|
"ZOOM_CLIENT_SECRET",
|
||||||
|
"DROPBOX_CLIENT_ID",
|
||||||
|
"DROPBOX_CLIENT_SECRET",
|
||||||
|
"VK_CLIENT_ID",
|
||||||
|
"VK_CLIENT_SECRET",
|
||||||
|
"LINKEDIN_CLIENT_ID",
|
||||||
|
"LINKEDIN_CLIENT_SECRET",
|
||||||
|
"REDDIT_CLIENT_ID",
|
||||||
|
"REDDIT_CLIENT_SECRET",
|
||||||
|
"ROBLOX_CLIENT_ID",
|
||||||
|
"ROBLOX_CLIENT_SECRET",
|
||||||
|
"SPOTIFY_CLIENT_ID",
|
||||||
|
"SPOTIFY_CLIENT_SECRET",
|
||||||
|
"TIKTOK_CLIENT_ID",
|
||||||
|
"TIKTOK_CLIENT_SECRET",
|
||||||
|
"TIKTOK_CLIENT_KEY",
|
||||||
|
"TWITCH_CLIENT_ID",
|
||||||
|
"TWITCH_CLIENT_SECRET",
|
||||||
|
"APPLE_CLIENT_ID",
|
||||||
|
"APPLE_CLIENT_SECRET",
|
||||||
|
"APPLE_APP_BUNDLE_IDENTIFIER",
|
||||||
"EMAIL_FROM",
|
"EMAIL_FROM",
|
||||||
"SMTP_HOST",
|
"SMTP_HOST",
|
||||||
"SMTP_PORT",
|
"SMTP_PORT",
|
||||||
|
|||||||
Reference in New Issue
Block a user