diff --git a/packages/web/src/auth.ts b/packages/web/src/auth.ts
index 544976d0..68a2501e 100644
--- a/packages/web/src/auth.ts
+++ b/packages/web/src/auth.ts
@@ -13,17 +13,22 @@ import { createTransport } from 'nodemailer';
import { render } from '@react-email/render';
import MagicLinkEmail from './emails/magicLinkEmail';
import bcrypt from 'bcryptjs';
-import { getSSOProviders } from '@/ee/features/sso/sso';
+import { getEEIdentityProviders } from '@/ee/features/sso/sso';
import { hasEntitlement } from '@sourcebot/shared';
import { onCreateUser } from '@/lib/authUtils';
import { getAuditService } from '@/ee/features/audit/factory';
import { SINGLE_TENANT_ORG_ID } from './lib/constants';
const auditService = getAuditService();
-const ssoProviders = hasEntitlement("sso") ? await getSSOProviders() : [];
+const eeIdentityProviders = hasEntitlement("sso") ? await getEEIdentityProviders() : [];
export const runtime = 'nodejs';
+export type IdentityProvider = {
+ provider: Provider;
+ purpose: "sso" | "integration";
+}
+
declare module 'next-auth' {
interface Session {
user: {
@@ -33,16 +38,16 @@ declare module 'next-auth' {
}
declare module 'next-auth/jwt' {
- interface JWT {
+ interface JWT {
userId: string
}
}
export const getProviders = () => {
- const providers: Provider[] = ssoProviders;
+ const providers: IdentityProvider[] = eeIdentityProviders;
if (env.SMTP_CONNECTION_URL && env.EMAIL_FROM_ADDRESS && env.AUTH_EMAIL_CODE_LOGIN_ENABLED === 'true') {
- providers.push(EmailProvider({
+ providers.push({ provider: EmailProvider({
server: env.SMTP_CONNECTION_URL,
from: env.EMAIL_FROM_ADDRESS,
maxAge: 60 * 10,
@@ -66,11 +71,11 @@ export const getProviders = () => {
throw new Error(`Email(s) (${failed.join(", ")}) could not be sent`);
}
}
- }));
+ }), purpose: "sso"});
}
if (env.AUTH_CREDENTIALS_LOGIN_ENABLED === 'true') {
- providers.push(Credentials({
+ providers.push({ provider: Credentials({
credentials: {
email: {},
password: {}
@@ -123,7 +128,7 @@ export const getProviders = () => {
};
}
}
- }));
+ }), purpose: "sso"});
}
return providers;
@@ -193,7 +198,7 @@ export const { handlers, signIn, signOut, auth } = NextAuth({
return session;
},
},
- providers: getProviders(),
+ providers: getProviders().map((provider) => provider.provider),
pages: {
signIn: "/login",
// We set redirect to false in signInOptions so we can pass the email is as a param
diff --git a/packages/web/src/ee/features/sso/sso.ts b/packages/web/src/ee/features/sso/sso.ts
index 8a6d8856..55092032 100644
--- a/packages/web/src/ee/features/sso/sso.ts
+++ b/packages/web/src/ee/features/sso/sso.ts
@@ -1,4 +1,3 @@
-import type { Provider } from "next-auth/providers";
import { env } from "@/env.mjs";
import GitHub from "next-auth/providers/github";
import Google from "next-auth/providers/google";
@@ -14,12 +13,13 @@ import { onCreateUser } from "@/lib/authUtils";
import { createLogger } from "@sourcebot/logger";
import { hasEntitlement, loadConfig } from "@sourcebot/shared";
import { getTokenFromConfig } from "@sourcebot/crypto";
+import type { IdentityProvider } from "@/auth";
import { GCPIAPIdentityProviderConfig, GitHubIdentityProviderConfig, GitLabIdentityProviderConfig, GoogleIdentityProviderConfig, KeycloakIdentityProviderConfig, MicrosoftEntraIDIdentityProviderConfig, OktaIdentityProviderConfig } from "@sourcebot/schemas/v3/index.type";
const logger = createLogger('web-sso');
-export const getSSOProviders = async (): Promise
=> {
- const providers: Provider[] = [];
+export const getEEIdentityProviders = async (): Promise => {
+ const providers: IdentityProvider[] = [];
const config = env.CONFIG_PATH ? await loadConfig(env.CONFIG_PATH) : undefined;
const identityProviders = config?.identityProviders ?? [];
@@ -27,55 +27,49 @@ export const getSSOProviders = async (): Promise => {
for (const identityProvider of identityProviders) {
if (identityProvider.provider === "github") {
const providerConfig = identityProvider as GitHubIdentityProviderConfig;
- if (providerConfig.purpose !== "sso") {
- continue;
- }
const clientId = await getTokenFromConfig(providerConfig.clientId);
const clientSecret = await getTokenFromConfig(providerConfig.clientSecret);
const baseUrl = providerConfig.baseUrl ? await getTokenFromConfig(providerConfig.baseUrl) : undefined;
- providers.push(createGitHubProvider(clientId, clientSecret, baseUrl));
+ providers.push({ provider: createGitHubProvider(clientId, clientSecret, baseUrl), purpose: providerConfig.purpose });
}
if (identityProvider.provider === "gitlab") {
const providerConfig = identityProvider as GitLabIdentityProviderConfig;
- if (providerConfig.purpose !== "sso") {
- continue;
- }
const clientId = await getTokenFromConfig(providerConfig.clientId);
const clientSecret = await getTokenFromConfig(providerConfig.clientSecret);
const baseUrl = providerConfig.baseUrl ? await getTokenFromConfig(providerConfig.baseUrl) : undefined;
- providers.push(createGitLabProvider(clientId, clientSecret, baseUrl));
+ providers.push({ provider: createGitLabProvider(clientId, clientSecret, baseUrl), purpose: providerConfig.purpose });
}
if (identityProvider.provider === "google") {
const providerConfig = identityProvider as GoogleIdentityProviderConfig;
const clientId = await getTokenFromConfig(providerConfig.clientId);
const clientSecret = await getTokenFromConfig(providerConfig.clientSecret);
- providers.push(createGoogleProvider(clientId, clientSecret));
+ providers.push({ provider: createGoogleProvider(clientId, clientSecret), purpose: "sso"});
}
if (identityProvider.provider === "okta") {
const providerConfig = identityProvider as OktaIdentityProviderConfig;
const clientId = await getTokenFromConfig(providerConfig.clientId);
const clientSecret = await getTokenFromConfig(providerConfig.clientSecret);
const issuer = await getTokenFromConfig(providerConfig.issuer);
- providers.push(createOktaProvider(clientId, clientSecret, issuer));
+ providers.push({ provider: createOktaProvider(clientId, clientSecret, issuer), purpose: "sso"});
}
if (identityProvider.provider === "keycloak") {
const providerConfig = identityProvider as KeycloakIdentityProviderConfig;
const clientId = await getTokenFromConfig(providerConfig.clientId);
const clientSecret = await getTokenFromConfig(providerConfig.clientSecret);
const issuer = await getTokenFromConfig(providerConfig.issuer);
- providers.push(createKeycloakProvider(clientId, clientSecret, issuer));
+ providers.push({ provider: createKeycloakProvider(clientId, clientSecret, issuer), purpose: "sso"});
}
if (identityProvider.provider === "microsoft-entra-id") {
const providerConfig = identityProvider as MicrosoftEntraIDIdentityProviderConfig;
const clientId = await getTokenFromConfig(providerConfig.clientId);
const clientSecret = await getTokenFromConfig(providerConfig.clientSecret);
const issuer = await getTokenFromConfig(providerConfig.issuer);
- providers.push(createMicrosoftEntraIDProvider(clientId, clientSecret, issuer));
+ providers.push({ provider: createMicrosoftEntraIDProvider(clientId, clientSecret, issuer), purpose: "sso"});
}
if (identityProvider.provider === "gcp-iap") {
const providerConfig = identityProvider as GCPIAPIdentityProviderConfig;
const audience = await getTokenFromConfig(providerConfig.audience);
- providers.push(createGCPIAPProvider(audience));
+ providers.push({ provider: createGCPIAPProvider(audience), purpose: "sso"});
}
}
diff --git a/packages/web/src/lib/authProviders.ts b/packages/web/src/lib/authProviders.ts
index ca2a6697..efcb54ff 100644
--- a/packages/web/src/lib/authProviders.ts
+++ b/packages/web/src/lib/authProviders.ts
@@ -1,18 +1,19 @@
import { getProviders } from "@/auth";
-export interface AuthProvider {
+export interface IdentityProviderMetadata {
id: string;
name: string;
+ purpose: "sso" | "integration";
}
-export const getAuthProviders = (): AuthProvider[] => {
+export const getIdentityProviderMetadata = (): IdentityProviderMetadata[] => {
const providers = getProviders();
return providers.map((provider) => {
- if (typeof provider === "function") {
- const providerInfo = provider();
- return { id: providerInfo.id, name: providerInfo.name };
+ if (typeof provider.provider === "function") {
+ const providerInfo = provider.provider();
+ return { id: providerInfo.id, name: providerInfo.name, purpose: provider.purpose };
} else {
- return { id: provider.id, name: provider.name };
+ return { id: provider.provider.id, name: provider.provider.name, purpose: provider.purpose };
}
});
};
\ No newline at end of file