From a99e7e24cc724596dfe2706f3cd9cb3a944e4fbc Mon Sep 17 00:00:00 2001 From: x032205 Date: Thu, 17 Jul 2025 22:52:56 -0400 Subject: [PATCH] feat(app-connection): Okta App Connection --- backend/src/lib/api-docs/constants.ts | 4 + .../app-connection-router.ts | 7 +- .../routes/v1/app-connection-routers/index.ts | 4 +- .../okta-connection-router.ts | 52 ++++++ .../app-connection/app-connection-enums.ts | 3 +- .../app-connection/app-connection-fns.ts | 11 +- .../app-connection/app-connection-maps.ts | 6 +- .../app-connection/app-connection-service.ts | 8 +- .../app-connection/app-connection-types.ts | 14 +- .../src/services/app-connection/okta/index.ts | 4 + .../okta/okta-connection-enums.ts | 3 + .../okta/okta-connection-fns.ts | 57 +++++++ .../okta/okta-connection-schemas.ts | 69 ++++++++ .../okta/okta-connection-service.ts | 23 +++ .../okta/okta-connection-types.ts | 28 ++++ frontend/public/images/integrations/Okta.png | Bin 0 -> 63604 bytes frontend/src/helpers/appConnections.ts | 19 ++- .../src/hooks/api/appConnections/enums.ts | 3 +- .../hooks/api/appConnections/okta/index.ts | 2 + .../hooks/api/appConnections/okta/queries.tsx | 36 ++++ .../hooks/api/appConnections/okta/types.ts | 4 + .../api/appConnections/types/app-options.ts | 8 +- .../hooks/api/appConnections/types/index.ts | 9 +- .../appConnections/types/okta-connection.ts | 14 ++ .../AppConnectionForm/AppConnectionForm.tsx | 5 + .../AppConnectionForm/OktaConnectionForm.tsx | 157 ++++++++++++++++++ 26 files changed, 526 insertions(+), 24 deletions(-) create mode 100644 backend/src/server/routes/v1/app-connection-routers/okta-connection-router.ts create mode 100644 backend/src/services/app-connection/okta/index.ts create mode 100644 backend/src/services/app-connection/okta/okta-connection-enums.ts create mode 100644 backend/src/services/app-connection/okta/okta-connection-fns.ts create mode 100644 backend/src/services/app-connection/okta/okta-connection-schemas.ts create mode 100644 backend/src/services/app-connection/okta/okta-connection-service.ts create mode 100644 backend/src/services/app-connection/okta/okta-connection-types.ts create mode 100644 frontend/public/images/integrations/Okta.png create mode 100644 frontend/src/hooks/api/appConnections/okta/index.ts create mode 100644 frontend/src/hooks/api/appConnections/okta/queries.tsx create mode 100644 frontend/src/hooks/api/appConnections/okta/types.ts create mode 100644 frontend/src/hooks/api/appConnections/types/okta-connection.ts create mode 100644 frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/OktaConnectionForm.tsx diff --git a/backend/src/lib/api-docs/constants.ts b/backend/src/lib/api-docs/constants.ts index 584f480ad..43f078123 100644 --- a/backend/src/lib/api-docs/constants.ts +++ b/backend/src/lib/api-docs/constants.ts @@ -2289,6 +2289,10 @@ export const AppConnections = { SUPABASE: { accessKey: "The Key used to access Supabase.", instanceUrl: "The URL used to access Supabase." + }, + OKTA: { + instanceUrl: "The URL used to access your Okta organization.", + apiToken: "The API token used to authenticate with Okta." } } }; diff --git a/backend/src/server/routes/v1/app-connection-routers/app-connection-router.ts b/backend/src/server/routes/v1/app-connection-routers/app-connection-router.ts index 7c1b52edd..ba0826f87 100644 --- a/backend/src/server/routes/v1/app-connection-routers/app-connection-router.ts +++ b/backend/src/server/routes/v1/app-connection-routers/app-connection-router.ts @@ -71,6 +71,7 @@ import { import { LdapConnectionListItemSchema, SanitizedLdapConnectionSchema } from "@app/services/app-connection/ldap"; import { MsSqlConnectionListItemSchema, SanitizedMsSqlConnectionSchema } from "@app/services/app-connection/mssql"; import { MySqlConnectionListItemSchema, SanitizedMySqlConnectionSchema } from "@app/services/app-connection/mysql"; +import { OktaConnectionListItemSchema, SanitizedOktaConnectionSchema } from "@app/services/app-connection/okta"; import { PostgresConnectionListItemSchema, SanitizedPostgresConnectionSchema @@ -138,7 +139,8 @@ const SanitizedAppConnectionSchema = z.union([ ...SanitizedZabbixConnectionSchema.options, ...SanitizedRailwayConnectionSchema.options, ...SanitizedChecklyConnectionSchema.options, - ...SanitizedSupabaseConnectionSchema.options + ...SanitizedSupabaseConnectionSchema.options, + ...SanitizedOktaConnectionSchema.options ]); const AppConnectionOptionsSchema = z.discriminatedUnion("app", [ @@ -175,7 +177,8 @@ const AppConnectionOptionsSchema = z.discriminatedUnion("app", [ ZabbixConnectionListItemSchema, RailwayConnectionListItemSchema, ChecklyConnectionListItemSchema, - SupabaseConnectionListItemSchema + SupabaseConnectionListItemSchema, + OktaConnectionListItemSchema ]); export const registerAppConnectionRouter = async (server: FastifyZodProvider) => { diff --git a/backend/src/server/routes/v1/app-connection-routers/index.ts b/backend/src/server/routes/v1/app-connection-routers/index.ts index 287a406f6..3bbdc363d 100644 --- a/backend/src/server/routes/v1/app-connection-routers/index.ts +++ b/backend/src/server/routes/v1/app-connection-routers/index.ts @@ -25,6 +25,7 @@ import { registerHumanitecConnectionRouter } from "./humanitec-connection-router import { registerLdapConnectionRouter } from "./ldap-connection-router"; import { registerMsSqlConnectionRouter } from "./mssql-connection-router"; import { registerMySqlConnectionRouter } from "./mysql-connection-router"; +import { registerOktaConnectionRouter } from "./okta-connection-router"; import { registerPostgresConnectionRouter } from "./postgres-connection-router"; import { registerRailwayConnectionRouter } from "./railway-connection-router"; import { registerRenderConnectionRouter } from "./render-connection-router"; @@ -72,5 +73,6 @@ export const APP_CONNECTION_REGISTER_ROUTER_MAP: Record { + registerAppConnectionEndpoints({ + app: AppConnection.Okta, + server, + sanitizedResponseSchema: SanitizedOktaConnectionSchema, + createSchema: CreateOktaConnectionSchema, + updateSchema: UpdateOktaConnectionSchema + }); + + // The below endpoints are not exposed and for Infisical App use + + server.route({ + method: "GET", + url: `/:connectionId/apps`, + config: { + rateLimit: readLimit + }, + schema: { + params: z.object({ + connectionId: z.string().uuid() + }), + response: { + 200: z.object({ + apps: z.object({ id: z.string(), label: z.string() }).array() + }) + } + }, + onRequest: verifyAuth([AuthMode.JWT]), + handler: async (req) => { + const { + params: { connectionId } + } = req; + + const apps = await server.services.appConnection.okta.listApps(connectionId, req.permission); + return { apps }; + } + }); +}; diff --git a/backend/src/services/app-connection/app-connection-enums.ts b/backend/src/services/app-connection/app-connection-enums.ts index 233ce0ea8..7fcdc7217 100644 --- a/backend/src/services/app-connection/app-connection-enums.ts +++ b/backend/src/services/app-connection/app-connection-enums.ts @@ -32,7 +32,8 @@ export enum AppConnection { Railway = "railway", Bitbucket = "bitbucket", Checkly = "checkly", - Supabase = "supabase" + Supabase = "supabase", + Okta = "okta" } export enum AWSRegion { diff --git a/backend/src/services/app-connection/app-connection-fns.ts b/backend/src/services/app-connection/app-connection-fns.ts index 10bab521e..b63ecdfd7 100644 --- a/backend/src/services/app-connection/app-connection-fns.ts +++ b/backend/src/services/app-connection/app-connection-fns.ts @@ -118,6 +118,7 @@ import { WindmillConnectionMethod } from "./windmill"; import { getZabbixConnectionListItem, validateZabbixConnectionCredentials, ZabbixConnectionMethod } from "./zabbix"; +import { getOktaConnectionListItem, OktaConnectionMethod, validateOktaConnectionCredentials } from "./okta"; export const listAppConnectionOptions = () => { return [ @@ -154,7 +155,8 @@ export const listAppConnectionOptions = () => { getRailwayConnectionListItem(), getBitbucketConnectionListItem(), getChecklyConnectionListItem(), - getSupabaseConnectionListItem() + getSupabaseConnectionListItem(), + getOktaConnectionListItem() ].sort((a, b) => a.name.localeCompare(b.name)); }; @@ -239,7 +241,8 @@ export const validateAppConnectionCredentials = async ( [AppConnection.Railway]: validateRailwayConnectionCredentials as TAppConnectionCredentialsValidator, [AppConnection.Bitbucket]: validateBitbucketConnectionCredentials as TAppConnectionCredentialsValidator, [AppConnection.Checkly]: validateChecklyConnectionCredentials as TAppConnectionCredentialsValidator, - [AppConnection.Supabase]: validateSupabaseConnectionCredentials as TAppConnectionCredentialsValidator + [AppConnection.Supabase]: validateSupabaseConnectionCredentials as TAppConnectionCredentialsValidator, + [AppConnection.Okta]: validateOktaConnectionCredentials as TAppConnectionCredentialsValidator }; return VALIDATE_APP_CONNECTION_CREDENTIALS_MAP[appConnection.app](appConnection); @@ -278,6 +281,7 @@ export const getAppConnectionMethodName = (method: TAppConnection["method"]) => case CloudflareConnectionMethod.APIToken: case BitbucketConnectionMethod.ApiToken: case ZabbixConnectionMethod.ApiToken: + case OktaConnectionMethod.ApiToken: return "API Token"; case PostgresConnectionMethod.UsernameAndPassword: case MsSqlConnectionMethod.UsernameAndPassword: @@ -365,7 +369,8 @@ export const TRANSITION_CONNECTION_CREDENTIALS_TO_PLATFORM: Record< [AppConnection.Railway]: platformManagedCredentialsNotSupported, [AppConnection.Bitbucket]: platformManagedCredentialsNotSupported, [AppConnection.Checkly]: platformManagedCredentialsNotSupported, - [AppConnection.Supabase]: platformManagedCredentialsNotSupported + [AppConnection.Supabase]: platformManagedCredentialsNotSupported, + [AppConnection.Okta]: platformManagedCredentialsNotSupported }; export const enterpriseAppCheck = async ( diff --git a/backend/src/services/app-connection/app-connection-maps.ts b/backend/src/services/app-connection/app-connection-maps.ts index 8a85020d8..03b979312 100644 --- a/backend/src/services/app-connection/app-connection-maps.ts +++ b/backend/src/services/app-connection/app-connection-maps.ts @@ -34,7 +34,8 @@ export const APP_CONNECTION_NAME_MAP: Record = { [AppConnection.Railway]: "Railway", [AppConnection.Bitbucket]: "Bitbucket", [AppConnection.Checkly]: "Checkly", - [AppConnection.Supabase]: "Supabase" + [AppConnection.Supabase]: "Supabase", + [AppConnection.Okta]: "Okta" }; export const APP_CONNECTION_PLAN_MAP: Record = { @@ -71,5 +72,6 @@ export const APP_CONNECTION_PLAN_MAP: Record>>; @@ -272,6 +279,7 @@ export type TAppConnectionInput = { id: string } & ( | TRailwayConnectionInput | TChecklyConnectionInput | TSupabaseConnectionInput + | TOktaConnectionInput ); export type TSqlConnectionInput = @@ -320,7 +328,8 @@ export type TAppConnectionConfig = | TZabbixConnectionConfig | TRailwayConnectionConfig | TChecklyConnectionConfig - | TSupabaseConnectionConfig; + | TSupabaseConnectionConfig + | TOktaConnectionConfig; export type TValidateAppConnectionCredentialsSchema = | TValidateAwsConnectionCredentialsSchema @@ -356,7 +365,8 @@ export type TValidateAppConnectionCredentialsSchema = | TValidateZabbixConnectionCredentialsSchema | TValidateRailwayConnectionCredentialsSchema | TValidateChecklyConnectionCredentialsSchema - | TValidateSupabaseConnectionCredentialsSchema; + | TValidateSupabaseConnectionCredentialsSchema + | TValidateOktaConnectionCredentialsSchema; export type TListAwsConnectionKmsKeys = { connectionId: string; diff --git a/backend/src/services/app-connection/okta/index.ts b/backend/src/services/app-connection/okta/index.ts new file mode 100644 index 000000000..ce06fe7e2 --- /dev/null +++ b/backend/src/services/app-connection/okta/index.ts @@ -0,0 +1,4 @@ +export * from "./okta-connection-enums"; +export * from "./okta-connection-fns"; +export * from "./okta-connection-schemas"; +export * from "./okta-connection-types"; diff --git a/backend/src/services/app-connection/okta/okta-connection-enums.ts b/backend/src/services/app-connection/okta/okta-connection-enums.ts new file mode 100644 index 000000000..75bd5ea61 --- /dev/null +++ b/backend/src/services/app-connection/okta/okta-connection-enums.ts @@ -0,0 +1,3 @@ +export enum OktaConnectionMethod { + ApiToken = "api-token" +} diff --git a/backend/src/services/app-connection/okta/okta-connection-fns.ts b/backend/src/services/app-connection/okta/okta-connection-fns.ts new file mode 100644 index 000000000..e408db9ac --- /dev/null +++ b/backend/src/services/app-connection/okta/okta-connection-fns.ts @@ -0,0 +1,57 @@ +import { request } from "@app/lib/config/request"; +import { UnauthorizedError } from "@app/lib/errors"; +import { removeTrailingSlash } from "@app/lib/fn"; +import { blockLocalAndPrivateIpAddresses } from "@app/lib/validator"; +import { AppConnection } from "@app/services/app-connection/app-connection-enums"; + +import { OktaConnectionMethod } from "./okta-connection-enums"; +import { TOktaApp, TOktaConnection, TOktaConnectionConfig } from "./okta-connection-types"; + +export const getOktaConnectionListItem = () => { + return { + name: "Okta" as const, + app: AppConnection.Okta as const, + methods: Object.values(OktaConnectionMethod) as [OktaConnectionMethod.ApiToken] + }; +}; + +export const getOktaInstanceUrl = async (config: TOktaConnectionConfig) => { + const instanceUrl = removeTrailingSlash(config.credentials.instanceUrl); + await blockLocalAndPrivateIpAddresses(instanceUrl); + return instanceUrl; +}; + +export const validateOktaConnectionCredentials = async (config: TOktaConnectionConfig) => { + const { apiToken } = config.credentials; + const instanceUrl = await getOktaInstanceUrl(config); + + try { + await request.get(`${instanceUrl}/api/v1/users/me`, { + headers: { + Accept: "application/json", + Authorization: `SSWS ${apiToken}` + }, + validateStatus: (status) => status === 200 + }); + } catch (error: unknown) { + throw new UnauthorizedError({ + message: "Unable to validate connection: invalid credentials" + }); + } + + return config.credentials; +}; + +export const listOktaApps = async (appConnection: TOktaConnection) => { + const { apiToken } = appConnection.credentials; + const instanceUrl = await getOktaInstanceUrl(appConnection); + + const { data } = await request.get(`${instanceUrl}/api/v1/apps`, { + headers: { + Accept: "application/json", + Authorization: `SSWS ${apiToken}` + } + }); + + return data.filter((app) => app.status === "ACTIVE"); +}; diff --git a/backend/src/services/app-connection/okta/okta-connection-schemas.ts b/backend/src/services/app-connection/okta/okta-connection-schemas.ts new file mode 100644 index 000000000..37ce0ec11 --- /dev/null +++ b/backend/src/services/app-connection/okta/okta-connection-schemas.ts @@ -0,0 +1,69 @@ +import RE2 from "re2"; +import z from "zod"; + +import { AppConnections } from "@app/lib/api-docs"; +import { AppConnection } from "@app/services/app-connection/app-connection-enums"; +import { + BaseAppConnectionSchema, + GenericCreateAppConnectionFieldsSchema, + GenericUpdateAppConnectionFieldsSchema +} from "@app/services/app-connection/app-connection-schemas"; + +import { OktaConnectionMethod } from "./okta-connection-enums"; + +export const OktaConnectionApiTokenCredentialsSchema = z.object({ + instanceUrl: z + .string() + .trim() + .url("Invalid Instance URL") + .min(1, "Instance URL required") + .max(255) + .describe(AppConnections.CREDENTIALS.OKTA.instanceUrl), + apiToken: z + .string() + .trim() + .min(1, "API Token required") + .refine((value) => new RE2("^00[a-zA-Z0-9_-]{40}$").test(value), "Invalid Okta API Token format") + .describe(AppConnections.CREDENTIALS.OKTA.apiToken) +}); + +const BaseOktaConnectionSchema = BaseAppConnectionSchema.extend({ app: z.literal(AppConnection.Okta) }); + +export const OktaConnectionSchema = BaseOktaConnectionSchema.extend({ + method: z.literal(OktaConnectionMethod.ApiToken), + credentials: OktaConnectionApiTokenCredentialsSchema +}); + +export const SanitizedOktaConnectionSchema = z.discriminatedUnion("method", [ + BaseOktaConnectionSchema.extend({ + method: z.literal(OktaConnectionMethod.ApiToken), + credentials: OktaConnectionApiTokenCredentialsSchema.pick({ + instanceUrl: true + }) + }) +]); + +export const ValidateOktaConnectionCredentialsSchema = z.discriminatedUnion("method", [ + z.object({ + method: z.literal(OktaConnectionMethod.ApiToken).describe(AppConnections.CREATE(AppConnection.Okta).method), + credentials: OktaConnectionApiTokenCredentialsSchema.describe(AppConnections.CREATE(AppConnection.Okta).credentials) + }) +]); + +export const CreateOktaConnectionSchema = ValidateOktaConnectionCredentialsSchema.and( + GenericCreateAppConnectionFieldsSchema(AppConnection.Okta) +); + +export const UpdateOktaConnectionSchema = z + .object({ + credentials: OktaConnectionApiTokenCredentialsSchema.optional().describe( + AppConnections.UPDATE(AppConnection.Okta).credentials + ) + }) + .and(GenericUpdateAppConnectionFieldsSchema(AppConnection.Okta)); + +export const OktaConnectionListItemSchema = z.object({ + name: z.literal("Okta"), + app: z.literal(AppConnection.Okta), + methods: z.nativeEnum(OktaConnectionMethod).array() +}); diff --git a/backend/src/services/app-connection/okta/okta-connection-service.ts b/backend/src/services/app-connection/okta/okta-connection-service.ts new file mode 100644 index 000000000..8ac036dcd --- /dev/null +++ b/backend/src/services/app-connection/okta/okta-connection-service.ts @@ -0,0 +1,23 @@ +import { OrgServiceActor } from "@app/lib/types"; + +import { AppConnection } from "../app-connection-enums"; +import { listOktaApps } from "./okta-connection-fns"; +import { TOktaConnection } from "./okta-connection-types"; + +type TGetAppConnectionFunc = ( + app: AppConnection, + connectionId: string, + actor: OrgServiceActor +) => Promise; + +export const oktaConnectionService = (getAppConnection: TGetAppConnectionFunc) => { + const listApps = async (connectionId: string, actor: OrgServiceActor) => { + const appConnection = await getAppConnection(AppConnection.Okta, connectionId, actor); + const apps = await listOktaApps(appConnection); + return apps; + }; + + return { + listApps + }; +}; diff --git a/backend/src/services/app-connection/okta/okta-connection-types.ts b/backend/src/services/app-connection/okta/okta-connection-types.ts new file mode 100644 index 000000000..58e70adf4 --- /dev/null +++ b/backend/src/services/app-connection/okta/okta-connection-types.ts @@ -0,0 +1,28 @@ +import z from "zod"; + +import { DiscriminativePick } from "@app/lib/types"; + +import { AppConnection } from "../app-connection-enums"; +import { + CreateOktaConnectionSchema, + OktaConnectionSchema, + ValidateOktaConnectionCredentialsSchema +} from "./okta-connection-schemas"; + +export type TOktaConnection = z.infer; + +export type TOktaConnectionInput = z.infer & { + app: AppConnection.Okta; +}; + +export type TValidateOktaConnectionCredentialsSchema = typeof ValidateOktaConnectionCredentialsSchema; + +export type TOktaConnectionConfig = DiscriminativePick & { + orgId: string; +}; + +export type TOktaApp = { + id: string; + label: string; + status: "ACTIVE" | "INACTIVE"; +}; diff --git a/frontend/public/images/integrations/Okta.png b/frontend/public/images/integrations/Okta.png new file mode 100644 index 0000000000000000000000000000000000000000..d742d434738741f72a34c018fee645b8d63c5f10 GIT binary patch literal 63604 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 { @@ -132,6 +134,7 @@ export const getAppConnectionMethodDetails = (method: TAppConnection["method"]) case CloudflareConnectionMethod.ApiToken: case BitbucketConnectionMethod.ApiToken: case ZabbixConnectionMethod.ApiToken: + case OktaConnectionMethod.ApiToken: return { name: "API Token", icon: faKey }; case PostgresConnectionMethod.UsernameAndPassword: case MsSqlConnectionMethod.UsernameAndPassword: diff --git a/frontend/src/hooks/api/appConnections/enums.ts b/frontend/src/hooks/api/appConnections/enums.ts index 965675bc7..2e1e59655 100644 --- a/frontend/src/hooks/api/appConnections/enums.ts +++ b/frontend/src/hooks/api/appConnections/enums.ts @@ -32,5 +32,6 @@ export enum AppConnection { Zabbix = "zabbix", Railway = "railway", Checkly = "checkly", - Supabase = "supabase" + Supabase = "supabase", + Okta = "okta" } diff --git a/frontend/src/hooks/api/appConnections/okta/index.ts b/frontend/src/hooks/api/appConnections/okta/index.ts new file mode 100644 index 000000000..2c1906d36 --- /dev/null +++ b/frontend/src/hooks/api/appConnections/okta/index.ts @@ -0,0 +1,2 @@ +export * from "./queries"; +export * from "./types"; diff --git a/frontend/src/hooks/api/appConnections/okta/queries.tsx b/frontend/src/hooks/api/appConnections/okta/queries.tsx new file mode 100644 index 000000000..9823a296a --- /dev/null +++ b/frontend/src/hooks/api/appConnections/okta/queries.tsx @@ -0,0 +1,36 @@ +import { useQuery, UseQueryOptions } from "@tanstack/react-query"; + +import { apiRequest } from "@app/config/request"; + +import { appConnectionKeys } from "../queries"; +import { TOktaApp } from "./types"; + +const oktaConnectionKeys = { + all: [...appConnectionKeys.all, "okta"] as const, + listApps: (connectionId: string) => [...oktaConnectionKeys.all, "apps", connectionId] as const +}; + +export const useOktaConnectionListApps = ( + connectionId: string, + options?: Omit< + UseQueryOptions< + TOktaApp[], + unknown, + TOktaApp[], + ReturnType + >, + "queryKey" | "queryFn" + > +) => { + return useQuery({ + queryKey: oktaConnectionKeys.listApps(connectionId), + queryFn: async () => { + const { data } = await apiRequest.get<{ apps: TOktaApp[] }>( + `/api/v1/app-connections/okta/${connectionId}/apps` + ); + + return data.apps; + }, + ...options + }); +}; diff --git a/frontend/src/hooks/api/appConnections/okta/types.ts b/frontend/src/hooks/api/appConnections/okta/types.ts new file mode 100644 index 000000000..8acc6c04d --- /dev/null +++ b/frontend/src/hooks/api/appConnections/okta/types.ts @@ -0,0 +1,4 @@ +export type TOktaApp = { + id: string; + label: string; +}; diff --git a/frontend/src/hooks/api/appConnections/types/app-options.ts b/frontend/src/hooks/api/appConnections/types/app-options.ts index b6b00a615..e9bc5b243 100644 --- a/frontend/src/hooks/api/appConnections/types/app-options.ts +++ b/frontend/src/hooks/api/appConnections/types/app-options.ts @@ -152,6 +152,10 @@ export type TSupabaseConnectionOption = TAppConnectionOptionBase & { app: AppConnection.Supabase; }; +export type TOktaConnectionOption = TAppConnectionOptionBase & { + app: AppConnection.Okta; +}; + export type TAppConnectionOption = | TAwsConnectionOption | TGitHubConnectionOption @@ -183,7 +187,8 @@ export type TAppConnectionOption = | TBitbucketConnectionOption | TZabbixConnectionOption | TRailwayConnectionOption - | TChecklyConnectionOption; + | TChecklyConnectionOption + | TOktaConnectionOption; export type TAppConnectionOptionMap = { [AppConnection.AWS]: TAwsConnectionOption; @@ -220,4 +225,5 @@ export type TAppConnectionOptionMap = { [AppConnection.Railway]: TRailwayConnectionOption; [AppConnection.Checkly]: TChecklyConnectionOption; [AppConnection.Supabase]: TSupabaseConnectionOption; + [AppConnection.Okta]: TOktaConnectionOption; }; diff --git a/frontend/src/hooks/api/appConnections/types/index.ts b/frontend/src/hooks/api/appConnections/types/index.ts index e177fa2ab..734aca8d9 100644 --- a/frontend/src/hooks/api/appConnections/types/index.ts +++ b/frontend/src/hooks/api/appConnections/types/index.ts @@ -24,6 +24,7 @@ import { TLdapConnection } from "./ldap-connection"; import { TMsSqlConnection } from "./mssql-connection"; import { TMySqlConnection } from "./mysql-connection"; import { TOCIConnection } from "./oci-connection"; +import { TOktaConnection } from "./okta-connection"; import { TOracleDBConnection } from "./oracledb-connection"; import { TPostgresConnection } from "./postgres-connection"; import { TRailwayConnection } from "./railway-connection"; @@ -44,6 +45,7 @@ export * from "./azure-devops-connection"; export * from "./azure-key-vault-connection"; export * from "./bitbucket-connection"; export * from "./camunda-connection"; +export * from "./checkly-connection"; export * from "./cloudflare-connection"; export * from "./databricks-connection"; export * from "./flyio-connection"; @@ -58,9 +60,12 @@ export * from "./ldap-connection"; export * from "./mssql-connection"; export * from "./mysql-connection"; export * from "./oci-connection"; +export * from "./okta-connection"; export * from "./oracledb-connection"; export * from "./postgres-connection"; +export * from "./railway-connection"; export * from "./render-connection"; +export * from "./supabase-connection"; export * from "./teamcity-connection"; export * from "./terraform-cloud-connection"; export * from "./vercel-connection"; @@ -101,7 +106,8 @@ export type TAppConnection = | TZabbixConnection | TRailwayConnection | TChecklyConnection - | TSupabaseConnection; + | TSupabaseConnection + | TOktaConnection; export type TAvailableAppConnection = Pick; @@ -163,4 +169,5 @@ export type TAppConnectionMap = { [AppConnection.Railway]: TRailwayConnection; [AppConnection.Checkly]: TChecklyConnection; [AppConnection.Supabase]: TSupabaseConnection; + [AppConnection.Okta]: TOktaConnection; }; diff --git a/frontend/src/hooks/api/appConnections/types/okta-connection.ts b/frontend/src/hooks/api/appConnections/types/okta-connection.ts new file mode 100644 index 000000000..a622388b4 --- /dev/null +++ b/frontend/src/hooks/api/appConnections/types/okta-connection.ts @@ -0,0 +1,14 @@ +import { AppConnection } from "@app/hooks/api/appConnections/enums"; +import { TRootAppConnection } from "@app/hooks/api/appConnections/types/root-connection"; + +export enum OktaConnectionMethod { + ApiToken = "api-token" +} + +export type TOktaConnection = TRootAppConnection & { app: AppConnection.Okta } & { + method: OktaConnectionMethod.ApiToken; + credentials: { + instanceUrl: string; + apiToken: string; + }; +}; diff --git a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/AppConnectionForm.tsx b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/AppConnectionForm.tsx index 45a774780..b1181a68b 100644 --- a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/AppConnectionForm.tsx +++ b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/AppConnectionForm.tsx @@ -33,6 +33,7 @@ import { LdapConnectionForm } from "./LdapConnectionForm"; import { MsSqlConnectionForm } from "./MsSqlConnectionForm"; import { MySqlConnectionForm } from "./MySqlConnectionForm"; import { OCIConnectionForm } from "./OCIConnectionForm"; +import { OktaConnectionForm } from "./OktaConnectionForm"; import { OracleDBConnectionForm } from "./OracleDBConnectionForm"; import { PostgresConnectionForm } from "./PostgresConnectionForm"; import { RailwayConnectionForm } from "./RailwayConnectionForm"; @@ -149,6 +150,8 @@ const CreateForm = ({ app, onComplete }: CreateFormProps) => { return ; case AppConnection.Supabase: return ; + case AppConnection.Okta: + return ; default: throw new Error(`Unhandled App ${app}`); } @@ -253,6 +256,8 @@ const UpdateForm = ({ appConnection, onComplete }: UpdateFormProps) => { return ; case AppConnection.Supabase: return ; + case AppConnection.Okta: + return ; default: throw new Error(`Unhandled App ${(appConnection as TAppConnection).app}`); } diff --git a/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/OktaConnectionForm.tsx b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/OktaConnectionForm.tsx new file mode 100644 index 000000000..0373d1e0e --- /dev/null +++ b/frontend/src/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/OktaConnectionForm.tsx @@ -0,0 +1,157 @@ +import { Controller, FormProvider, useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { z } from "zod"; + +import { + Button, + FormControl, + Input, + ModalClose, + SecretInput, + Select, + SelectItem +} from "@app/components/v2"; +import { APP_CONNECTION_MAP, getAppConnectionMethodDetails } from "@app/helpers/appConnections"; +import { OktaConnectionMethod, TOktaConnection } from "@app/hooks/api/appConnections"; +import { AppConnection } from "@app/hooks/api/appConnections/enums"; + +import { + genericAppConnectionFieldsSchema, + GenericAppConnectionsFields +} from "./GenericAppConnectionFields"; + +type Props = { + appConnection?: TOktaConnection; + onSubmit: (formData: FormData) => void; +}; + +const rootSchema = genericAppConnectionFieldsSchema.extend({ + app: z.literal(AppConnection.Okta) +}); + +const formSchema = z.discriminatedUnion("method", [ + rootSchema.extend({ + method: z.literal(OktaConnectionMethod.ApiToken), + credentials: z.object({ + instanceUrl: z + .string() + .trim() + .url("Invalid Instance URL") + .min(1, "Instance URL required") + .max(255), + apiToken: z + .string() + .trim() + .min(1, "API Token required") + .regex(/^00[a-zA-Z0-9_-]{40}$/, "Invalid Okta API Token format") + }) + }) +]); + +type FormData = z.infer; + +export const OktaConnectionForm = ({ appConnection, onSubmit }: Props) => { + const isUpdate = Boolean(appConnection); + + const form = useForm({ + resolver: zodResolver(formSchema), + defaultValues: appConnection ?? { + app: AppConnection.Okta, + method: OktaConnectionMethod.ApiToken + } + }); + + const { + handleSubmit, + control, + formState: { isSubmitting, isDirty } + } = form; + + return ( + +
+ {!isUpdate && } + ( + + + + )} + /> + ( + + + + )} + /> + ( + + onChange(e.target.value)} + /> + + )} + /> +
+ + + + +
+ +
+ ); +};