feat: refactored login
This commit is contained in:
parent
0f40578ca9
commit
ffc927759e
|
@ -13,6 +13,50 @@ export default async function updateUserById(
|
||||||
userId: number,
|
userId: number,
|
||||||
data: AccountSettings
|
data: AccountSettings
|
||||||
) {
|
) {
|
||||||
|
const ssoUser = await prisma.account.findFirst({
|
||||||
|
where: {
|
||||||
|
userId: userId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const user = await prisma.user.findUnique({
|
||||||
|
where: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (ssoUser) { // deny changes to SSO-defined properties
|
||||||
|
if (data.email !== user?.email) {
|
||||||
|
return {
|
||||||
|
response: "SSO users cannot change their email.",
|
||||||
|
status: 400,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (data.newPassword) {
|
||||||
|
return {
|
||||||
|
response: "SSO Users cannot change their password.",
|
||||||
|
status: 400,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (data.name !== user?.name) {
|
||||||
|
return {
|
||||||
|
response: "SSO Users cannot change their name.",
|
||||||
|
status: 400,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (data.username !== user?.username) {
|
||||||
|
return {
|
||||||
|
response: "SSO Users cannot change their username.",
|
||||||
|
status: 400,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (data.image !== "") {
|
||||||
|
return {
|
||||||
|
response: "SSO Users cannot change their avatar.",
|
||||||
|
status: 400,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
} else { // verify only for non-SSO users
|
||||||
|
// SSO users cannot change their email, password, name, username, or avatar
|
||||||
if (emailEnabled && !data.email)
|
if (emailEnabled && !data.email)
|
||||||
return {
|
return {
|
||||||
response: "Email invalid.",
|
response: "Email invalid.",
|
||||||
|
@ -28,7 +72,6 @@ export default async function updateUserById(
|
||||||
response: "Password must be at least 8 characters.",
|
response: "Password must be at least 8 characters.",
|
||||||
status: 400,
|
status: 400,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check email (if enabled)
|
// Check email (if enabled)
|
||||||
const checkEmail =
|
const checkEmail =
|
||||||
/^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
|
/^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i;
|
||||||
|
@ -114,11 +157,15 @@ export default async function updateUserById(
|
||||||
} else if (data.image == "") {
|
} else if (data.image == "") {
|
||||||
removeFile({ filePath: `uploads/avatar/${userId}.jpg` });
|
removeFile({ filePath: `uploads/avatar/${userId}.jpg` });
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const previousEmail = (
|
const previousEmail = (
|
||||||
await prisma.user.findUnique({ where: { id: userId } })
|
await prisma.user.findUnique({ where: { id: userId } })
|
||||||
)?.email;
|
)?.email;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Other settings
|
// Other settings
|
||||||
|
|
||||||
const saltRounds = 10;
|
const saltRounds = 10;
|
||||||
|
@ -130,7 +177,7 @@ export default async function updateUserById(
|
||||||
},
|
},
|
||||||
data: {
|
data: {
|
||||||
name: data.name,
|
name: data.name,
|
||||||
username: data.username.toLowerCase().trim(),
|
username: data.username?.toLowerCase().trim(),
|
||||||
email: data.email?.toLowerCase().trim(),
|
email: data.email?.toLowerCase().trim(),
|
||||||
isPrivate: data.isPrivate,
|
isPrivate: data.isPrivate,
|
||||||
image: data.image ? `uploads/avatar/${userId}.jpg` : "",
|
image: data.image ? `uploads/avatar/${userId}.jpg` : "",
|
||||||
|
|
|
@ -31,13 +31,18 @@ export default async function verifyUser({
|
||||||
subscriptions: true,
|
subscriptions: true,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
const ssoUser = await prisma.account.findFirst({
|
||||||
|
where: {
|
||||||
|
userId: userId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
res.status(404).json({ response: "User not found." });
|
res.status(404).json({ response: "User not found." });
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!user.username) {
|
if (!user.username && !ssoUser) { // SSO users don't need a username
|
||||||
res.status(401).json({
|
res.status(401).json({
|
||||||
response: "Username not found.",
|
response: "Username not found.",
|
||||||
});
|
});
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,31 @@
|
||||||
|
import type { NextApiRequest, NextApiResponse } from 'next';
|
||||||
|
import * as process from "process";
|
||||||
|
|
||||||
|
export type ResponseData = {
|
||||||
|
credentialsEnabled: string|undefined
|
||||||
|
emailEnabled: string|undefined
|
||||||
|
registrationDisabled: string|undefined
|
||||||
|
buttonAuths: {
|
||||||
|
method: string
|
||||||
|
name: string
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
export default function handler(req: NextApiRequest, res: NextApiResponse<ResponseData>) {
|
||||||
|
res.json(getLogins());
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getLogins() {
|
||||||
|
const buttonAuths = []
|
||||||
|
if (process.env.NEXT_PUBLIC_KEYCLOAK_ENABLED === 'true') {
|
||||||
|
buttonAuths.push({method: 'keycloak', name: 'Keycloak'});
|
||||||
|
}
|
||||||
|
if (process.env.NEXT_PUBLIC_AUTHENTIK_ENABLED === 'true') {
|
||||||
|
buttonAuths.push({method: 'authentik', name: process.env.AUTHENTIK_CUSTOM_NAME ?? 'Authentik'});
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
credentialsEnabled: (process.env.NEXT_PUBLIC_CREDENTIALS_ENABLED === 'true' || process.env.NEXT_PUBLIC_CREDENTIALS_ENABLED === undefined) ? "true" : "false",
|
||||||
|
emailEnabled: process.env.NEXT_PUBLIC_EMAIL_PROVIDER,
|
||||||
|
registrationDisabled: process.env.NEXT_PUBLIC_DISABLE_REGISTRATION,
|
||||||
|
buttonAuths: buttonAuths
|
||||||
|
};
|
||||||
|
}
|
|
@ -5,16 +5,21 @@ import { signIn } from "next-auth/react";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useState, FormEvent } from "react";
|
import { useState, FormEvent } from "react";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
|
import {getLogins} from './api/v1/logins'
|
||||||
|
import {InferGetServerSidePropsType} from "next";
|
||||||
|
|
||||||
interface FormData {
|
interface FormData {
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const emailEnabled = process.env.NEXT_PUBLIC_EMAIL_PROVIDER;
|
export const getServerSideProps = (() => {
|
||||||
const keycloakEnabled = process.env.NEXT_PUBLIC_KEYCLOAK_ENABLED;
|
const availableLogins = getLogins();
|
||||||
|
return {props: {availableLogins}}
|
||||||
|
});
|
||||||
|
|
||||||
export default function Login() {
|
|
||||||
|
export default function Login({availableLogins} : InferGetServerSidePropsType<typeof getServerSideProps>) {
|
||||||
const [submitLoader, setSubmitLoader] = useState(false);
|
const [submitLoader, setSubmitLoader] = useState(false);
|
||||||
|
|
||||||
const [form, setForm] = useState<FormData>({
|
const [form, setForm] = useState<FormData>({
|
||||||
|
@ -48,32 +53,28 @@ export default function Login() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loginUserKeycloak() {
|
async function loginUserButton(method: string) {
|
||||||
setSubmitLoader(true);
|
setSubmitLoader(true);
|
||||||
|
|
||||||
const load = toast.loading("Authenticating...");
|
const load = toast.loading("Authenticating...");
|
||||||
|
|
||||||
const res = await signIn("keycloak", {});
|
const res = await signIn(method, {});
|
||||||
|
|
||||||
toast.dismiss(load);
|
toast.dismiss(load);
|
||||||
|
|
||||||
setSubmitLoader(false);
|
setSubmitLoader(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
function displayLoginCredential() {
|
||||||
<CenteredForm text="Sign in to your account">
|
if (availableLogins.credentialsEnabled === 'true') {
|
||||||
<form onSubmit={loginUser}>
|
return (<><p className="text-3xl text-black dark:text-white text-center font-extralight">
|
||||||
<div className="p-4 mx-auto flex flex-col gap-3 justify-between max-w-[30rem] min-w-80 w-full bg-slate-50 dark:bg-neutral-800 rounded-2xl shadow-md border border-sky-100 dark:border-neutral-700">
|
|
||||||
<p className="text-3xl text-black dark:text-white text-center font-extralight">
|
|
||||||
Enter your credentials
|
Enter your credentials
|
||||||
</p>
|
</p>
|
||||||
|
<hr className="border-1 border-sky-100 dark:border-neutral-700"/>
|
||||||
<hr className="border-1 border-sky-100 dark:border-neutral-700" />
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<p className="text-sm text-black dark:text-white w-fit font-semibold mb-1">
|
<p className="text-sm text-black dark:text-white w-fit font-semibold mb-1">
|
||||||
Username
|
Username
|
||||||
{emailEnabled ? " or Email" : undefined}
|
{availableLogins.emailEnabled === 'true' ? " or Email" : undefined}
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<TextInput
|
<TextInput
|
||||||
|
@ -81,10 +82,8 @@ export default function Login() {
|
||||||
placeholder="johnny"
|
placeholder="johnny"
|
||||||
value={form.username}
|
value={form.username}
|
||||||
className="bg-white"
|
className="bg-white"
|
||||||
onChange={(e) => setForm({ ...form, username: e.target.value })}
|
onChange={(e) => setForm({...form, username: e.target.value})}/>
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<p className="text-sm text-black dark:text-white w-fit font-semibold mb-1">
|
<p className="text-sm text-black dark:text-white w-fit font-semibold mb-1">
|
||||||
Password
|
Password
|
||||||
|
@ -95,9 +94,8 @@ export default function Login() {
|
||||||
placeholder="••••••••••••••"
|
placeholder="••••••••••••••"
|
||||||
value={form.password}
|
value={form.password}
|
||||||
className="bg-white"
|
className="bg-white"
|
||||||
onChange={(e) => setForm({ ...form, password: e.target.value })}
|
onChange={(e) => setForm({...form, password: e.target.value})}/>
|
||||||
/>
|
{availableLogins.emailEnabled === 'true' && (
|
||||||
{emailEnabled && (
|
|
||||||
<div className="w-fit ml-auto mt-1">
|
<div className="w-fit ml-auto mt-1">
|
||||||
<Link
|
<Link
|
||||||
href={"/forgot"}
|
href={"/forgot"}
|
||||||
|
@ -108,24 +106,31 @@ export default function Login() {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SubmitButton
|
<SubmitButton
|
||||||
type="submit"
|
type="submit"
|
||||||
label="Login"
|
label="Login"
|
||||||
className=" w-full text-center"
|
className=" w-full text-center"
|
||||||
loading={submitLoader}
|
loading={submitLoader}/></>
|
||||||
/>
|
)
|
||||||
{process.env.NEXT_PUBLIC_KEYCLOAK_ENABLED === "true" ? (
|
}
|
||||||
<SubmitButton
|
}
|
||||||
|
function displayLoginExternalButton() {
|
||||||
|
const Buttons: any = [];
|
||||||
|
availableLogins.buttonAuths.forEach((value, index) => {
|
||||||
|
Buttons.push(<SubmitButton key={index}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={loginUserKeycloak}
|
onClick={() => loginUserButton(value.method)}
|
||||||
label="Sign in with Keycloak"
|
label={`Sign in with ${value.name}`}
|
||||||
className=" w-full text-center"
|
className=" w-full text-center"
|
||||||
loading={submitLoader}
|
loading={submitLoader}
|
||||||
/>
|
/>);
|
||||||
) : undefined}
|
});
|
||||||
{process.env.NEXT_PUBLIC_DISABLE_REGISTRATION ===
|
return (Buttons);
|
||||||
"true" ? undefined : (
|
}
|
||||||
|
|
||||||
|
function displayRegistration() {
|
||||||
|
if (availableLogins.registrationDisabled !== 'true') {
|
||||||
|
return (
|
||||||
<div className="flex items-baseline gap-1 justify-center">
|
<div className="flex items-baseline gap-1 justify-center">
|
||||||
<p className="w-fit text-gray-500 dark:text-gray-400">
|
<p className="w-fit text-gray-500 dark:text-gray-400">
|
||||||
New here?
|
New here?
|
||||||
|
@ -137,7 +142,17 @@ export default function Login() {
|
||||||
Sign Up
|
Sign Up
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)}
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CenteredForm text="Sign in to your account">
|
||||||
|
<form onSubmit={loginUser}>
|
||||||
|
<div className="p-4 mx-auto flex flex-col gap-3 justify-between max-w-[30rem] min-w-80 w-full bg-slate-50 dark:bg-neutral-800 rounded-2xl shadow-md border border-sky-100 dark:border-neutral-700">
|
||||||
|
{displayLoginCredential()}
|
||||||
|
{displayLoginExternalButton()}
|
||||||
|
{displayRegistration()}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</CenteredForm>
|
</CenteredForm>
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useState, FormEvent } from "react";
|
import { useState, FormEvent } from "react";
|
||||||
import { toast } from "react-hot-toast";
|
import { toast } from "react-hot-toast";
|
||||||
import SubmitButton from "@/components/SubmitButton";
|
|
||||||
import { signIn } from "next-auth/react";
|
import { signIn } from "next-auth/react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import CenteredForm from "@/layouts/CenteredForm";
|
import CenteredForm from "@/layouts/CenteredForm";
|
||||||
import TextInput from "@/components/TextInput";
|
import TextInput from "@/components/TextInput";
|
||||||
|
|
||||||
const emailEnabled = process.env.NEXT_PUBLIC_EMAIL_PROVIDER;
|
const emailEnabled = process.env.NEXT_PUBLIC_EMAIL_PROVIDER === "true";
|
||||||
|
|
||||||
type FormData = {
|
type FormData = {
|
||||||
name: string;
|
name: string;
|
||||||
|
|
|
@ -17,10 +17,8 @@ declare global {
|
||||||
SPACES_REGION?: string;
|
SPACES_REGION?: string;
|
||||||
SPACES_FORCE_PATH_STYLE?: string;
|
SPACES_FORCE_PATH_STYLE?: string;
|
||||||
|
|
||||||
NEXT_PUBLIC_KEYCLOAK_ENABLED?: string;
|
NEXT_PUBLIC_CREDENTIALS_ENABLED?: string;
|
||||||
KEYCLOAK_ISSUER?: string;
|
DISABLE_NEW_SSO_USERS?: string;
|
||||||
KEYCLOAK_CLIENT_ID?: string;
|
|
||||||
KEYCLOAK_CLIENT_SECRET?: string;
|
|
||||||
|
|
||||||
NEXT_PUBLIC_EMAIL_PROVIDER?: string;
|
NEXT_PUBLIC_EMAIL_PROVIDER?: string;
|
||||||
EMAIL_FROM?: string;
|
EMAIL_FROM?: string;
|
||||||
|
@ -33,6 +31,367 @@ declare global {
|
||||||
NEXT_PUBLIC_STRIPE_BILLING_PORTAL_URL?: string;
|
NEXT_PUBLIC_STRIPE_BILLING_PORTAL_URL?: string;
|
||||||
NEXT_PUBLIC_TRIAL_PERIOD_DAYS?: string;
|
NEXT_PUBLIC_TRIAL_PERIOD_DAYS?: string;
|
||||||
BASE_URL?: string;
|
BASE_URL?: string;
|
||||||
|
|
||||||
|
//
|
||||||
|
// SSO Providers
|
||||||
|
//
|
||||||
|
|
||||||
|
// 42 School
|
||||||
|
NEXT_PUBLIC_FORTYTWO_ENABLED?: string;
|
||||||
|
FORTYTWO_CUSTOM_NAME?: string;
|
||||||
|
FORTYTWO_CLIENT_ID?: string;
|
||||||
|
FORTYTWO_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Apple
|
||||||
|
NEXT_PUBLIC_APPLE_ENABLED?: string;
|
||||||
|
APPLE_CUSTOM_NAME?: string;
|
||||||
|
APPLE_ID?: string;
|
||||||
|
APPLE_SECRET?: string;
|
||||||
|
|
||||||
|
// Atlassian
|
||||||
|
NEXT_PUBLIC_ATLASSIAN_ENABLED?: string;
|
||||||
|
ATLASSIAN_CUSTOM_NAME?: string;
|
||||||
|
ATLASSIAN_CLIENT_ID?: string;
|
||||||
|
ATLASSIAN_CLIENT_SECRET?: string;
|
||||||
|
ATLASSIAN_SCOPE?: string;
|
||||||
|
|
||||||
|
// Auth0
|
||||||
|
NEXT_PUBLIC_AUTH0_ENABLED?: string;
|
||||||
|
AUTH0_CUSTOM_NAME?: string;
|
||||||
|
AUTH0_ISSUER?: string;
|
||||||
|
AUTH0_CLIENT_SECRET?: string;
|
||||||
|
AUTH0_CLIENT_ID?: string;
|
||||||
|
|
||||||
|
// Authentik
|
||||||
|
NEXT_PUBLIC_AUTHENTIK_ENABLED?: string;
|
||||||
|
AUTHENTIK_CUSTOM_NAME?: string;
|
||||||
|
AUTHENTIK_ISSUER?: string;
|
||||||
|
AUTHENTIK_CLIENT_ID?: string;
|
||||||
|
AUTHENTIK_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// TODO: Azure AD B2C
|
||||||
|
// TODO: Azure AD
|
||||||
|
|
||||||
|
// Battle.net
|
||||||
|
NEXT_PUBLIC_BATTLENET_ENABLED?: string;
|
||||||
|
BATTLENET_CUSTOM_NAME?: string;
|
||||||
|
BATTLENET_CLIENT_ID?: string;
|
||||||
|
BATTLENET_CLIENT_SECRET?: string;
|
||||||
|
BATLLENET_ISSUER?: string;
|
||||||
|
|
||||||
|
// Box
|
||||||
|
NEXT_PUBLIC_BOX_ENABLED?: string;
|
||||||
|
BOX_CUSTOM_NAME?: string;
|
||||||
|
BOX_CLIENT_ID?: string;
|
||||||
|
BOX_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// TODO: BoxyHQ SAML
|
||||||
|
|
||||||
|
// Bungie
|
||||||
|
NEXT_PUBLIC_BUNGIE_ENABLED?: string;
|
||||||
|
BUNGIE_CUSTOM_NAME?: string;
|
||||||
|
BUNGIE_CLIENT_ID?: string;
|
||||||
|
BUNGIE_CLIENT_SECRET?: string;
|
||||||
|
BUNGIE_API_KEY?: string;
|
||||||
|
|
||||||
|
// Cognito
|
||||||
|
NEXT_PUBLIC_COGNITO_ENABLED?: string;
|
||||||
|
COGNITO_CUSTOM_NAME?: string;
|
||||||
|
COGNITO_CLIENT_ID?: string;
|
||||||
|
COGNITO_CLIENT_SECRET?: string;
|
||||||
|
COGNITO_ISSUER?: string;
|
||||||
|
|
||||||
|
// Coinbase
|
||||||
|
NEXT_PUBLIC_COINBASE_ENABLED?: string;
|
||||||
|
COINBASE_CUSTOM_NAME?: string;
|
||||||
|
COINBASE_CLIENT_ID?: string;
|
||||||
|
COINBASE_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Discord
|
||||||
|
NEXT_PUBLIC_DISCORD_ENABLED?: string;
|
||||||
|
DISCORD_CUSTOM_NAME?: string;
|
||||||
|
DISCORD_CLIENT_ID?: string;
|
||||||
|
DISCORD_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Dropbox
|
||||||
|
NEXT_PUBLIC_DROPBOX_ENABLED?: string;
|
||||||
|
DROPBOX_CUSTOM_NAME?: string;
|
||||||
|
DROPBOX_CLIENT_ID?: string;
|
||||||
|
DROPBOX_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// DuendeIndentityServer6
|
||||||
|
NEXT_PUBLIC_DUENDE_IDS6_ENABLED?: string;
|
||||||
|
DUENDE_IDS6_CUSTOM_NAME?: string;
|
||||||
|
DUENDE_IDS6_CLIENT_ID?: string;
|
||||||
|
DUENDE_IDS6_CLIENT_SECRET?: string;
|
||||||
|
DUENDE_IDS6_ISSUER?: string;
|
||||||
|
|
||||||
|
// EVE Online
|
||||||
|
NEXT_PUBLIC_EVEONLINE_ENABLED?: string;
|
||||||
|
EVEONLINE_CUSTOM_NAME?: string;
|
||||||
|
EVEONLINE_CLIENT_ID?: string;
|
||||||
|
EVEONLINE_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Facebook
|
||||||
|
NEXT_PUBLIC_FACEBOOK_ENABLED?: string;
|
||||||
|
FACEBOOK_CUSTOM_NAME?: string;
|
||||||
|
FACEBOOK_CLIENT_ID?: string;
|
||||||
|
FACEBOOK_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// FACEIT
|
||||||
|
NEXT_PUBLIC_FACEIT_ENABLED?: string;
|
||||||
|
FACEIT_CUSTOM_NAME?: string;
|
||||||
|
FACEIT_CLIENT_ID?: string;
|
||||||
|
FACEIT_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Foursquare
|
||||||
|
NEXT_PUBLIC_FOURSQUARE_ENABLED?: string;
|
||||||
|
FOURSQUARE_CUSTOM_NAME?: string;
|
||||||
|
FOURSQUARE_CLIENT_ID?: string;
|
||||||
|
FOURSQUARE_CLIENT_SECRET?: string;
|
||||||
|
FOURSQUARE_APIVERSION?: string;
|
||||||
|
|
||||||
|
// Freshbooks
|
||||||
|
NEXT_PUBLIC_FRESHBOOKS_ENABLED?: string;
|
||||||
|
FRESHBOOKS_CUSTOM_NAME?: string;
|
||||||
|
FRESHBOOKS_CLIENT_ID?: string;
|
||||||
|
FRESHBOOKS_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// FusionAuth
|
||||||
|
NEXT_PUBLIC_FUSIONAUTH_ENABLED?: string;
|
||||||
|
FUSIONAUTH_CUSTOM_NAME?: string;
|
||||||
|
FUSIONAUTH_CLIENT_ID?: string;
|
||||||
|
FUSIONAUTH_CLIENT_SECRET?: string;
|
||||||
|
FUSIONAUTH_ISSUER?: string;
|
||||||
|
FUSIONAUTH_TENANT_ID?: string;
|
||||||
|
|
||||||
|
// GitHub
|
||||||
|
NEXT_PUBLIC_GITHUB_ENABLED?: string;
|
||||||
|
GITHUB_CUSTOM_NAME?: string;
|
||||||
|
GITHUB_CLIENT_ID?: string;
|
||||||
|
GITHUB_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// GitLab
|
||||||
|
NEXT_PUBLIC_GITLAB_ENABLED?: string;
|
||||||
|
GITLAB_CUSTOM_NAME?: string;
|
||||||
|
GITLAB_CLIENT_ID?: string;
|
||||||
|
GITLAB_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Google
|
||||||
|
NEXT_PUBLIC_GOOGLE_ENABLED?: string;
|
||||||
|
NEXT_PUBLIC_GOOGLE_CUSTOM_NAME?: string;
|
||||||
|
GOOGLE_CLIENT_ID?: string;
|
||||||
|
GOOGLE_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// HubSpot
|
||||||
|
NEXT_PUBLIC_HUBSPOT_ENABLED?: string;
|
||||||
|
HUBSPOT_CUSTOM_NAME?: string;
|
||||||
|
HUBSPOT_CLIENT_ID?: string;
|
||||||
|
HUBSPOT_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// IdentityServer4
|
||||||
|
NEXT_PUBLIC_IDS4_ENABLED?: string;
|
||||||
|
IDS4_CUSTOM_NAME?: string;
|
||||||
|
IDS4_CLIENT_ID?: string;
|
||||||
|
IDS4_CLIENT_SECRET?: string;
|
||||||
|
IDS4_ISSUER?: string;
|
||||||
|
|
||||||
|
// TODO: Instagram (Doesn't return email)
|
||||||
|
|
||||||
|
// Kakao
|
||||||
|
NEXT_PUBLIC_KAKAO_ENABLED?: string;
|
||||||
|
KAOKAO_CUSTOM_NAME?: string;
|
||||||
|
KAKAO_CLIENT_ID?: string;
|
||||||
|
KAKAO_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Keycloak
|
||||||
|
NEXT_PUBLIC_KEYCLOAK_ENABLED?: string;
|
||||||
|
KEYCLOAK_CUSTOM_NAME?: string;
|
||||||
|
KEYCLOAK_ISSUER?: string;
|
||||||
|
KEYCLOAK_CLIENT_ID?: string;
|
||||||
|
KEYCLOAK_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// LINE
|
||||||
|
NEXT_PUBLIC_LINE_ENABLED?: string;
|
||||||
|
LINE_CUSTOM_NAME?: string;
|
||||||
|
LINE_CLIENT_ID?: string;
|
||||||
|
LINE_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// LinkedIn
|
||||||
|
NEXT_PUBLIC_LINKEDIN_ENABLED?: string;
|
||||||
|
LINKEDIN_CUSTOM_NAME?: string;
|
||||||
|
LINKEDIN_CLIENT_ID?: string;
|
||||||
|
LINKEDIN_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Mailchimp
|
||||||
|
NEXT_PUBLIC_MAILCHIMP_ENABLED?: string;
|
||||||
|
MAILCHIMP_CUSTOM_NAME?: string;
|
||||||
|
MAILCHIMP_CLIENT_ID?: string;
|
||||||
|
MAILCHIMP_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Mail.ru
|
||||||
|
NEXT_PUBLIC_MAILRU_ENABLED?: string;
|
||||||
|
MAILRU_CUSTOM_NAME?: string;
|
||||||
|
MAILRU_CLIENT_ID?: string;
|
||||||
|
MAILRU_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// TODO: Medium (Doesn't return email)
|
||||||
|
|
||||||
|
// Naver
|
||||||
|
NEXT_PUBLIC_NAVER_ENABLED?: string;
|
||||||
|
NAVER_CUSTOM_NAME?: string;
|
||||||
|
NAVER_CLIENT_ID?: string;
|
||||||
|
NAVER_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Netlify
|
||||||
|
NEXT_PUBLIC_NETLIFY_ENABLED?: string;
|
||||||
|
NETLIFY_CUSTOM_NAME?: string;
|
||||||
|
NETLIFY_CLIENT_ID?: string;
|
||||||
|
NETLIFY_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Okta
|
||||||
|
NEXT_PUBLIC_OKTA_ENABLED?: string;
|
||||||
|
OKTA_CUSTOM_NAME?: string;
|
||||||
|
OKTA_CLIENT_ID?: string;
|
||||||
|
OKTA_CLIENT_SECRET?: string;
|
||||||
|
OKTA_ISSUER?: string;
|
||||||
|
|
||||||
|
// OneLogin
|
||||||
|
NEXT_PUBLIC_ONELOGIN_ENABLED?: string;
|
||||||
|
ONELOGIN_CUSTOM_NAME?: string;
|
||||||
|
ONELOGIN_CLIENT_ID?: string;
|
||||||
|
ONELOGIN_CLIENT_SECRET?: string;
|
||||||
|
ONELOGIN_ISSUER?: string;
|
||||||
|
|
||||||
|
// Osso
|
||||||
|
NEXT_PUBLIC_OSSO_ENABLED?: string;
|
||||||
|
OSSO_CUSTOM_NAME?: string;
|
||||||
|
OSSO_CLIENT_ID?: string;
|
||||||
|
OSSO_CLIENT_SECRET?: string;
|
||||||
|
OSSO_ISSUER?: string;
|
||||||
|
|
||||||
|
// osu!
|
||||||
|
NEXT_PUBLIC_OSU_ENABLED?: string;
|
||||||
|
OSU_CUSTOM_NAME?: string;
|
||||||
|
OSU_CLIENT_ID?: string;
|
||||||
|
OSU_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Patreon
|
||||||
|
NEXT_PUBLIC_PATREON_ENABLED?: string;
|
||||||
|
PATREON_CUSTOM_NAME?: string;
|
||||||
|
PATREON_CLIENT_ID?: string;
|
||||||
|
PATREON_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Pinterest
|
||||||
|
NEXT_PUBLIC_PINTEREST_ENABLED?: string;
|
||||||
|
PINTEREST_CUSTOM_NAME?: string;
|
||||||
|
PINTEREST_CLIENT_ID?: string;
|
||||||
|
PINTEREST_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Pipedrive
|
||||||
|
NEXT_PUBLIC_PIPEDRIVE_ENABLED?: string;
|
||||||
|
PIPEDRIVE_CUSTOM_NAME?: string;
|
||||||
|
PIPEDRIVE_CLIENT_ID?: string;
|
||||||
|
PIPEDRIVE_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Reddit
|
||||||
|
// TODO (1h tokens)
|
||||||
|
NEXT_PUBLIC_REDDIT_ENABLED?: string;
|
||||||
|
REDDIT_CUSTOM_NAME?: string;
|
||||||
|
REDDIT_CLIENT_ID?: string;
|
||||||
|
REDDIT_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Salesforce
|
||||||
|
NEXT_PUBLIC_SALESFORCE_ENABLED?: string;
|
||||||
|
SALESFORCE_CUSTOM_NAME?: string;
|
||||||
|
SALESFORCE_CLIENT_ID?: string;
|
||||||
|
SALESFORCE_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Slack
|
||||||
|
NEXT_PUBLIC_SLACK_ENABLED?: string;
|
||||||
|
SLACK_CUSTOM_NAME?: string;
|
||||||
|
SLACK_CLIENT_ID?: string;
|
||||||
|
SLACK_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Spotify
|
||||||
|
NEXT_PUBLIC_SPOTIFY_ENABLED?: string;
|
||||||
|
SPOTIFY_CUSTOM_NAME?: string;
|
||||||
|
SPOTIFY_CLIENT_ID?: string;
|
||||||
|
SPOTIFY_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Strava
|
||||||
|
NEXT_PUBLIC_STRAVA_ENABLED?: string;
|
||||||
|
STRAVA_CUSTOM_NAME?: string;
|
||||||
|
STRAVA_CLIENT_ID?: string;
|
||||||
|
STRAVA_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Todoist
|
||||||
|
NEXT_PUBLIC_TODOIST_ENABLED?: string;
|
||||||
|
TODOIST_CUSTOM_NAME?: string;
|
||||||
|
TODOIST_CLIENT_ID?: string;
|
||||||
|
TODOIST_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// TODO: Trakt (Doesn't return email)
|
||||||
|
|
||||||
|
// Twitch
|
||||||
|
NEXT_PUBLIC_TWITCH_ENABLED?: string;
|
||||||
|
TWITCH_CUSTOM_NAME?: string;
|
||||||
|
TWITCH_CLIENT_ID?: string;
|
||||||
|
TWITCH_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// TODO: Twitter (OAuth 1.0)
|
||||||
|
|
||||||
|
// United Effects
|
||||||
|
NEXT_PUBLIC_UNITED_EFFECTS_ENABLED?: string;
|
||||||
|
UNITED_EFFECTS_CUSTOM_NAME?: string;
|
||||||
|
UNITED_EFFECTS_CLIENT_ID?: string;
|
||||||
|
UNITED_EFFECTS_CLIENT_SECRET?: string;
|
||||||
|
UNITED_EFFECTS_ISSUER?: string;
|
||||||
|
|
||||||
|
// VK
|
||||||
|
NEXT_PUBLIC_VK_ENABLED?: string;
|
||||||
|
VK_CUSTOM_NAME?: string;
|
||||||
|
VK_CLIENT_ID?: string;
|
||||||
|
VK_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Wikimedia
|
||||||
|
NEXT_PUBLIC_WIKIMEDIA_ENABLED?: string;
|
||||||
|
WIKIMEDIA_CUSTOM_NAME?: string;
|
||||||
|
WIKIMEDIA_CLIENT_ID?: string;
|
||||||
|
WIKIMEDIA_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Wordpress.com
|
||||||
|
NEXT_PUBLIC_WORDPRESS_ENABLED?: string;
|
||||||
|
WORDPRESS_CUSTOM_NAME?: string;
|
||||||
|
WORDPRESS_CLIENT_ID?: string;
|
||||||
|
WORDPRESS_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// TODO: WorkOS (Custom flow)
|
||||||
|
|
||||||
|
// Yandex
|
||||||
|
NEXT_PUBLIC_YANDEX_ENABLED?: string;
|
||||||
|
YANDEX_CUSTOM_NAME?: string;
|
||||||
|
YANDEX_CLIENT_ID?: string;
|
||||||
|
YANDEX_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Zitadel
|
||||||
|
NEXT_PUBLIC_ZITADEL_ENABLED?: string;
|
||||||
|
ZITADEL_CUSTOM_NAME?: string;
|
||||||
|
ZITADEL_CLIENT_ID?: string;
|
||||||
|
ZITADEL_CLIENT_SECRET?: string;
|
||||||
|
ZITADEL_ISSUER?: string;
|
||||||
|
|
||||||
|
// Zoho
|
||||||
|
NEXT_PUBLIC_ZOHO_ENABLED?: string;
|
||||||
|
ZOHO_CUSTOM_NAME?: string;
|
||||||
|
ZOHO_CLIENT_ID?: string;
|
||||||
|
ZOHO_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
// Zoom
|
||||||
|
NEXT_PUBLIC_ZOOM_ENABLED?: string;
|
||||||
|
ZOOM_CUSTOM_NAME?: string;
|
||||||
|
ZOOM_CLIENT_ID?: string;
|
||||||
|
ZOOM_CLIENT_SECRET?: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Ŝarĝante…
Reference in New Issue