-
{t("signup.initial-title")}
-
- {
- window.open("/api/v1/sso/redirect/google");
- window.close();
- }}
- leftIcon={ }
- className="h-12 w-full mx-0"
- >
- {t("signup.continue-with-google")}
-
-
-
- {
- window.open("/api/v1/sso/redirect/github");
- window.close();
- }}
- leftIcon={ }
- className="h-12 w-full mx-0"
- >
- Continue with GitHub
-
-
-
- {
- setIsSignupWithEmail(true);
- }}
- leftIcon={ }
- className="h-12 w-full mx-0"
- >
- Continue with Email
-
-
-
- router.push("/saml-sso")}
- leftIcon={ }
- className="h-12 w-full mx-0"
- >
- Continue with SSO
-
-
-
- {t("signup.create-policy")}
-
-
-
- {t("signup.already-have-account")}
-
-
+ return (
+
+
+ {t("signup.initial-title")}
+
+
+ {
+ window.open("/api/v1/sso/redirect/google");
+ window.close();
+ }}
+ leftIcon={ }
+ className="mx-0 h-12 w-full"
+ >
+ {t("signup.continue-with-google")}
+
+
+
+ {
+ window.open("/api/v1/sso/redirect/github");
+ window.close();
+ }}
+ leftIcon={ }
+ className="mx-0 h-12 w-full"
+ >
+ Continue with GitHub
+
+
+
+ {
+ window.open("/api/v1/sso/redirect/gitlab");
+ window.close();
+ }}
+ leftIcon={ }
+ className="mx-0 h-12 w-full"
+ >
+ Continue with GitLab
+
+
+
+ {
+ setIsSignupWithEmail(true);
+ }}
+ leftIcon={ }
+ className="mx-0 h-12 w-full"
+ >
+ Continue with Email
+
+
+
+ router.push("/saml-sso")}
+ leftIcon={ }
+ className="mx-0 h-12 w-full"
+ >
+ Continue with SSO
+
+
+
+ {t("signup.create-policy")}
+
+
+
+
+ {t("signup.already-have-account")}
+
+
+
+ );
}
diff --git a/frontend/src/hooks/api/users/types.ts b/frontend/src/hooks/api/users/types.ts
index 07f497c078..6917bcdc71 100644
--- a/frontend/src/hooks/api/users/types.ts
+++ b/frontend/src/hooks/api/users/types.ts
@@ -4,9 +4,10 @@ export enum AuthMethod {
EMAIL = "email",
GOOGLE = "google",
GITHUB = "github",
- OKTA_SAML = "okta-saml",
- AZURE_SAML = "azure-saml",
- JUMPCLOUD_SAML = "jumpcloud-saml"
+ GITLAB = "gitlab",
+ OKTA_SAML = "okta-saml",
+ AZURE_SAML = "azure-saml",
+ JUMPCLOUD_SAML = "jumpcloud-saml"
}
export type User = {
diff --git a/frontend/src/views/Login/components/InitialStep/InitialStep.tsx b/frontend/src/views/Login/components/InitialStep/InitialStep.tsx
index 7bab7414e6..50eaf5cb71 100644
--- a/frontend/src/views/Login/components/InitialStep/InitialStep.tsx
+++ b/frontend/src/views/Login/components/InitialStep/InitialStep.tsx
@@ -2,10 +2,10 @@ import { FormEvent, useState } from "react";
import { useTranslation } from "react-i18next";
import Link from "next/link";
import { useRouter } from "next/router";
-import { faGithub,faGoogle } from "@fortawesome/free-brands-svg-icons";
+import { faGithub, faGitlab, faGoogle } from "@fortawesome/free-brands-svg-icons";
import { faLock } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import axios from "axios"
+import axios from "axios";
import Error from "@app/components/basic/Error";
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
@@ -16,208 +16,234 @@ import { fetchOrganizations } from "@app/hooks/api/organization/queries";
import { useFetchServerStatus } from "@app/hooks/api/serverDetails";
type Props = {
- setStep: (step: number) => void;
- email: string;
- setEmail: (email: string) => void;
- password: string;
- setPassword: (email: string) => void;
-}
+ setStep: (step: number) => void;
+ email: string;
+ setEmail: (email: string) => void;
+ password: string;
+ setPassword: (email: string) => void;
+};
-export const InitialStep = ({
- setStep,
- email,
- setEmail,
- password,
- setPassword
-}: Props) => {
- const router = useRouter();
- const { createNotification } = useNotificationContext();
- const { t } = useTranslation();
- const [isLoading, setIsLoading] = useState(false);
- const [loginError, setLoginError] = useState(false);
- const { data: serverDetails } = useFetchServerStatus();
- const queryParams = new URLSearchParams(window.location.search);
+export const InitialStep = ({ setStep, email, setEmail, password, setPassword }: Props) => {
+ const router = useRouter();
+ const { createNotification } = useNotificationContext();
+ const { t } = useTranslation();
+ const [isLoading, setIsLoading] = useState(false);
+ const [loginError, setLoginError] = useState(false);
+ const { data: serverDetails } = useFetchServerStatus();
+ const queryParams = new URLSearchParams(window.location.search);
- const handleLogin = async (e: FormEvent
) => {
- e.preventDefault()
- try {
- if (!email || !password) {
- return;
- }
+ const handleLogin = async (e: FormEvent) => {
+ e.preventDefault();
+ try {
+ if (!email || !password) {
+ return;
+ }
- setIsLoading(true);
- if (queryParams && queryParams.get("callback_port")) {
- const callbackPort = queryParams.get("callback_port")
+ setIsLoading(true);
+ if (queryParams && queryParams.get("callback_port")) {
+ const callbackPort = queryParams.get("callback_port");
- // attemptCliLogin
- const isCliLoginSuccessful = await attemptCliLogin({
- email: email.toLowerCase(),
- password,
- })
+ // attemptCliLogin
+ const isCliLoginSuccessful = await attemptCliLogin({
+ email: email.toLowerCase(),
+ password
+ });
- if (isCliLoginSuccessful && isCliLoginSuccessful.success) {
+ if (isCliLoginSuccessful && isCliLoginSuccessful.success) {
+ if (isCliLoginSuccessful.mfaEnabled) {
+ // case: login requires MFA step
+ setStep(1);
+ setIsLoading(false);
+ return;
+ }
+ // case: login was successful
+ const cliUrl = `http://localhost:${callbackPort}`;
- if (isCliLoginSuccessful.mfaEnabled) {
- // case: login requires MFA step
- setStep(1);
- setIsLoading(false);
- return;
- }
- // case: login was successful
- const cliUrl = `http://localhost:${callbackPort}`
+ // send request to server endpoint
+ const instance = axios.create();
+ await instance.post(cliUrl, { ...isCliLoginSuccessful.loginResponse });
- // send request to server endpoint
- const instance = axios.create()
- await instance.post(cliUrl, { ...isCliLoginSuccessful.loginResponse })
+ // cli page
+ router.push("/cli-redirect");
- // cli page
- router.push("/cli-redirect");
-
- // on success, router.push to cli Login Successful page
-
- }
- } else {
- const isLoginSuccessful = await attemptLogin({
- email: email.toLowerCase(),
- password,
- });
- if (isLoginSuccessful && isLoginSuccessful.success) {
- // case: login was successful
-
- if (isLoginSuccessful.mfaEnabled) {
- // case: login requires MFA step
- setStep(1);
- setIsLoading(false);
- return;
- }
- const userOrgs = await fetchOrganizations();
- const userOrg = userOrgs[0] && userOrgs[0]._id;
-
- // case: login does not require MFA step
- createNotification({
- text: "Successfully logged in",
- type: "success"
- });
- router.push(`/org/${userOrg}/overview`);
- }
- }
-
-
- } catch (err) {
- setLoginError(true);
- createNotification({
- text: "Login unsuccessful. Double-check your credentials and try again.",
- type: "error"
- });
+ // on success, router.push to cli Login Successful page
}
+ } else {
+ const isLoginSuccessful = await attemptLogin({
+ email: email.toLowerCase(),
+ password
+ });
+ if (isLoginSuccessful && isLoginSuccessful.success) {
+ // case: login was successful
- setIsLoading(false);
+ if (isLoginSuccessful.mfaEnabled) {
+ // case: login requires MFA step
+ setStep(1);
+ setIsLoading(false);
+ return;
+ }
+ const userOrgs = await fetchOrganizations();
+ const userOrg = userOrgs[0] && userOrgs[0]._id;
+
+ // case: login does not require MFA step
+ createNotification({
+ text: "Successfully logged in",
+ type: "success"
+ });
+ router.push(`/org/${userOrg}/overview`);
+ }
+ }
+ } catch (err) {
+ setLoginError(true);
+ createNotification({
+ text: "Login unsuccessful. Double-check your credentials and try again.",
+ type: "error"
+ });
}
- return (
-
- );
-}
\ No newline at end of file
+ setIsLoading(false);
+ };
+
+ return (
+
+ );
+};
diff --git a/frontend/src/views/Settings/PersonalSettingsPage/AuthMethodSection/AuthMethodSection.tsx b/frontend/src/views/Settings/PersonalSettingsPage/AuthMethodSection/AuthMethodSection.tsx
index 42917aae68..73d266e2eb 100644
--- a/frontend/src/views/Settings/PersonalSettingsPage/AuthMethodSection/AuthMethodSection.tsx
+++ b/frontend/src/views/Settings/PersonalSettingsPage/AuthMethodSection/AuthMethodSection.tsx
@@ -1,6 +1,6 @@
import { useEffect } from "react";
import { useForm } from "react-hook-form";
-import { faGithub, faGoogle, IconDefinition } from "@fortawesome/free-brands-svg-icons";
+import { faGithub, faGitlab, faGoogle, IconDefinition } from "@fortawesome/free-brands-svg-icons";
import { faEnvelope } from "@fortawesome/free-regular-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { yupResolver } from "@hookform/resolvers/yup";
@@ -10,129 +10,127 @@ import { useNotificationContext } from "@app/components/context/Notifications/No
import { Switch } from "@app/components/v2";
import { useUser } from "@app/context";
import { useUpdateUserAuthMethods } from "@app/hooks/api";
-import {
- AuthMethod
-} from "@app/hooks/api/users/types";
+import { AuthMethod } from "@app/hooks/api/users/types";
interface AuthMethodOption {
- label: string,
- value: AuthMethod,
- icon: IconDefinition;
+ label: string;
+ value: AuthMethod;
+ icon: IconDefinition;
}
const authMethodOpts: AuthMethodOption[] = [
- { label: "Email", value: AuthMethod.EMAIL, icon: faEnvelope },
- { label: "Google", value: AuthMethod.GOOGLE, icon: faGoogle },
- { label: "GitHub", value: AuthMethod.GITHUB, icon: faGithub }
+ { label: "Email", value: AuthMethod.EMAIL, icon: faEnvelope },
+ { label: "Google", value: AuthMethod.GOOGLE, icon: faGoogle },
+ { label: "GitHub", value: AuthMethod.GITHUB, icon: faGithub },
+ { label: "GitLab", value: AuthMethod.GITLAB, icon: faGitlab }
];
const samlProviders = [AuthMethod.OKTA_SAML, AuthMethod.JUMPCLOUD_SAML, AuthMethod.AZURE_SAML];
const schema = yup.object({
- authMethods: yup.array().required("Auth method is required")
+ authMethods: yup.array().required("Auth method is required")
});
export type FormData = yup.InferType;
export const AuthMethodSection = () => {
- const { createNotification } = useNotificationContext();
- const { user } = useUser();
- const { mutateAsync } = useUpdateUserAuthMethods();
-
- const {
- reset,
- setValue,
- watch,
- } = useForm({
- defaultValues: {
- authMethods: user.authMethods,
- },
- resolver: yupResolver(schema)
- });
-
- const authMethods = watch("authMethods");
-
- useEffect(() => {
- if (user) {
- reset({
- authMethods: user.authMethods,
- });
- }
- }, [user]);
-
- const onAuthMethodToggle = async (value: boolean, authMethodOpt: AuthMethodOption) => {
- const hasSamlEnabled = user.authMethods
- .some((authMethod: AuthMethod) => samlProviders.includes(authMethod));
+ const { createNotification } = useNotificationContext();
+ const { user } = useUser();
+ const { mutateAsync } = useUpdateUserAuthMethods();
- if (hasSamlEnabled) {
- createNotification({
- text: "SAML authentication can only be configured in your organization settings",
- type: "error"
- });
- }
-
- const newAuthMethods = value
- ? [...authMethods, authMethodOpt.value]
- : authMethods.filter(auth => auth !== authMethodOpt.value);
-
- if (value) {
- const newUser = await mutateAsync({
- authMethods: newAuthMethods
- });
+ const { reset, setValue, watch } = useForm({
+ defaultValues: {
+ authMethods: user.authMethods
+ },
+ resolver: yupResolver(schema)
+ });
- setValue("authMethods", newUser.authMethods);
- createNotification({
- text: "Successfully enabled authentication method",
- type: "success"
- });
- return;
- }
-
- if (newAuthMethods.length === 0) {
- createNotification({
- text: "You must keep at least 1 authentication method enabled",
- type: "error"
- });
- return;
- }
-
- const newUser = await mutateAsync({
- authMethods: newAuthMethods
- });
-
- setValue("authMethods", newUser.authMethods);
- createNotification({
- text: "Successfully disabled authentication method",
- type: "success"
- });
+ const authMethods = watch("authMethods");
+
+ useEffect(() => {
+ if (user) {
+ reset({
+ authMethods: user.authMethods
+ });
}
-
- return (
-
-
- Authentication methods
-
-
- By enabling a SSO provider, you are allowing an account with that provider which uses the same email address as your existing Infisical account to be able to log in to Infisical.
-
-
- {user && authMethodOpts.map((authMethodOpt) => {
- return (
-
-
-
-
-
onAuthMethodToggle(value, authMethodOpt)}
- isChecked={authMethods?.includes(authMethodOpt.value) ?? false}
- >
- {authMethodOpt.label}
-
-
- );
- })}
-
-
+ }, [user]);
+
+ const onAuthMethodToggle = async (value: boolean, authMethodOpt: AuthMethodOption) => {
+ const hasSamlEnabled = user.authMethods.some((authMethod: AuthMethod) =>
+ samlProviders.includes(authMethod)
);
-}
+
+ if (hasSamlEnabled) {
+ createNotification({
+ text: "SAML authentication can only be configured in your organization settings",
+ type: "error"
+ });
+ }
+
+ const newAuthMethods = value
+ ? [...authMethods, authMethodOpt.value]
+ : authMethods.filter((auth) => auth !== authMethodOpt.value);
+
+ if (value) {
+ const newUser = await mutateAsync({
+ authMethods: newAuthMethods
+ });
+
+ setValue("authMethods", newUser.authMethods);
+ createNotification({
+ text: "Successfully enabled authentication method",
+ type: "success"
+ });
+ return;
+ }
+
+ if (newAuthMethods.length === 0) {
+ createNotification({
+ text: "You must keep at least 1 authentication method enabled",
+ type: "error"
+ });
+ return;
+ }
+
+ const newUser = await mutateAsync({
+ authMethods: newAuthMethods
+ });
+
+ setValue("authMethods", newUser.authMethods);
+ createNotification({
+ text: "Successfully disabled authentication method",
+ type: "success"
+ });
+ };
+
+ return (
+
+
+ Authentication methods
+
+
+ By enabling a SSO provider, you are allowing an account with that provider which uses the
+ same email address as your existing Infisical account to be able to log in to Infisical.
+
+
+ {user &&
+ authMethodOpts.map((authMethodOpt) => {
+ return (
+
+
+
+
+
onAuthMethodToggle(value, authMethodOpt)}
+ isChecked={authMethods?.includes(authMethodOpt.value) ?? false}
+ >
+ {authMethodOpt.label}
+
+
+ );
+ })}
+
+
+ );
+};