From 3bb45e1514c485e441c94b121fff70e4be316da3 Mon Sep 17 00:00:00 2001 From: Flavien David Date: Thu, 7 Mar 2024 18:57:13 +0100 Subject: [PATCH] Improve SSO login flow (#4206) * Improve SSO login flow * Expose initiate login url in SSO drawer * :sparkles: --- front/components/workspace/connection.tsx | 23 ++++++++++------- front/lib/api/config.ts | 3 +++ front/lib/api/enterprise_connection.ts | 30 +++++++++++++++++------ front/pages/api/auth/[auth0].ts | 18 +++++++++++--- front/pages/w/[wId]/members/index.tsx | 5 +++- 5 files changed, 58 insertions(+), 21 deletions(-) diff --git a/front/components/workspace/connection.tsx b/front/components/workspace/connection.tsx index f8496beb08a0..b30426c1b574 100644 --- a/front/components/workspace/connection.tsx +++ b/front/components/workspace/connection.tsx @@ -28,8 +28,9 @@ interface EnterpriseConnectionDetailsProps { } export interface EnterpriseConnectionStrategyDetails { - strategy: SupportedEnterpriseConnectionStrategies; callbackUrl: string; + initiateLoginUrl: string; + strategy: SupportedEnterpriseConnectionStrategies; } export function EnterpriseConnectionDetails({ @@ -170,7 +171,7 @@ function CreateOktaEnterpriseConnectionModal({ domain?: string; }>({}); - const { callbackUrl } = strategyDetails; + const { callbackUrl, initiateLoginUrl } = strategyDetails; const sendNotification = useContext(SendNotificationsContext); @@ -225,15 +226,19 @@ function CreateOktaEnterpriseConnectionModal({ Callback URL: - setEnterpriseConnectionDetails({ - ...enterpriseConnectionDetails, - domain: value, - }) - } + className="max-w-sm" + /> + + + Initiate login URI: + diff --git a/front/lib/api/config.ts b/front/lib/api/config.ts index a829a1f02776..e68d2a977d30 100644 --- a/front/lib/api/config.ts +++ b/front/lib/api/config.ts @@ -1,6 +1,9 @@ import { EnvironmentConfig } from "@dust-tt/types"; const config = { + getAppUrl: (): string => { + return EnvironmentConfig.getEnvVariable("URL"); + }, getAuth0TenantUrl: (): string => { return EnvironmentConfig.getEnvVariable("AUTH0_TENANT_DOMAIN_URL"); }, diff --git a/front/lib/api/enterprise_connection.ts b/front/lib/api/enterprise_connection.ts index 39d8a8e8e7d5..fae75505ac61 100644 --- a/front/lib/api/enterprise_connection.ts +++ b/front/lib/api/enterprise_connection.ts @@ -5,16 +5,30 @@ import { ManagementClient } from "auth0"; import config from "@app/lib/api/config"; import type { Authenticator } from "@app/lib/auth"; -const management = new ManagementClient({ - domain: config.getAuth0TenantUrl(), - clientId: config.getAuth0M2MClientId(), - clientSecret: config.getAuth0M2MClientSecret(), -}); +let auth0ManagemementClient: ManagementClient | null = null; + +function getAuth0ManagemementClient(): ManagementClient { + if (!auth0ManagemementClient) { + auth0ManagemementClient = new ManagementClient({ + domain: config.getAuth0TenantUrl(), + clientId: config.getAuth0M2MClientId(), + clientSecret: config.getAuth0M2MClientSecret(), + }); + } + + return auth0ManagemementClient; +} function makeEnterpriseConnectionName(workspaceId: string) { return `workspace-${workspaceId}`; } +export function makeEnterpriseConnectionInitiateLoginUrl(workspaceId: string) { + return `${config.getAppUrl()}/api/auth/login?connection=${makeEnterpriseConnectionName( + workspaceId + )}`; +} + export async function getEnterpriseConnectionForWorkspace( auth: Authenticator, strategy: SupportedEnterpriseConnectionStrategies = "okta" @@ -26,7 +40,7 @@ export async function getEnterpriseConnectionForWorkspace( // This endpoint supports fetching up to 1000 connections in one page. // In the future, consider implementing pagination to handle larger datasets. - const connections = await management.connections.getAll({ + const connections = await getAuth0ManagemementClient().connections.getAll({ strategy: [strategy], }); @@ -54,7 +68,7 @@ export async function createEnterpriseConnection( } const { sId } = owner; - const connection = await management.connections.create({ + const connection = await getAuth0ManagemementClient().connections.create({ name: makeEnterpriseConnectionName(sId), display_name: makeEnterpriseConnectionName(sId), strategy: connectionDetails.strategy, @@ -93,7 +107,7 @@ export async function deleteEnterpriseConnection( throw new Error("Enterprise connection not found."); } - return management.connections.delete({ + return getAuth0ManagemementClient().connections.delete({ id: existingConnection.id, }); } diff --git a/front/pages/api/auth/[auth0].ts b/front/pages/api/auth/[auth0].ts index af491266e2a3..ee0004268545 100644 --- a/front/pages/api/auth/[auth0].ts +++ b/front/pages/api/auth/[auth0].ts @@ -1,9 +1,21 @@ import { handleAuth, handleLogin } from "@auth0/nextjs-auth0"; +import type { AuthorizationParameters } from "@auth0/nextjs-auth0/dist/auth0-session"; export default handleAuth({ - login: handleLogin({ - authorizationParams: { + login: handleLogin((req) => { + const connection = "query" in req ? req.query.connection : undefined; + + const defaultAuthorizationParams: Partial = { scope: "openid profile email", - }, + }; + + // Set the Auth0 connection based on the provided connection param, redirecting the user to the correct screen. + if (connection) { + defaultAuthorizationParams.connection = connection; + } + + return { + authorizationParams: defaultAuthorizationParams, + }; }), }); diff --git a/front/pages/w/[wId]/members/index.tsx b/front/pages/w/[wId]/members/index.tsx index dcb0c6eda8c5..83a7bd635366 100644 --- a/front/pages/w/[wId]/members/index.tsx +++ b/front/pages/w/[wId]/members/index.tsx @@ -35,6 +35,7 @@ import { SendNotificationsContext } from "@app/components/sparkle/Notification"; import type { EnterpriseConnectionStrategyDetails } from "@app/components/workspace/connection"; import { EnterpriseConnectionDetails } from "@app/components/workspace/connection"; import config from "@app/lib/api/config"; +import { makeEnterpriseConnectionInitiateLoginUrl } from "@app/lib/api/enterprise_connection"; import { checkWorkspaceSeatAvailabilityUsingAuth, getWorkspaceVerifiedDomain, @@ -80,9 +81,11 @@ export const getServerSideProps = withDefaultGetServerSidePropsRequirements<{ const enterpriseConnectionStrategyDetails: EnterpriseConnectionStrategyDetails = { - strategy: "okta", callbackUrl: config.getAuth0TenantUrl(), + initiateLoginUrl: makeEnterpriseConnectionInitiateLoginUrl(owner.sId), + strategy: "okta", }; + return { props: { user,