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

View File

@@ -45,6 +45,7 @@
"node-cache": "^5.1.2",
"nodemailer": "^6.8.0",
"passport": "^0.6.0",
"passport-github": "^1.1.0",
"passport-google-oauth20": "^2.0.0",
"posthog-node": "^2.6.0",
"probot": "^12.3.1",
@@ -11385,6 +11386,17 @@
"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": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/passport-google-oauth20/-/passport-google-oauth20-2.0.0.tgz",
@@ -22858,6 +22870,14 @@
"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": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/passport-google-oauth20/-/passport-google-oauth20-2.0.0.tgz",

View File

@@ -36,6 +36,7 @@
"node-cache": "^5.1.2",
"nodemailer": "^6.8.0",
"passport": "^0.6.0",
"passport-github": "^1.1.0",
"passport-google-oauth20": "^2.0.0",
"posthog-node": "^2.6.0",
"probot": "^12.3.1",

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 getClientIdGitHub = async () => (await client.getSecret("CLIENT_ID_GITHUB")).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 getClientSecretAzure = async () => (await client.getSecret("CLIENT_SECRET_AZURE")).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 getClientSecretGitHub = async () => (await client.getSecret("CLIENT_SECRET_GITHUB")).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 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 getPostHogProjectApiKey = async () => (await client.getSecret("POSTHOG_PROJECT_API_KEY")).secretValue || "phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE";
export const getSentryDSN = async () => (await client.getSecret("SENTRY_DSN")).secretValue;

View File

