diff --git a/src/components/auth/SocialLoginButtons.tsx b/src/components/auth/SocialLoginButtons.tsx new file mode 100644 index 0000000..1f1d371 --- /dev/null +++ b/src/components/auth/SocialLoginButtons.tsx @@ -0,0 +1,100 @@ +import { Fingerprint } from "lucide-react"; +import { Button } from "@/components/ui/button"; +import { Separator } from "@/components/ui/separator"; + +interface SocialLoginButtonsProps { + isLoading: boolean; + onProviderLogin: (provider: "google" | "github" | "microsoft") => Promise; + onPasskeyLogin: () => Promise; + oidcSessionId?: string | null; +} + +export function SocialLoginButtons({ + isLoading, + onProviderLogin, + onPasskeyLogin, +}: SocialLoginButtonsProps) { + return ( + <> +
+ + + or continue with + +
+ +
+ + +
+ + + +
+
+ + ); +} diff --git a/src/pages/auth/LoginPage.tsx b/src/pages/auth/LoginPage.tsx index 92387c7..7d36387 100644 --- a/src/pages/auth/LoginPage.tsx +++ b/src/pages/auth/LoginPage.tsx @@ -25,6 +25,7 @@ import { AddPasskeyWizard } from "@/components/security/AddPasskeyWizard"; import { TotpEnrollmentWizard } from "@/components/security/TotpEnrollmentWizard"; import { OAuthProvider } from "@/lib/oauth"; import { config } from "@/config"; +import { SocialLoginButtons } from "@/components/auth/SocialLoginButtons"; /** * Complete an OIDC authorization flow after the user has authenticated. @@ -1023,86 +1024,7 @@ export default function LoginPage() { -
- - - or continue with - -
- - {/* Alternative login methods */} -
- - -
- - - -
-
+

Don't have an account?{" "} diff --git a/src/pages/auth/OIDCLoginPage.tsx b/src/pages/auth/OIDCLoginPage.tsx index ba8ac24..182d120 100644 --- a/src/pages/auth/OIDCLoginPage.tsx +++ b/src/pages/auth/OIDCLoginPage.tsx @@ -33,8 +33,10 @@ import { Label } from "@/components/ui/label"; import { Card } from "@/components/ui/card"; import { Separator } from "@/components/ui/separator"; import { Badge } from "@/components/ui/badge"; +import { SocialLoginButtons } from "@/components/auth/SocialLoginButtons"; import { useAuth } from "@/contexts/AuthContext"; -import { ApiError, tokenManager } from "@/lib/api"; +import { api, ApiError, tokenManager } from "@/lib/api"; +import { OAuthProvider } from "@/lib/oauth"; import { config } from "@/config"; // ── Scope display metadata ──────────────────────────────────────────────────── @@ -196,6 +198,28 @@ export default function OIDCLoginPage() { setLoginError(null); }; + // ── OAuth login ────────────────────────────────────────────────────────────── + const handleOAuthLogin = async (provider: OAuthProvider) => { + setIsSubmitting(true); + try { + const response = await api.externalAuth.initiateLogin(provider, { + flow: 'login', + oidc_session_id: oidcSessionId, + }); + window.location.href = response.authorization_url; + } catch (err) { + const message = err instanceof ApiError ? err.message : err instanceof Error ? err.message : "Failed to initiate social login"; + setLoginError(message); + setIsSubmitting(false); + } + }; + + // ── Passkey login ───────────────────────────────────────────────────────────── + const handlePasskeyLogin = async () => { + // For OIDC flow, passkey login redirects to main login page with OIDC context + navigate(`/login?oidc_session_id=${oidcSessionId}`); + }; + // ── Render: loading ────────────────────────────────────────────────────────── if (step === "loading") { return ( @@ -325,6 +349,13 @@ export default function OIDCLoginPage() { + +