Skip to content

Commit a2e0626

Browse files
committed
fix issue with new auth providers not being shown in login page
1 parent 97a2a3e commit a2e0626

File tree

8 files changed

+177
-46
lines changed

8 files changed

+177
-46
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Fixed
11+
- Fixed issue where new oauth providers weren't being display in the login page
12+
1013
## [4.0.1] - 2025-05-28
1114

1215
### Fixed

packages/web/public/keycloak.svg

Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 9 additions & 0 deletions
Loading

packages/web/public/okta.svg

Lines changed: 3 additions & 0 deletions
Loading

packages/web/src/app/login/components/loginForm.tsx

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
'use client';
22

33
import { Button } from "@/components/ui/button";
4-
import googleLogo from "@/public/google.svg";
54
import Image from "next/image";
65
import { signIn } from "next-auth/react";
76
import { Fragment, useCallback, useMemo } from "react";
87
import { Card } from "@/components/ui/card";
9-
import { cn, getCodeHostIcon } from "@/lib/utils";
8+
import { cn, getAuthProviderInfo } from "@/lib/utils";
109
import { MagicLinkForm } from "./magicLinkForm";
1110
import { CredentialsForm } from "./credentialsForm";
1211
import { SourcebotLogo } from "@/app/components/sourcebotLogo";
@@ -22,15 +21,10 @@ const PRIVACY_POLICY_URL = "https://sourcebot.dev/privacy";
2221
interface LoginFormProps {
2322
callbackUrl?: string;
2423
error?: string;
25-
enabledMethods: {
26-
github: boolean;
27-
google: boolean;
28-
magicLink: boolean;
29-
credentials: boolean;
30-
}
24+
providers: Array<{ id: string; name: string }>;
3125
}
3226

