mirror of
https://github.com/documenso/documenso.git
synced 2025-11-14 00:32:43 +10:00
feat: add oidc support
This commit is contained in:
4
apps/web/process-env.d.ts
vendored
4
apps/web/process-env.d.ts
vendored
@ -12,5 +12,9 @@ declare namespace NodeJS {
|
|||||||
|
|
||||||
NEXT_PRIVATE_GOOGLE_CLIENT_ID: string;
|
NEXT_PRIVATE_GOOGLE_CLIENT_ID: string;
|
||||||
NEXT_PRIVATE_GOOGLE_CLIENT_SECRET: string;
|
NEXT_PRIVATE_GOOGLE_CLIENT_SECRET: string;
|
||||||
|
|
||||||
|
NEXT_PRIVATE_OIDC_WELL_KNOWN: string;
|
||||||
|
NEXT_PRIVATE_OIDC_CLIENT_ID: string;
|
||||||
|
NEXT_PRIVATE_OIDC_CLIENT_SECRET: string;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { redirect } from 'next/navigation';
|
|||||||
|
|
||||||
import { env } from 'next-runtime-env';
|
import { env } from 'next-runtime-env';
|
||||||
|
|
||||||
import { IS_GOOGLE_SSO_ENABLED } from '@documenso/lib/constants/auth';
|
import { IS_GOOGLE_SSO_ENABLED, IS_OIDC_SSO_ENABLED } from '@documenso/lib/constants/auth';
|
||||||
import { decryptSecondaryData } from '@documenso/lib/server-only/crypto/decrypt';
|
import { decryptSecondaryData } from '@documenso/lib/server-only/crypto/decrypt';
|
||||||
|
|
||||||
import { SignInForm } from '~/components/forms/signin';
|
import { SignInForm } from '~/components/forms/signin';
|
||||||
@ -37,10 +37,13 @@ export default function SignInPage({ searchParams }: SignInPageProps) {
|
|||||||
<p className="text-muted-foreground mt-2 text-sm">
|
<p className="text-muted-foreground mt-2 text-sm">
|
||||||
Welcome back, we are lucky to have you.
|
Welcome back, we are lucky to have you.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<hr className="-mx-6 my-4" />
|
<hr className="-mx-6 my-4" />
|
||||||
|
|
||||||
<SignInForm initialEmail={email || undefined} isGoogleSSOEnabled={IS_GOOGLE_SSO_ENABLED} />
|
<SignInForm
|
||||||
|
initialEmail={email || undefined}
|
||||||
|
isGoogleSSOEnabled={IS_GOOGLE_SSO_ENABLED}
|
||||||
|
isOIDCSSOEnabled={IS_OIDC_SSO_ENABLED}
|
||||||
|
/>
|
||||||
|
|
||||||
{NEXT_PUBLIC_DISABLE_SIGNUP !== 'true' && (
|
{NEXT_PUBLIC_DISABLE_SIGNUP !== 'true' && (
|
||||||
<p className="text-muted-foreground mt-6 text-center text-sm">
|
<p className="text-muted-foreground mt-6 text-center text-sm">
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { redirect } from 'next/navigation';
|
|||||||
|
|
||||||
import { env } from 'next-runtime-env';
|
import { env } from 'next-runtime-env';
|
||||||
|
|
||||||
import { IS_GOOGLE_SSO_ENABLED } from '@documenso/lib/constants/auth';
|
import { IS_GOOGLE_SSO_ENABLED, IS_OIDC_SSO_ENABLED } from '@documenso/lib/constants/auth';
|
||||||
import { decryptSecondaryData } from '@documenso/lib/server-only/crypto/decrypt';
|
import { decryptSecondaryData } from '@documenso/lib/server-only/crypto/decrypt';
|
||||||
|
|
||||||
import { SignUpFormV2 } from '~/components/forms/v2/signup';
|
import { SignUpFormV2 } from '~/components/forms/v2/signup';
|
||||||
@ -37,6 +37,7 @@ export default function SignUpPage({ searchParams }: SignUpPageProps) {
|
|||||||
className="w-screen max-w-screen-2xl px-4 md:px-16 lg:-my-16"
|
className="w-screen max-w-screen-2xl px-4 md:px-16 lg:-my-16"
|
||||||
initialEmail={email || undefined}
|
initialEmail={email || undefined}
|
||||||
isGoogleSSOEnabled={IS_GOOGLE_SSO_ENABLED}
|
isGoogleSSOEnabled={IS_GOOGLE_SSO_ENABLED}
|
||||||
|
isOIDCSSOEnabled={IS_OIDC_SSO_ENABLED}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import { browserSupportsWebAuthn, startAuthentication } from '@simplewebauthn/br
|
|||||||
import { KeyRoundIcon } from 'lucide-react';
|
import { KeyRoundIcon } from 'lucide-react';
|
||||||
import { signIn } from 'next-auth/react';
|
import { signIn } from 'next-auth/react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
|
import { FaIdCardClip } from 'react-icons/fa6';
|
||||||
import { FcGoogle } from 'react-icons/fc';
|
import { FcGoogle } from 'react-icons/fc';
|
||||||
import { match } from 'ts-pattern';
|
import { match } from 'ts-pattern';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
@ -68,9 +69,15 @@ export type SignInFormProps = {
|
|||||||
className?: string;
|
className?: string;
|
||||||
initialEmail?: string;
|
initialEmail?: string;
|
||||||
isGoogleSSOEnabled?: boolean;
|
isGoogleSSOEnabled?: boolean;
|
||||||
|
isOIDCSSOEnabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SignInForm = ({ className, initialEmail, isGoogleSSOEnabled }: SignInFormProps) => {
|
export const SignInForm = ({
|
||||||
|
className,
|
||||||
|
initialEmail,
|
||||||
|
isGoogleSSOEnabled,
|
||||||
|
isOIDCSSOEnabled,
|
||||||
|
}: SignInFormProps) => {
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const { getFlag } = useFeatureFlags();
|
const { getFlag } = useFeatureFlags();
|
||||||
|
|
||||||
@ -256,6 +263,19 @@ export const SignInForm = ({ className, initialEmail, isGoogleSSOEnabled }: Sign
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onSignInWithOIDCClick = async () => {
|
||||||
|
try {
|
||||||
|
await signIn('oidc', { callbackUrl: LOGIN_REDIRECT_PATH });
|
||||||
|
} catch (err) {
|
||||||
|
toast({
|
||||||
|
title: 'An unknown error occurred',
|
||||||
|
description:
|
||||||
|
'We encountered an unknown error while attempting to sign you In. Please try again later.',
|
||||||
|
variant: 'destructive',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
@ -316,7 +336,7 @@ export const SignInForm = ({ className, initialEmail, isGoogleSSOEnabled }: Sign
|
|||||||
{isSubmitting ? 'Signing in...' : 'Sign In'}
|
{isSubmitting ? 'Signing in...' : 'Sign In'}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{(isGoogleSSOEnabled || isPasskeyEnabled) && (
|
{(isGoogleSSOEnabled || isPasskeyEnabled || isOIDCSSOEnabled) && (
|
||||||
<div className="relative flex items-center justify-center gap-x-4 py-2 text-xs uppercase">
|
<div className="relative flex items-center justify-center gap-x-4 py-2 text-xs uppercase">
|
||||||
<div className="bg-border h-px flex-1" />
|
<div className="bg-border h-px flex-1" />
|
||||||
<span className="text-muted-foreground bg-transparent">Or continue with</span>
|
<span className="text-muted-foreground bg-transparent">Or continue with</span>
|
||||||
@ -338,6 +358,20 @@ export const SignInForm = ({ className, initialEmail, isGoogleSSOEnabled }: Sign
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{isOIDCSSOEnabled && (
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
size="lg"
|
||||||
|
variant="outline"
|
||||||
|
className="bg-background text-muted-foreground border"
|
||||||
|
disabled={isSubmitting}
|
||||||
|
onClick={onSignInWithOIDCClick}
|
||||||
|
>
|
||||||
|
<FaIdCardClip className="mr-2 h-5 w-5" />
|
||||||
|
OIDC
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
{isPasskeyEnabled && (
|
{isPasskeyEnabled && (
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@ -52,9 +52,15 @@ export type SignUpFormProps = {
|
|||||||
className?: string;
|
className?: string;
|
||||||
initialEmail?: string;
|
initialEmail?: string;
|
||||||
isGoogleSSOEnabled?: boolean;
|
isGoogleSSOEnabled?: boolean;
|
||||||
|
isOIDCSSOEnabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SignUpForm = ({ className, initialEmail, isGoogleSSOEnabled }: SignUpFormProps) => {
|
export const SignUpForm = ({
|
||||||
|
className,
|
||||||
|
initialEmail,
|
||||||
|
isGoogleSSOEnabled,
|
||||||
|
isOIDCSSOEnabled,
|
||||||
|
}: SignUpFormProps) => {
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const analytics = useAnalytics();
|
const analytics = useAnalytics();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -121,6 +127,19 @@ export const SignUpForm = ({ className, initialEmail, isGoogleSSOEnabled }: Sign
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onSignUpWithOIDCClick = async () => {
|
||||||
|
try {
|
||||||
|
await signIn('google', { callbackUrl: SIGN_UP_REDIRECT_PATH });
|
||||||
|
} catch (err) {
|
||||||
|
toast({
|
||||||
|
title: 'An unknown error occurred',
|
||||||
|
description:
|
||||||
|
'We encountered an unknown error while attempting to sign you Up. Please try again later.',
|
||||||
|
variant: 'destructive',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
@ -221,6 +240,28 @@ export const SignUpForm = ({ className, initialEmail, isGoogleSSOEnabled }: Sign
|
|||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{isOIDCSSOEnabled && (
|
||||||
|
<>
|
||||||
|
<div className="relative flex items-center justify-center gap-x-4 py-2 text-xs uppercase">
|
||||||
|
<div className="bg-border h-px flex-1" />
|
||||||
|
<span className="text-muted-foreground bg-transparent">Or</span>
|
||||||
|
<div className="bg-border h-px flex-1" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
size="lg"
|
||||||
|
variant={'outline'}
|
||||||
|
className="bg-background text-muted-foreground border"
|
||||||
|
disabled={isSubmitting}
|
||||||
|
onClick={onSignUpWithOIDCClick}
|
||||||
|
>
|
||||||
|
<FcGoogle className="mr-2 h-5 w-5" />
|
||||||
|
Sign Up with OIDC
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</form>
|
</form>
|
||||||
</Form>
|
</Form>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import { zodResolver } from '@hookform/resolvers/zod';
|
|||||||
import { AnimatePresence, motion } from 'framer-motion';
|
import { AnimatePresence, motion } from 'framer-motion';
|
||||||
import { signIn } from 'next-auth/react';
|
import { signIn } from 'next-auth/react';
|
||||||
import { useForm } from 'react-hook-form';
|
import { useForm } from 'react-hook-form';
|
||||||
|
import { FaIdCardClip } from 'react-icons/fa6';
|
||||||
import { FcGoogle } from 'react-icons/fc';
|
import { FcGoogle } from 'react-icons/fc';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
@ -73,12 +74,14 @@ export type SignUpFormV2Props = {
|
|||||||
className?: string;
|
className?: string;
|
||||||
initialEmail?: string;
|
initialEmail?: string;
|
||||||
isGoogleSSOEnabled?: boolean;
|
isGoogleSSOEnabled?: boolean;
|
||||||
|
isOIDCSSOEnabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const SignUpFormV2 = ({
|
export const SignUpFormV2 = ({
|
||||||
className,
|
className,
|
||||||
initialEmail,
|
initialEmail,
|
||||||
isGoogleSSOEnabled,
|
isGoogleSSOEnabled,
|
||||||
|
isOIDCSSOEnabled,
|
||||||
}: SignUpFormV2Props) => {
|
}: SignUpFormV2Props) => {
|
||||||
const { toast } = useToast();
|
const { toast } = useToast();
|
||||||
const analytics = useAnalytics();
|
const analytics = useAnalytics();
|
||||||
@ -179,6 +182,19 @@ export const SignUpFormV2 = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onSignUpWithOIDCClick = async () => {
|
||||||
|
try {
|
||||||
|
await signIn('oidc', { callbackUrl: SIGN_UP_REDIRECT_PATH });
|
||||||
|
} catch (err) {
|
||||||
|
toast({
|
||||||
|
title: 'An unknown error occurred',
|
||||||
|
description:
|
||||||
|
'We encountered an unknown error while attempting to sign you Up. Please try again later.',
|
||||||
|
variant: 'destructive',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn('flex justify-center gap-x-12', className)}>
|
<div className={cn('flex justify-center gap-x-12', className)}>
|
||||||
<div className="border-border relative hidden flex-1 overflow-hidden rounded-xl border xl:flex">
|
<div className="border-border relative hidden flex-1 overflow-hidden rounded-xl border xl:flex">
|
||||||
@ -255,7 +271,7 @@ export const SignUpFormV2 = ({
|
|||||||
<fieldset
|
<fieldset
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex h-[550px] w-full flex-col gap-y-4',
|
'flex h-[550px] w-full flex-col gap-y-4',
|
||||||
isGoogleSSOEnabled && 'h-[650px]',
|
(isGoogleSSOEnabled || isOIDCSSOEnabled) && 'h-[650px]',
|
||||||
)}
|
)}
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
>
|
>
|
||||||
@ -323,14 +339,18 @@ export const SignUpFormV2 = ({
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{isGoogleSSOEnabled && (
|
{(isGoogleSSOEnabled || isOIDCSSOEnabled) && (
|
||||||
<>
|
<>
|
||||||
<div className="relative flex items-center justify-center gap-x-4 py-2 text-xs uppercase">
|
<div className="relative flex items-center justify-center gap-x-4 py-2 text-xs uppercase">
|
||||||
<div className="bg-border h-px flex-1" />
|
<div className="bg-border h-px flex-1" />
|
||||||
<span className="text-muted-foreground bg-transparent">Or</span>
|
<span className="text-muted-foreground bg-transparent">Or</span>
|
||||||
<div className="bg-border h-px flex-1" />
|
<div className="bg-border h-px flex-1" />
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isGoogleSSOEnabled && (
|
||||||
|
<>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
size="lg"
|
size="lg"
|
||||||
@ -345,6 +365,22 @@ export const SignUpFormV2 = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{isOIDCSSOEnabled && (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
size="lg"
|
||||||
|
variant={'outline'}
|
||||||
|
className="bg-background text-muted-foreground border"
|
||||||
|
disabled={isSubmitting}
|
||||||
|
onClick={onSignUpWithOIDCClick}
|
||||||
|
>
|
||||||
|
<FaIdCardClip className="mr-2 h-5 w-5" />
|
||||||
|
Sign Up with OIDC
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
<p className="text-muted-foreground mt-4 text-sm">
|
<p className="text-muted-foreground mt-4 text-sm">
|
||||||
Already have an account?{' '}
|
Already have an account?{' '}
|
||||||
<Link href="/signin" className="text-documenso-700 duration-200 hover:opacity-70">
|
<Link href="/signin" className="text-documenso-700 duration-200 hover:opacity-70">
|
||||||
|
|||||||
@ -5,12 +5,19 @@ export const SALT_ROUNDS = 12;
|
|||||||
export const IDENTITY_PROVIDER_NAME: { [key in IdentityProvider]: string } = {
|
export const IDENTITY_PROVIDER_NAME: { [key in IdentityProvider]: string } = {
|
||||||
[IdentityProvider.DOCUMENSO]: 'Documenso',
|
[IdentityProvider.DOCUMENSO]: 'Documenso',
|
||||||
[IdentityProvider.GOOGLE]: 'Google',
|
[IdentityProvider.GOOGLE]: 'Google',
|
||||||
|
[IdentityProvider.OIDC]: 'OIDC',
|
||||||
};
|
};
|
||||||
|
|
||||||
export const IS_GOOGLE_SSO_ENABLED = Boolean(
|
export const IS_GOOGLE_SSO_ENABLED = Boolean(
|
||||||
process.env.NEXT_PRIVATE_GOOGLE_CLIENT_ID && process.env.NEXT_PRIVATE_GOOGLE_CLIENT_SECRET,
|
process.env.NEXT_PRIVATE_GOOGLE_CLIENT_ID && process.env.NEXT_PRIVATE_GOOGLE_CLIENT_SECRET,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const IS_OIDC_SSO_ENABLED = Boolean(
|
||||||
|
process.env.NEXT_PRIVATE_OIDC_WELL_KNOWN &&
|
||||||
|
process.env.NEXT_PRIVATE_OIDC_CLIENT_ID &&
|
||||||
|
process.env.NEXT_PRIVATE_OIDC_CLIENT_SECRET,
|
||||||
|
);
|
||||||
|
|
||||||
export const USER_SECURITY_AUDIT_LOG_MAP: { [key in UserSecurityAuditLogType]: string } = {
|
export const USER_SECURITY_AUDIT_LOG_MAP: { [key in UserSecurityAuditLogType]: string } = {
|
||||||
[UserSecurityAuditLogType.ACCOUNT_SSO_LINK]: 'Linked account to SSO',
|
[UserSecurityAuditLogType.ACCOUNT_SSO_LINK]: 'Linked account to SSO',
|
||||||
[UserSecurityAuditLogType.ACCOUNT_PROFILE_UPDATE]: 'Profile updated',
|
[UserSecurityAuditLogType.ACCOUNT_PROFILE_UPDATE]: 'Profile updated',
|
||||||
|
|||||||
@ -136,6 +136,25 @@ export const NEXT_AUTH_OPTIONS: AuthOptions = {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
{
|
||||||
|
id: 'oidc',
|
||||||
|
name: 'OIDC',
|
||||||
|
wellKnown: process.env.NEXT_PRIVATE_OIDC_WELL_KNOWN,
|
||||||
|
clientId: process.env.NEXT_PRIVATE_OIDC_CLIENT_ID,
|
||||||
|
clientSecret: process.env.NEXT_PRIVATE_OIDC_CLIENT_SECRET,
|
||||||
|
authorization: { params: { scope: 'openid email profile' } },
|
||||||
|
idToken: true,
|
||||||
|
checks: ['pkce', 'state'],
|
||||||
|
type: 'oauth',
|
||||||
|
allowDangerousEmailAccountLinking: true,
|
||||||
|
profile(profile) {
|
||||||
|
return {
|
||||||
|
id: Number(profile.sub),
|
||||||
|
email: profile.email,
|
||||||
|
name: profile.name || `${profile.given_name} ${profile.family_name}`.trim(),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
CredentialsProvider({
|
CredentialsProvider({
|
||||||
id: 'webauthn',
|
id: 'webauthn',
|
||||||
name: 'Keypass',
|
name: 'Keypass',
|
||||||
|
|||||||
@ -0,0 +1 @@
|
|||||||
|
ALTER TYPE "IdentityProvider" ADD VALUE IF NOT EXISTS 'OIDC';
|
||||||
@ -11,6 +11,7 @@ datasource db {
|
|||||||
enum IdentityProvider {
|
enum IdentityProvider {
|
||||||
DOCUMENSO
|
DOCUMENSO
|
||||||
GOOGLE
|
GOOGLE
|
||||||
|
OIDC
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Role {
|
enum Role {
|
||||||
|
|||||||
4
packages/tsconfig/process-env.d.ts
vendored
4
packages/tsconfig/process-env.d.ts
vendored
@ -6,6 +6,10 @@ declare namespace NodeJS {
|
|||||||
NEXT_PRIVATE_GOOGLE_CLIENT_ID?: string;
|
NEXT_PRIVATE_GOOGLE_CLIENT_ID?: string;
|
||||||
NEXT_PRIVATE_GOOGLE_CLIENT_SECRET?: string;
|
NEXT_PRIVATE_GOOGLE_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
|
NEXT_PRIVATE_OIDC_WELL_KNOWN?: string;
|
||||||
|
NEXT_PRIVATE_OIDC_CLIENT_ID?: string;
|
||||||
|
NEXT_PRIVATE_OIDC_CLIENT_SECRET?: string;
|
||||||
|
|
||||||
NEXT_PRIVATE_DATABASE_URL: string;
|
NEXT_PRIVATE_DATABASE_URL: string;
|
||||||
NEXT_PRIVATE_ENCRYPTION_KEY: string;
|
NEXT_PRIVATE_ENCRYPTION_KEY: string;
|
||||||
NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY: string;
|
NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY: string;
|
||||||
|
|||||||
@ -70,6 +70,9 @@
|
|||||||
"NEXT_PRIVATE_SIGNING_GCLOUD_APPLICATION_CREDENTIALS_CONTENTS",
|
"NEXT_PRIVATE_SIGNING_GCLOUD_APPLICATION_CREDENTIALS_CONTENTS",
|
||||||
"NEXT_PRIVATE_GOOGLE_CLIENT_ID",
|
"NEXT_PRIVATE_GOOGLE_CLIENT_ID",
|
||||||
"NEXT_PRIVATE_GOOGLE_CLIENT_SECRET",
|
"NEXT_PRIVATE_GOOGLE_CLIENT_SECRET",
|
||||||
|
"NEXT_PRIVATE_OIDC_WELL_KNOWN",
|
||||||
|
"NEXT_PRIVATE_OIDC_CLIENT_ID",
|
||||||
|
"NEXT_PRIVATE_OIDC_CLIENT_SECRET",
|
||||||
"NEXT_PUBLIC_UPLOAD_TRANSPORT",
|
"NEXT_PUBLIC_UPLOAD_TRANSPORT",
|
||||||
"NEXT_PRIVATE_UPLOAD_ENDPOINT",
|
"NEXT_PRIVATE_UPLOAD_ENDPOINT",
|
||||||
"NEXT_PRIVATE_UPLOAD_FORCE_PATH_STYLE",
|
"NEXT_PRIVATE_UPLOAD_FORCE_PATH_STYLE",
|
||||||
|
|||||||
Reference in New Issue
Block a user