Merge pull request #818 from JunedKhan101/feature-github-signin

initial-setup for github signin
This commit is contained in:
BlackMagiq
2023-08-03 15:44:15 +07:00
committed by GitHub
13 changed files with 288 additions and 120 deletions
+20
View File
@@ -45,6 +45,7 @@
"node-cache": "^5.1.2", "node-cache": "^5.1.2",
"nodemailer": "^6.8.0", "nodemailer": "^6.8.0",
"passport": "^0.6.0", "passport": "^0.6.0",
"passport-github": "^1.1.0",
"passport-google-oauth20": "^2.0.0", "passport-google-oauth20": "^2.0.0",
"posthog-node": "^2.6.0", "posthog-node": "^2.6.0",
"probot": "^12.3.1", "probot": "^12.3.1",
@@ -11385,6 +11386,17 @@
"url": "https://github.com/sponsors/jaredhanson" "url": "https://github.com/sponsors/jaredhanson"
} }
}, },
"node_modules/passport-github": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/passport-github/-/passport-github-1.1.0.tgz",
"integrity": "sha512-XARXJycE6fFh/dxF+Uut8OjlwbFEXgbPVj/+V+K7cvriRK7VcAOm+NgBmbiLM9Qv3SSxEAV+V6fIk89nYHXa8A==",
"dependencies": {
"passport-oauth2": "1.x.x"
},
"engines": {
"node": ">= 0.4.0"
}
},
"node_modules/passport-google-oauth20": { "node_modules/passport-google-oauth20": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/passport-google-oauth20/-/passport-google-oauth20-2.0.0.tgz", "resolved": "https://registry.npmjs.org/passport-google-oauth20/-/passport-google-oauth20-2.0.0.tgz",
@@ -22858,6 +22870,14 @@
"utils-merge": "^1.0.1" "utils-merge": "^1.0.1"
} }
}, },
"passport-github": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/passport-github/-/passport-github-1.1.0.tgz",
"integrity": "sha512-XARXJycE6fFh/dxF+Uut8OjlwbFEXgbPVj/+V+K7cvriRK7VcAOm+NgBmbiLM9Qv3SSxEAV+V6fIk89nYHXa8A==",
"requires": {
"passport-oauth2": "1.x.x"
}
},
"passport-google-oauth20": { "passport-google-oauth20": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/passport-google-oauth20/-/passport-google-oauth20-2.0.0.tgz", "resolved": "https://registry.npmjs.org/passport-google-oauth20/-/passport-google-oauth20-2.0.0.tgz",
+1
View File
@@ -36,6 +36,7 @@
"node-cache": "^5.1.2", "node-cache": "^5.1.2",
"nodemailer": "^6.8.0", "nodemailer": "^6.8.0",
"passport": "^0.6.0", "passport": "^0.6.0",
"passport-github": "^1.1.0",
"passport-google-oauth20": "^2.0.0", "passport-google-oauth20": "^2.0.0",
"posthog-node": "^2.6.0", "posthog-node": "^2.6.0",
"probot": "^12.3.1", "probot": "^12.3.1",
+6 -2
View File
@@ -36,7 +36,6 @@ export const getClientIdVercel = async () => (await client.getSecret("CLIENT_ID_
export const getClientIdNetlify = async () => (await client.getSecret("CLIENT_ID_NETLIFY")).secretValue; export const getClientIdNetlify = async () => (await client.getSecret("CLIENT_ID_NETLIFY")).secretValue;
export const getClientIdGitHub = async () => (await client.getSecret("CLIENT_ID_GITHUB")).secretValue; export const getClientIdGitHub = async () => (await client.getSecret("CLIENT_ID_GITHUB")).secretValue;
export const getClientIdGitLab = async () => (await client.getSecret("CLIENT_ID_GITLAB")).secretValue; export const getClientIdGitLab = async () => (await client.getSecret("CLIENT_ID_GITLAB")).secretValue;
export const getClientIdGoogle = async () => (await client.getSecret("CLIENT_ID_GOOGLE")).secretValue;
export const getClientIdBitBucket = async () => (await client.getSecret("CLIENT_ID_BITBUCKET")).secretValue; export const getClientIdBitBucket = async () => (await client.getSecret("CLIENT_ID_BITBUCKET")).secretValue;
export const getClientSecretAzure = async () => (await client.getSecret("CLIENT_SECRET_AZURE")).secretValue; export const getClientSecretAzure = async () => (await client.getSecret("CLIENT_SECRET_AZURE")).secretValue;
export const getClientSecretHeroku = async () => (await client.getSecret("CLIENT_SECRET_HEROKU")).secretValue; export const getClientSecretHeroku = async () => (await client.getSecret("CLIENT_SECRET_HEROKU")).secretValue;
@@ -44,9 +43,14 @@ export const getClientSecretVercel = async () => (await client.getSecret("CLIENT
export const getClientSecretNetlify = async () => (await client.getSecret("CLIENT_SECRET_NETLIFY")).secretValue; export const getClientSecretNetlify = async () => (await client.getSecret("CLIENT_SECRET_NETLIFY")).secretValue;
export const getClientSecretGitHub = async () => (await client.getSecret("CLIENT_SECRET_GITHUB")).secretValue; export const getClientSecretGitHub = async () => (await client.getSecret("CLIENT_SECRET_GITHUB")).secretValue;
export const getClientSecretGitLab = async () => (await client.getSecret("CLIENT_SECRET_GITLAB")).secretValue; export const getClientSecretGitLab = async () => (await client.getSecret("CLIENT_SECRET_GITLAB")).secretValue;
export const getClientSecretGoogle = async () => (await client.getSecret("CLIENT_SECRET_GOOGLE")).secretValue;
export const getClientSecretBitBucket = async () => (await client.getSecret("CLIENT_SECRET_BITBUCKET")).secretValue; export const getClientSecretBitBucket = async () => (await client.getSecret("CLIENT_SECRET_BITBUCKET")).secretValue;
export const getClientSlugVercel = async () => (await client.getSecret("CLIENT_SLUG_VERCEL")).secretValue; export const getClientSlugVercel = async () => (await client.getSecret("CLIENT_SLUG_VERCEL")).secretValue;
export const getClientIdGoogleLogin = async () => (await client.getSecret("CLIENT_ID_GOOGLE_LOGIN")).secretValue;
export const getClientSecretGoogleLogin = async () => (await client.getSecret("CLIENT_SECRET_GOOGLE_LOGIN")).secretValue;
export const getClientIdGitHubLogin = async () => (await client.getSecret("CLIENT_ID_GITHUB_LOGIN")).secretValue;
export const getClientSecretGitHubLogin = async () => (await client.getSecret("CLIENT_SECRET_GITHUB_LOGIN")).secretValue;
export const getPostHogHost = async () => (await client.getSecret("POSTHOG_HOST")).secretValue || "https://app.posthog.com"; export const getPostHogHost = async () => (await client.getSecret("POSTHOG_HOST")).secretValue || "https://app.posthog.com";
export const getPostHogProjectApiKey = async () => (await client.getSecret("POSTHOG_PROJECT_API_KEY")).secretValue || "phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE"; export const getPostHogProjectApiKey = async () => (await client.getSecret("POSTHOG_PROJECT_API_KEY")).secretValue || "phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE";
export const getSentryDSN = async () => (await client.getSecret("SENTRY_DSN")).secretValue; export const getSentryDSN = async () => (await client.getSecret("SENTRY_DSN")).secretValue;
@@ -123,9 +123,15 @@ export const updateAuthProvider = async (req: Request, res: Response) => {
authProvider authProvider
} = req.body; } = req.body;
if (req.user?.authProvider === AuthProvider.OKTA_SAML) return res.status(400).send({ if (
req.user?.authProvider === AuthProvider.OKTA_SAML
|| req.user?.authProvider === AuthProvider.AZURE_SAML
|| req.user?.authProvider === AuthProvider.JUMPCLOUD_SAML
) {
return res.status(400).send({
message: "Failed to update user authentication method because SAML SSO is enforced" message: "Failed to update user authentication method because SAML SSO is enforced"
}); });
}
const user = await User.findByIdAndUpdate( const user = await User.findByIdAndUpdate(
req.user._id.toString(), req.user._id.toString(),
+23
View File
@@ -41,6 +41,29 @@ router.get(
ssoController.redirectSSO ssoController.redirectSSO
); );
router.get(
"/redirect/github",
authLimiter,
(req, res, next) => {
passport.authenticate("github", {
session: false,
...(req.query.callback_port ? {
state: req.query.callback_port as string
} : {})
})(req, res, next);
}
);
router.get(
"/github",
authLimiter,
passport.authenticate("github", {
failureRedirect: "/login/provider/error",
session: false
}),
ssoController.redirectSSO
);
router.get( router.get(
"/redirect/saml2/:ssoIdentifier", "/redirect/saml2/:ssoIdentifier",
authLimiter, authLimiter,
+1
View File
@@ -3,6 +3,7 @@ import { Document, Schema, Types, model } from "mongoose";
export enum AuthProvider { export enum AuthProvider {
EMAIL = "email", EMAIL = "email",
GOOGLE = "google", GOOGLE = "google",
GITHUB = "github",
OKTA_SAML = "okta-saml", OKTA_SAML = "okta-saml",
AZURE_SAML = "azure-saml", AZURE_SAML = "azure-saml",
JUMPCLOUD_SAML = "jumpcloud-saml", JUMPCLOUD_SAML = "jumpcloud-saml",
+2 -1
View File
@@ -50,7 +50,8 @@ router.patch(
}), }),
body("authProvider").exists().isString().isIn([ body("authProvider").exists().isString().isIn([
AuthProvider.EMAIL, AuthProvider.EMAIL,
AuthProvider.GOOGLE AuthProvider.GOOGLE,
AuthProvider.GITHUB
]), ]),
validateRequest, validateRequest,
usersController.updateAuthProvider usersController.updateAuthProvider
+70 -12
View File
@@ -12,8 +12,10 @@ import {
} from "../models"; } from "../models";
import { createToken } from "../helpers/auth"; import { createToken } from "../helpers/auth";
import { import {
getClientIdGoogle, getClientIdGitHubLogin,
getClientSecretGoogle, getClientIdGoogleLogin,
getClientSecretGitHubLogin,
getClientSecretGoogleLogin,
getJwtProviderAuthLifetime, getJwtProviderAuthLifetime,
getJwtProviderAuthSecret, getJwtProviderAuthSecret,
} from "../config"; } from "../config";
@@ -25,6 +27,8 @@ import { getSiteURL } from "../config";
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
const GoogleStrategy = require("passport-google-oauth20").Strategy; const GoogleStrategy = require("passport-google-oauth20").Strategy;
// eslint-disable-next-line @typescript-eslint/no-var-requires // eslint-disable-next-line @typescript-eslint/no-var-requires
const GitHubStrategy = require("passport-github").Strategy;
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { MultiSamlStrategy } = require("@node-saml/passport-saml"); const { MultiSamlStrategy } = require("@node-saml/passport-saml");
/** /**
@@ -67,13 +71,16 @@ const getAuthDataPayloadUserObj = (authData: AuthData) => {
} }
const initializePassport = async () => { const initializePassport = async () => {
const googleClientSecret = await getClientSecretGoogle(); const clientIdGoogleLogin = await getClientIdGoogleLogin();
const googleClientId = await getClientIdGoogle(); const clientSecretGoogleLogin = await getClientSecretGoogleLogin();
const clientIdGitHubLogin = await getClientIdGitHubLogin();
const clientSecretGitHubLogin = await getClientSecretGitHubLogin();
if (clientIdGoogleLogin && clientSecretGoogleLogin) {
passport.use(new GoogleStrategy({ passport.use(new GoogleStrategy({
passReqToCallback: true, passReqToCallback: true,
clientID: googleClientId, clientID: clientIdGoogleLogin,
clientSecret: googleClientSecret, clientSecret: clientSecretGoogleLogin,
callbackURL: "/api/v1/sso/google", callbackURL: "/api/v1/sso/google",
scope: ["profile", " email"], scope: ["profile", " email"],
}, async ( }, async (
@@ -85,8 +92,6 @@ const initializePassport = async () => {
) => { ) => {
try { try {
const email = profile.emails[0].value; const email = profile.emails[0].value;
const firstName = profile.name.givenName;
const lastName = profile.name.familyName;
let user = await User.findOne({ let user = await User.findOne({
email email
@@ -101,8 +106,8 @@ const initializePassport = async () => {
email, email,
authProvider: AuthProvider.GOOGLE, authProvider: AuthProvider.GOOGLE,
authId: profile.id, authId: profile.id,
firstName, firstName: profile.name.givenName,
lastName lastName: profile.name.familyName
}).save(); }).save();
} }
@@ -111,8 +116,8 @@ const initializePassport = async () => {
payload: { payload: {
userId: user._id.toString(), userId: user._id.toString(),
email: user.email, email: user.email,
firstName, firstName: user.firstName,
lastName, lastName: user.lastName,
authProvider: user.authProvider, authProvider: user.authProvider,
isUserCompleted, isUserCompleted,
...(req.query.state ? { ...(req.query.state ? {
@@ -130,6 +135,59 @@ const initializePassport = async () => {
done(null, false); done(null, false);
} }
})); }));
}
if (clientIdGitHubLogin && clientSecretGitHubLogin) {
passport.use(new GitHubStrategy({
passReqToCallback: true,
clientID: clientIdGitHubLogin,
clientSecret: clientSecretGitHubLogin,
callbackURL: "/api/v1/sso/github"
},
async (req : express.Request, accessToken : any, refreshToken : any, profile : any, done : any) => {
const email = profile.emails[0].value;
let user = await User.findOne({
email
}).select("+publicKey");
if (user && user.authProvider !== AuthProvider.GITHUB) {
done(InternalServerError());
}
if (!user) {
user = await new User({
email: email,
authProvider: AuthProvider.GITHUB,
authId: profile.id,
firstName: profile.displayName,
lastName: ""
}).save();
}
const isUserCompleted = !!user.publicKey;
const providerAuthToken = createToken({
payload: {
userId: user._id.toString(),
email: user.email,
firstName: user.firstName,
lastName: user.lastName,
authProvider: user.authProvider,
isUserCompleted,
...(req.query.state ? {
callbackPort: req.query.state as string
} : {})
},
expiresIn: await getJwtProviderAuthLifetime(),
secret: await getJwtProviderAuthSecret(),
});
req.isUserCompleted = isUserCompleted;
req.providerAuthToken = providerAuthToken;
return done(null, profile);
}
));
}
passport.use("saml", new MultiSamlStrategy( passport.use("saml", new MultiSamlStrategy(
{ {
-7
View File
@@ -24,8 +24,6 @@ import {
reencryptSecretBlindIndexDataSalts reencryptSecretBlindIndexDataSalts
} from "./reencryptData"; } from "./reencryptData";
import { import {
getClientIdGoogle,
getClientSecretGoogle,
getMongoURL, getMongoURL,
getNodeEnv, getNodeEnv,
getSentryDSN getSentryDSN
@@ -55,12 +53,7 @@ export const setup = async () => {
// initializing the database connection // initializing the database connection
await DatabaseService.initDatabase(await getMongoURL()); await DatabaseService.initDatabase(await getMongoURL());
const googleClientSecret: string = await getClientSecretGoogle();
const googleClientId: string = await getClientIdGoogle();
if (googleClientId && googleClientSecret) {
await initializePassport(); await initializePassport();
}
// re-encrypt any data previously encrypted under server hex 128-bit ENCRYPTION_KEY // re-encrypt any data previously encrypted under server hex 128-bit ENCRYPTION_KEY
// to base64 256-bit ROOT_ENCRYPTION_KEY // to base64 256-bit ROOT_ENCRYPTION_KEY
+68 -14
View File
@@ -14,24 +14,39 @@ Other environment variables are listed below to increase the functionality of yo
Must be a random 16 byte hex string. Can be generated with `openssl rand -hex 16` Must be a random 16 byte hex string. Can be generated with `openssl rand -hex 16`
</ParamField> </ParamField>
{" "}
<ParamField query="JWT_SIGNUP_SECRET" type="string" default="none" required> <ParamField query="JWT_SIGNUP_SECRET" type="string" default="none" required>
Must be a random 16 byte hex string. Can be generated with `openssl rand -hex 16` Must be a random 16 byte hex string. Can be generated with `openssl rand -hex
16`
</ParamField> </ParamField>
{" "}
<ParamField query="JWT_REFRESH_SECRET" type="string" default="none" required> <ParamField query="JWT_REFRESH_SECRET" type="string" default="none" required>
Must be a random 16 byte hex string. Can be generated with `openssl rand -hex 16` Must be a random 16 byte hex string. Can be generated with `openssl rand -hex
16`
</ParamField> </ParamField>
{" "}
<ParamField query="JWT_AUTH_SECRET" type="string" default="none" required> <ParamField query="JWT_AUTH_SECRET" type="string" default="none" required>
Must be a random 16 byte hex string. Can be generated with `openssl rand -hex 16` Must be a random 16 byte hex string. Can be generated with `openssl rand -hex
16`
</ParamField> </ParamField>
{" "}
<ParamField query="JWT_MFA_SECRET" type="string" default="none" required> <ParamField query="JWT_MFA_SECRET" type="string" default="none" required>
Must be a random 16 byte hex string. Can be generated with `openssl rand -hex 16` Must be a random 16 byte hex string. Can be generated with `openssl rand -hex
16`
</ParamField> </ParamField>
{" "}
<ParamField query="JWT_SERVICE_SECRET" type="string" default="none" required> <ParamField query="JWT_SERVICE_SECRET" type="string" default="none" required>
Must be a random 16 byte hex string. Can be generated with `openssl rand -hex 16` Must be a random 16 byte hex string. Can be generated with `openssl rand -hex
16`
</ParamField> </ParamField>
<ParamField query="MONGO_URL" type="string" default="none" required> <ParamField query="MONGO_URL" type="string" default="none" required>
@@ -68,6 +83,7 @@ Other environment variables are listed below to increase the functionality of yo
<ParamField query="SMTP_FROM_NAME" type="string" default="none" optional> <ParamField query="SMTP_FROM_NAME" type="string" default="none" optional>
Name label to be used in From field (e.g. Team) Name label to be used in From field (e.g. Team)
</ParamField> </ParamField>
</Tab> </Tab>
<Tab title="Secret Integrations"> <Tab title="Secret Integrations">
To sync secret to third party services, provide value for the related services To sync secret to third party services, provide value for the related services
@@ -115,17 +131,24 @@ Other environment variables are listed below to increase the functionality of yo
<ParamField query="CLIENT_SECRET_BITBUCKET" type="string" default="none" optional> <ParamField query="CLIENT_SECRET_BITBUCKET" type="string" default="none" optional>
OAuth2 client secret for BitBucket integration OAuth2 client secret for BitBucket integration
</ParamField> </ParamField>
</Tab> </Tab>
<Tab title="Auth Integrations"> <Tab title="Auth Integrations">
To integrate with external auth providers, provide value for the related keys To integrate with external auth providers, provide value for the related keys
<ParamField query="JWT_PROVIDER_AUTH_SECRET" type="string" required> <ParamField query="JWT_PROVIDER_AUTH_SECRET" type="string" required>
Must be a random 16 byte hex string. Can be generated with `openssl rand -hex 16` Must be a random 16 byte hex string. Can be generated with `openssl rand -hex 16`
</ParamField> </ParamField>
<ParamField query="CLIENT_ID_GOOGLE" type="string" default="none" optional> <ParamField query="CLIENT_ID_GOOGLE_LOGIN" type="string" default="none" optional>
OAuth2 client ID for Google auth integration OAuth2 client ID for Google login
</ParamField> </ParamField>
<ParamField query="CLIENT_SECRET_GOOGLE" type="string" default="none" optional> <ParamField query="CLIENT_SECRET_GOOGLE_LOGIN" type="string" default="none" optional>
OAuth2 client secret for Google auth integration OAuth2 client secret for Google login
</ParamField>
<ParamField query="CLIENT_ID_GITHUB_LOGIN" type="string" default="none" optional>
OAuth2 client ID for GitHub login
</ParamField>
<ParamField query="CLIENT_SECRET_GITHUB_LOGIN" type="string" default="none" optional>
OAuth2 client secret for GitHub login
</ParamField> </ParamField>
</Tab> </Tab>
<Tab title="Others"> <Tab title="Others">
@@ -150,15 +173,41 @@ Other environment variables are listed below to increase the functionality of yo
JWT token lifetime expressed in seconds or a string describing a time span JWT token lifetime expressed in seconds or a string describing a time span
</ParamField> </ParamField>
<ParamField query="MONGO_USERNAME" type="string" default="none" optional></ParamField> {" "}
<ParamField query="MONGO_PASSWORD" type="string" default="none" optional></ParamField> <ParamField
query="MONGO_USERNAME"
type="string"
default="none"
optional
></ParamField>
{" "}
<ParamField
query="MONGO_PASSWORD"
type="string"
default="none"
optional
></ParamField>
#### Error logging #### Error logging
Infisical uses Sentry to report error logs Infisical uses Sentry to report error logs
<ParamField query="SENTRY_DSN" type="string" default="none" optional></ParamField>
{" "}
<ParamField
query="SENTRY_DSN"
type="string"
default="none"
optional
></ParamField>
#### Settings #### Settings
{" "}
<ParamField query="INVITE_ONLY_SIGNUP" type="string" default="false" optional> <ParamField query="INVITE_ONLY_SIGNUP" type="string" default="false" optional>
Only allow users who are invited to sign up Only allow users who are invited to sign up
</ParamField> </ParamField>
@@ -170,6 +219,11 @@ Other environment variables are listed below to increase the functionality of yo
</Tab> </Tab>
</Tabs> </Tabs>
## Frontend environment variables ## Frontend environment variables
<ParamField query="TELEMETRY_ENABLED" type="string" default="true" optional></ParamField>
<ParamField
query="TELEMETRY_ENABLED"
type="string"
default="true"
optional
></ParamField>
-2
View File
@@ -293,12 +293,10 @@ export const useRevokeMySessions = () => {
const queryClient = useQueryClient(); const queryClient = useQueryClient();
return useMutation({ return useMutation({
mutationFn: async () => { mutationFn: async () => {
console.log("useRevokeAllSessions 1");
const { data } = await apiRequest.delete( const { data } = await apiRequest.delete(
"/api/v2/users/me/sessions" "/api/v2/users/me/sessions"
); );
console.log("useRevokeAllSessions 2: ", data);
return data; return data;
}, },
onSuccess() { onSuccess() {
@@ -2,7 +2,7 @@ import { FormEvent, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import Link from "next/link"; import Link from "next/link";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { faGoogle } from "@fortawesome/free-brands-svg-icons"; import { faGithub,faGoogle } from "@fortawesome/free-brands-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import axios from "axios" import axios from "axios"
@@ -34,7 +34,6 @@ export const InitialStep = ({
const { t } = useTranslation(); const { t } = useTranslation();
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [loginError, setLoginError] = useState(false); const [loginError, setLoginError] = useState(false);
const [loginEmailChosen, setLoginEmailChosen] = useState(false);
const { data: serverDetails } = useFetchServerStatus(); const { data: serverDetails } = useFetchServerStatus();
const queryParams = new URLSearchParams(window.location.search); const queryParams = new URLSearchParams(window.location.search);
@@ -68,8 +67,7 @@ export const InitialStep = ({
// send request to server endpoint // send request to server endpoint
const instance = axios.create() const instance = axios.create()
const cliResp = await instance.post(cliUrl, { ...isCliLoginSuccessful.loginResponse }) await instance.post(cliUrl, { ...isCliLoginSuccessful.loginResponse })
console.log(cliResp)
// cli page // cli page
router.push("/cli-redirect"); router.push("/cli-redirect");
@@ -118,23 +116,6 @@ export const InitialStep = ({
return ( return (
<form onSubmit={handleLogin} className='flex flex-col mx-auto w-full justify-center items-center'> <form onSubmit={handleLogin} className='flex flex-col mx-auto w-full justify-center items-center'>
<h1 className='text-xl font-medium text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200 text-center mb-8' >Login to Infisical</h1> <h1 className='text-xl font-medium text-transparent bg-clip-text bg-gradient-to-b from-white to-bunker-200 text-center mb-8' >Login to Infisical</h1>
<div className='lg:w-1/6 w-1/4 min-w-[21.2rem] md:min-w-[20.1rem] text-center rounded-md mt-4'>
<Button
colorSchema="primary"
variant={loginEmailChosen ? "outline_bg" : "solid"}
onClick={() => {
const callbackPort = queryParams.get("callback_port");
window.open(`/api/v1/sso/redirect/google${callbackPort ? `?callback_port=${callbackPort}` : ""}`);
window.close();
}}
leftIcon={<FontAwesomeIcon icon={faGoogle} className="mr-1" />}
className="h-12 w-full mx-0"
>
{t("login.continue-with-google")}
</Button>
</div>
{loginEmailChosen && <>
<div className='lg:w-1/6 w-1/4 min-w-[20rem] flex flex-row items-center my-4 py-2'> <div className='lg:w-1/6 w-1/4 min-w-[20rem] flex flex-row items-center my-4 py-2'>
<div className='w-full border-t border-mineshaft-500' /> <div className='w-full border-t border-mineshaft-500' />
</div> </div>
@@ -175,19 +156,40 @@ export const InitialStep = ({
{!isLoading && loginError && <Error text={t("login.error-login") ?? ""} />} {!isLoading && loginError && <Error text={t("login.error-login") ?? ""} />}
<div className='lg:w-1/6 w-1/4 min-w-[20rem] flex flex-row items-center mt-4 py-2'> <div className='lg:w-1/6 w-1/4 min-w-[20rem] flex flex-row items-center mt-4 py-2'>
<div className='w-full border-t border-mineshaft-500' /> <div className='w-full border-t border-mineshaft-500' />
</div></>} </div>
{!loginEmailChosen && <div className='lg:w-1/6 w-1/4 min-w-[21.2rem] md:min-w-[20.1rem] text-center rounded-md mt-4'> <div className='lg:w-1/6 w-1/4 min-w-[21.2rem] md:min-w-[20.1rem] text-center rounded-md mt-4'>
<Button <Button
onClick={() => {
setLoginEmailChosen(true);
}}
size="sm"
isFullWidth
className='h-12'
colorSchema="primary" colorSchema="primary"
variant="outline_bg" variant="outline_bg"
> Continue with Email </Button> onClick={() => {
</div>} const callbackPort = queryParams.get("callback_port");
window.open(`/api/v1/sso/redirect/google${callbackPort ? `?callback_port=${callbackPort}` : ""}`);
window.close();
}}
leftIcon={<FontAwesomeIcon icon={faGoogle} className="mr-2" />}
className="h-12 w-full mx-0"
>
{t("login.continue-with-google")}
</Button>
</div>
<div className='lg:w-1/6 w-1/4 min-w-[21.2rem] md:min-w-[20.1rem] text-center rounded-md mt-4'>
<Button
colorSchema="primary"
variant="outline_bg"
onClick={() => {
const callbackPort = queryParams.get("callback_port");
window.open(`/api/v1/sso/redirect/github${callbackPort ? `?callback_port=${callbackPort}` : ""}`);
window.close();
}}
leftIcon={<FontAwesomeIcon icon={faGithub} className="mr-2" />}
className="h-12 w-full mx-0"
>
Continue with GitHub
</Button>
</div>
<div className='lg:w-1/6 w-1/4 min-w-[21.2rem] md:min-w-[20.1rem] text-center rounded-md mt-4'> <div className='lg:w-1/6 w-1/4 min-w-[21.2rem] md:min-w-[20.1rem] text-center rounded-md mt-4'>
<Button <Button
colorSchema="primary" colorSchema="primary"
@@ -17,7 +17,10 @@ import {
const authMethods = [ const authMethods = [
{ label: "Email", value: "email" }, { label: "Email", value: "email" },
{ label: "Google SSO", value: "google" }, { label: "Google SSO", value: "google" },
{ label: "Okta SAML 2.0", value: "okta-saml" }, { label: "GitHub SSO", value: "github" },
{ label: "Okta SAML", value: "okta-saml" },
{ label: "Azure SAML", value: "azure-saml" },
{ label: "JumpCloud SAML", value: "jumpcloud-saml" }
]; ];
const schema = yup.object({ const schema = yup.object({
@@ -54,9 +57,13 @@ export const AuthMethodSection = () => {
authMethod authMethod
}: FormData) => { }: FormData) => {
try { try {
if (authMethod === "okta-saml") { if (
authMethod === "okta-saml"
|| authMethod === "azure-saml"
|| authMethod === "jumpcloud-saml"
) {
createNotification({ createNotification({
text: "Okta SAML 2.0 can only be configured in your organization settings", text: "SAML authentication can only be configured in your organization settings",
type: "error" type: "error"
}); });