33-
export const LoginForm = ({ callbackUrl, error, enabledMethods }: LoginFormProps) => {
27+
export const LoginForm = ({ callbackUrl, error, providers }: LoginFormProps) => {
3428
const captureEvent = useCaptureEvent();
3529
const onSignInWithOauth = useCallback((provider: string) => {
3630
signIn(provider, { redirectTo: callbackUrl ?? "/" });
@@ -50,6 +44,33 @@ export const LoginForm = ({ callbackUrl, error, enabledMethods }: LoginFormProps
5044
}
5145
}, [error]);
5246

47+
// Separate OAuth providers from special auth methods
48+
const oauthProviders = providers.filter(p =>
49+
!["credentials", "nodemailer"].includes(p.id)
50+
);
51+
const hasCredentials = providers.some(p => p.id === "credentials");
52+
const hasMagicLink = providers.some(p => p.id === "nodemailer");
53+
54+
// Helper function to get the correct analytics event name
55+
const getLoginEventName = (providerId: string) => {
56+
switch (providerId) {
57+
case "github":
58+
return "wa_login_with_github" as const;
59+
case "google":
60+
return "wa_login_with_google" as const;
61+
case "gitlab":
62+
return "wa_login_with_gitlab" as const;
63+
case "okta":
64+
return "wa_login_with_okta" as const;
65+
case "keycloak":
66+
return "wa_login_with_keycloak" as const;
67+
case "microsoft-entra-id":
68+
return "wa_login_with_microsoft_entra_id" as const;
69+
default:
70+
return "wa_login_with_github" as const; // fallback
71+
}
72+
};
73+
5374
return (
5475
<div className="flex flex-col items-center justify-center w-full">
5576
<div className="mb-6 flex flex-col items-center">
@@ -71,36 +92,28 @@ export const LoginForm = ({ callbackUrl, error, enabledMethods }: LoginFormProps
7192
)}
7293
<DividerSet
7394
elements={[
74-
...(enabledMethods.github || enabledMethods.google ? [
75-
<>
76-
{enabledMethods.github && (
77-
<ProviderButton
78-
key="github"
79-
name="GitHub"
80-
logo={getCodeHostIcon("github")!}
81-
onClick={() => {
82-
captureEvent("wa_login_with_github", {});
83-
onSignInWithOauth("github")
84-
}}
85-
/>
86-
)}
87-
{enabledMethods.google && (
88-
<ProviderButton
89-
key="google"
90-
name="Google"
91-
logo={{ src: googleLogo }}
92-
onClick={() => {
93-
captureEvent("wa_login_with_google", {});
94-
onSignInWithOauth("google")
95-
}}
96-
/>
97-
)}
98-
</>
95+
...(oauthProviders.length > 0 ? [
96+
<div key="oauth-providers" className="w-full space-y-3">
97+
{oauthProviders.map((provider) => {
98+
const providerInfo = getAuthProviderInfo(provider.id);
99+
return (
100+
<ProviderButton
101+
key={provider.id}
102+
name={providerInfo.displayName}
103+
logo={providerInfo.icon}
104+
onClick={() => {
105+
captureEvent(getLoginEventName(provider.id), {});
106+
onSignInWithOauth(provider.id);
107+
}}
108+
/>
109+
);
110+
})}
111+
</div>
99112
] : []),
100-
...(enabledMethods.magicLink ? [
113+
...(hasMagicLink ? [
101114
<MagicLinkForm key="magic-link" callbackUrl={callbackUrl} />
102115
] : []),
103-
...(enabledMethods.credentials ? [
116+
...(hasCredentials ? [
104117
<CredentialsForm key="credentials" callbackUrl={callbackUrl} />
105118
] : [])
106119
]}
@@ -120,7 +133,7 @@ const ProviderButton = ({
120133
className,
121134
}: {
122135
name: string;
123-
logo: { src: string, className?: string };
136+
logo: { src: string, className?: string } | null;
124137
onClick: () => void;
125138
className?: string;
126139
}) => {

packages/web/src/app/login/page.tsx

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ export default async function Login({ searchParams }: LoginProps) {
2020
}
2121

2222
const providers = getProviders();
23-
const providerMap = providers
23+
const providerData = providers
2424
.map((provider) => {
2525
if (typeof provider === "function") {
26-
const providerData = provider()
27-
return { id: providerData.id, name: providerData.name }
26+
const providerInfo = provider()
27+
return { id: providerInfo.id, name: providerInfo.name }
2828
} else {
2929
return { id: provider.id, name: provider.name }
3030
}
@@ -36,12 +36,7 @@ export default async function Login({ searchParams }: LoginProps) {
3636
<LoginForm
3737
callbackUrl={searchParams.callbackUrl}
3838
error={searchParams.error}
39-
enabledMethods={{
40-
github: providerMap.some(provider => provider.id === "github"),
41-
google: providerMap.some(provider => provider.id === "google"),
42-
magicLink: providerMap.some(provider => provider.id === "nodemailer"),
43-
credentials: providerMap.some(provider => provider.id === "credentials"),
44-
}}
39+
providers={providerData}
4540
/>
4641
</div>
4742
<Footer />

packages/web/src/lib/posthogEvents.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,10 @@ export type PosthogEventMap = {
216216
//////////////////////////////////////////////////////////////////
217217
wa_login_with_github: {},
218218
wa_login_with_google: {},
219+
wa_login_with_gitlab: {},
220+
wa_login_with_okta: {},
221+
wa_login_with_keycloak: {},
222+
wa_login_with_microsoft_entra_id: {},
219223
wa_login_with_magic_link: {},
220224
wa_login_with_credentials: {},
221225
//////////////////////////////////////////////////////////////////

packages/web/src/lib/utils.ts

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import giteaLogo from "@/public/gitea.svg";
66
import gerritLogo from "@/public/gerrit.svg";
77
import bitbucketLogo from "@/public/bitbucket.svg";
88
import gitLogo from "@/public/git.svg";
9+
import googleLogo from "@/public/google.svg";
10+
import oktaLogo from "@/public/okta.svg";
11+
import keycloakLogo from "@/public/keycloak.svg";
12+
import microsoftLogo from "@/public/microsoft_entra.svg";
913
import { ServiceError } from "./serviceError";
1014
import { StatusCodes } from "http-status-codes";
1115
import { ErrorCode } from "./errorCodes";
@@ -44,6 +48,105 @@ export type CodeHostType =
4448
"bitbucket-server" |
4549
"generic-git-host";
4650

51+
export type AuthProviderType =
52+
"github" |
53+
"gitlab" |
54+
"google" |
55+
"okta" |
56+
"keycloak" |
57+
"microsoft-entra-id" |
58+
"credentials" |
59+
"nodemailer";
60+
61+
type AuthProviderInfo = {
62+
id: string;
63+
name: string;
64+
displayName: string;
65+
icon: { src: string; className?: string } | null;
66+
}
67+
68+
export const getAuthProviderInfo = (providerId: string): AuthProviderInfo => {
69+
switch (providerId) {
70+
case "github":
71+
return {
72+
id: "github",
73+
name: "GitHub",
74+
displayName: "GitHub",
75+
icon: {
76+
src: githubLogo,
77+
className: "dark:invert",
78+
},
79+
};
80+
case "gitlab":
81+
return {
82+
id: "gitlab",
83+
name: "GitLab",
84+
displayName: "GitLab",
85+
icon: {
86+
src: gitlabLogo,
87+
},
88+
};
89+
case "google":
90+
return {
91+
id: "google",
92+
name: "Google",
93+
displayName: "Google",
94+
icon: {
95+
src: googleLogo,
96+
},
97+
};
98+
case "okta":
99+
return {
100+
id: "okta",
101+
name: "Okta",
102+
displayName: "Okta",
103+
icon: {
104+
src: oktaLogo,
105+
className: "dark:invert",
106+
},
107+
};
108+
case "keycloak":
109+
return {
110+
id: "keycloak",
111+
name: "Keycloak",
112+
displayName: "Keycloak",
113+
icon: {
114+
src: keycloakLogo,
115+
},
116+
};
117+
case "microsoft-entra-id":
118+
return {
119+
id: "microsoft-entra-id",
120+
name: "Microsoft Entra ID",
121+
displayName: "Microsoft Entra ID",
122+
icon: {
123+
src: microsoftLogo,
124+
},
125+
};
126+
case "credentials":
127+
return {
128+
id: "credentials",
129+
name: "Credentials",
130+
displayName: "Email & Password",
131+
icon: null, // No icon needed for credentials
132+
};
133+
case "nodemailer":
134+
return {
135+
id: "nodemailer",
136+
name: "Email",
137+
displayName: "Email Code",
138+
icon: null, // No icon needed for email
139+
};
140+
default:
141+
return {
142+
id: providerId,
143+
name: providerId,
144+
displayName: providerId.charAt(0).toUpperCase() + providerId.slice(1),
145+
icon: null,
146+
};
147+
}
148+
};
149+
47150
type CodeHostInfo = {
48151
type: CodeHostType;
49152
displayName: string;

0 commit comments

Comments
 (0)