@@ -123,9 +123,15 @@ export const updateAuthProvider = async (req: Request, res: Response) => {
authProvider
} = req.body;
if (req.user?.authProvider === AuthProvider.OKTA_SAML) return res.status(400).send({
message: "Failed to update user authentication method because SAML SSO is enforced"
});
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"
});
}
const user = await User.findByIdAndUpdate(
req.user._id.toString(),

View File

@@ -41,6 +41,29 @@ router.get(
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(
"/redirect/saml2/:ssoIdentifier",
authLimiter,

View File

@@ -3,6 +3,7 @@ import { Document, Schema, Types, model } from "mongoose";
export enum AuthProvider {
EMAIL = "email",
GOOGLE = "google",
GITHUB = "github",
OKTA_SAML = "okta-saml",
AZURE_SAML = "azure-saml",
JUMPCLOUD_SAML = "jumpcloud-saml",

View File

@@ -50,7 +50,8 @@ router.patch(
}),
body("authProvider").exists().isString().isIn([
AuthProvider.EMAIL,
AuthProvider.GOOGLE
AuthProvider.GOOGLE,
AuthProvider.GITHUB
]),
validateRequest,
usersController.updateAuthProvider

View File

@@ -12,8 +12,10 @@ import {
} from "../models";
import { createToken } from "../helpers/auth";
import {
getClientIdGoogle,
getClientSecretGoogle,
getClientIdGitHubLogin,
getClientIdGoogleLogin,
getClientSecretGitHubLogin,
getClientSecretGoogleLogin,
getJwtProviderAuthLifetime,
getJwtProviderAuthSecret,
} from "../config";
@@ -25,6 +27,8 @@ import { getSiteURL } from "../config";
// eslint-disable-next-line @typescript-eslint/no-var-requires
const GoogleStrategy = require("passport-google-oauth20").Strategy;
// 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");
/**
@@ -67,42 +71,97 @@ const getAuthDataPayloadUserObj = (authData: AuthData) => {
}
const initializePassport = async () => {
const googleClientSecret = await getClientSecretGoogle();
const googleClientId = await getClientIdGoogle();
const clientIdGoogleLogin = await getClientIdGoogleLogin();
const clientSecretGoogleLogin = await getClientSecretGoogleLogin();
const clientIdGitHubLogin = await getClientIdGitHubLogin();
const clientSecretGitHubLogin = await getClientSecretGitHubLogin();
passport.use(new GoogleStrategy({
passReqToCallback: true,
clientID: googleClientId,
clientSecret: googleClientSecret,
callbackURL: "/api/v1/sso/google",
scope: ["profile", " email"],
}, async (
req: express.Request,
accessToken: string,
refreshToken: string,
profile: any,
done: any
) => {
try {
if (clientIdGoogleLogin && clientSecretGoogleLogin) {
passport.use(new GoogleStrategy({
passReqToCallback: true,
clientID: clientIdGoogleLogin,
clientSecret: clientSecretGoogleLogin,
callbackURL: "/api/v1/sso/google",
scope: ["profile", " email"],
}, async (
req: express.Request,
accessToken: string,
refreshToken: string,
profile: any,
done: any
) => {
try {
const email = profile.emails[0].value;
let user = await User.findOne({
email
}).select("+publicKey");
if (user && user.authProvider !== AuthProvider.GOOGLE) {
done(InternalServerError());
}
if (!user) {
user = await new User({
email,
authProvider: AuthProvider.GOOGLE,
authId: profile.id,
firstName: profile.name.givenName,
lastName: profile.name.familyName
}).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;
done(null, profile);
} catch (err) {
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;
const firstName = profile.name.givenName;
const lastName = profile.name.familyName;
let user = await User.findOne({
email
}).select("+publicKey");
if (user && user.authProvider !== AuthProvider.GOOGLE) {
if (user && user.authProvider !== AuthProvider.GITHUB) {
done(InternalServerError());
}
if (!user) {
user = await new User({
email,
authProvider: AuthProvider.GOOGLE,
email: email,
authProvider: AuthProvider.GITHUB,
authId: profile.id,
firstName,
lastName
firstName: profile.displayName,
lastName: ""
}).save();
}
@@ -111,8 +170,8 @@ const initializePassport = async () => {
payload: {
userId: user._id.toString(),
email: user.email,
firstName,
lastName,
firstName: user.firstName,
lastName: user.lastName,
authProvider: user.authProvider,
isUserCompleted,
...(req.query.state ? {
@@ -125,11 +184,10 @@ const initializePassport = async () => {
req.isUserCompleted = isUserCompleted;
req.providerAuthToken = providerAuthToken;
done(null, profile);
} catch (err) {
done(null, false);
return done(null, profile);
}
}));
));
}
passport.use("saml", new MultiSamlStrategy(
{

View File

@@ -24,8 +24,6 @@ import {
reencryptSecretBlindIndexDataSalts
} from "./reencryptData";
import {
getClientIdGoogle,
getClientSecretGoogle,
getMongoURL,
getNodeEnv,
getSentryDSN
@@ -55,12 +53,7 @@ export const setup = async () => {
// initializing the database connection
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
// to base64 256-bit ROOT_ENCRYPTION_KEY

View File

@@ -5,7 +5,7 @@ description: "Configure your environment variables when self-hosting Infisical."
## Backend environment variables
Depending on your choosen self hosted deployment method, you may need to configured at least the required environment variable listed below.
Depending on your choosen self hosted deployment method, you may need to configured at least the required environment variable listed below.
Other environment variables are listed below to increase the functionality of your self hosted instance based on your use case.
<Tabs>
@@ -14,25 +14,40 @@ 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`
</ParamField>
<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`
</ParamField>
{" "}
<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`
</ParamField>
<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`
</ParamField>
<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`
</ParamField>
{" "}
<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`
</ParamField>
<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`
</ParamField>
<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`
</ParamField>
{" "}
<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`
</ParamField>
{" "}
<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`
</ParamField>
{" "}
<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`
</ParamField>
<ParamField query="MONGO_URL" type="string" default="none" required>
*TLS based connection string is not yet supported
@@ -58,7 +73,7 @@ Other environment variables are listed below to increase the functionality of yo
</ParamField>
<ParamField query="SMTP_SECURE" type="string" default="none" optional>
If true, use TLS when connecting to host. If false, TLS will be used if STARTTLS is supported
If true, use TLS when connecting to host. If false, TLS will be used if STARTTLS is supported
</ParamField>
<ParamField query="SMTP_FROM_ADDRESS" type="string" default="none" optional>
@@ -68,9 +83,10 @@ Other environment variables are listed below to increase the functionality of yo
<ParamField query="SMTP_FROM_NAME" type="string" default="none" optional>
Name label to be used in From field (e.g. Team)
</ParamField>
</Tab>
<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
<ParamField query="CLIENT_ID_HEROKU" type="string" default="none" optional>
OAuth2 client ID for Heroku integration
@@ -81,7 +97,7 @@ Other environment variables are listed below to increase the functionality of yo
</ParamField>
<ParamField query="CLIENT_ID_VERCEL" type="string" default="none" optional>
OAuth2 client ID for Vercel integration
OAuth2 client ID for Vercel integration
</ParamField>
<ParamField query="CLIENT_SECRET_VERCEL" type="string" default="none" optional>
@@ -89,7 +105,7 @@ Other environment variables are listed below to increase the functionality of yo
</ParamField>
<ParamField query="CLIENT_ID_NETLIFY" type="string" default="none" optional>
OAuth2 client ID for Netlify integration
OAuth2 client ID for Netlify integration
</ParamField>
<ParamField query="CLIENT_SECRET_NETLIFY" type="string" default="none" optional>
@@ -97,7 +113,7 @@ Other environment variables are listed below to increase the functionality of yo
</ParamField>
<ParamField query="CLIENT_ID_GITHUB" type="string" default="none" optional>
OAuth2 client ID for GitHub integration
OAuth2 client ID for GitHub integration
</ParamField>
<ParamField query="CLIENT_SECRET_GITHUB" type="string" default="none" optional>
@@ -109,23 +125,30 @@ Other environment variables are listed below to increase the functionality of yo
</ParamField>
<ParamField query="CLIENT_ID_BITBUCKET" type="string" default="none" optional>
OAuth2 client ID for BitBucket integration
OAuth2 client ID for BitBucket integration
</ParamField>
<ParamField query="CLIENT_SECRET_BITBUCKET" type="string" default="none" optional>
OAuth2 client secret for BitBucket integration
</ParamField>
</Tab>
<Tab title="Auth Integrations">
To integrate with external auth providers, provide value for the related keys
<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`
</ParamField>
<ParamField query="CLIENT_ID_GOOGLE" type="string" default="none" optional>
OAuth2 client ID for Google auth integration
<ParamField query="CLIENT_ID_GOOGLE_LOGIN" type="string" default="none" optional>
OAuth2 client ID for Google login
</ParamField>
<ParamField query="CLIENT_SECRET_GOOGLE" type="string" default="none" optional>
OAuth2 client secret for Google auth integration
<ParamField query="CLIENT_SECRET_GOOGLE_LOGIN" type="string" default="none" optional>
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>
</Tab>
<Tab title="Others">
@@ -150,18 +173,44 @@ 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
</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>
#### Error logging
Infisical uses Sentry to report error logs
<ParamField query="SENTRY_DSN" type="string" default="none" optional></ParamField>
{" "}
#### Settings
<ParamField query="INVITE_ONLY_SIGNUP" type="string" default="false" optional>
Only allow users who are invited to sign up
</ParamField>
<ParamField
query="MONGO_PASSWORD"
type="string"
default="none"
optional
></ParamField>
#### Error logging
Infisical uses Sentry to report error logs
{" "}
<ParamField
query="SENTRY_DSN"
type="string"
default="none"
optional
></ParamField>
#### Settings
{" "}
<ParamField query="INVITE_ONLY_SIGNUP" type="string" default="false" optional>
Only allow users who are invited to sign up
</ParamField>
<ParamField query="SITE_URL" type="string" default="none" optional>
Site URL - should be an absolute URL including the protocol (e.g. https://app.infisical.com)
@@ -170,6 +219,11 @@ Other environment variables are listed below to increase the functionality of yo
</Tab>
</Tabs>
## Frontend environment variables
<ParamField query="TELEMETRY_ENABLED" type="string" default="true" optional></ParamField>
<ParamField
query="TELEMETRY_ENABLED"
type="string"
default="true"
optional
></ParamField>

View File

@@ -293,12 +293,10 @@ export const useRevokeMySessions = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async () => {
console.log("useRevokeAllSessions 1");
const { data } = await apiRequest.delete(
"/api/v2/users/me/sessions"
);
console.log("useRevokeAllSessions 2: ", data);
return data;
},
onSuccess() {

View File

@@ -2,7 +2,7 @@ import { FormEvent, useState } from "react";
import { useTranslation } from "react-i18next";
import Link from "next/link";
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 axios from "axios"
@@ -34,7 +34,6 @@ export const InitialStep = ({
const { t } = useTranslation();
const [isLoading, setIsLoading] = useState(false);
const [loginError, setLoginError] = useState(false);
const [loginEmailChosen, setLoginEmailChosen] = useState(false);
const { data: serverDetails } = useFetchServerStatus();
const queryParams = new URLSearchParams(window.location.search);
@@ -68,8 +67,7 @@ export const InitialStep = ({
// send request to server endpoint
const instance = axios.create()
const cliResp = await instance.post(cliUrl, { ...isCliLoginSuccessful.loginResponse })
console.log(cliResp)
await instance.post(cliUrl, { ...isCliLoginSuccessful.loginResponse })
// cli page
router.push("/cli-redirect");
@@ -118,23 +116,6 @@ export const InitialStep = ({
return (
<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>
<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='w-full border-t border-mineshaft-500' />
</div>
@@ -175,19 +156,40 @@ export const InitialStep = ({
{!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='w-full border-t border-mineshaft-500' />
</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>
<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
onClick={() => {
setLoginEmailChosen(true);
}}
size="sm"
isFullWidth
className='h-12'
colorSchema="primary"
colorSchema="primary"
variant="outline_bg"
> Continue with Email </Button>
</div>}
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-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'>
<Button
colorSchema="primary"

View File

@@ -17,7 +17,10 @@ import {
const authMethods = [
{ label: "Email", value: "email" },
{ 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({
@@ -54,9 +57,13 @@ export const AuthMethodSection = () => {
authMethod
}: FormData) => {
try {
if (authMethod === "okta-saml") {
if (
authMethod === "okta-saml"
|| authMethod === "azure-saml"
|| authMethod === "jumpcloud-saml"
) {
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"
});