mirror of
https://github.com/documenso/documenso.git
synced 2025-11-10 04:22:32 +10:00
feat: signin with microsoft (#1998)
This commit is contained in:
@ -13,6 +13,10 @@ NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY="DEADBEEF"
|
|||||||
# https://docs.documenso.com/developers/self-hosting/setting-up-oauth-providers#google-oauth-gmail
|
# https://docs.documenso.com/developers/self-hosting/setting-up-oauth-providers#google-oauth-gmail
|
||||||
NEXT_PRIVATE_GOOGLE_CLIENT_ID=""
|
NEXT_PRIVATE_GOOGLE_CLIENT_ID=""
|
||||||
NEXT_PRIVATE_GOOGLE_CLIENT_SECRET=""
|
NEXT_PRIVATE_GOOGLE_CLIENT_SECRET=""
|
||||||
|
# Find documentation on setting up Microsoft OAuth here:
|
||||||
|
# https://docs.documenso.com/developers/self-hosting/setting-up-oauth-providers#microsoft-oauth-azure-ad
|
||||||
|
NEXT_PRIVATE_MICROSOFT_CLIENT_ID=""
|
||||||
|
NEXT_PRIVATE_MICROSOFT_CLIENT_SECRET=""
|
||||||
|
|
||||||
NEXT_PRIVATE_OIDC_WELL_KNOWN=""
|
NEXT_PRIVATE_OIDC_WELL_KNOWN=""
|
||||||
NEXT_PRIVATE_OIDC_CLIENT_ID=""
|
NEXT_PRIVATE_OIDC_CLIENT_ID=""
|
||||||
|
|||||||
@ -27,3 +27,33 @@ NEXT_PRIVATE_GOOGLE_CLIENT_SECRET=<your-client-secret>
|
|||||||
```
|
```
|
||||||
|
|
||||||
Finally verify the signing in with Google works by signing in with your Google account and checking the email address in your profile.
|
Finally verify the signing in with Google works by signing in with your Google account and checking the email address in your profile.
|
||||||
|
|
||||||
|
## Microsoft OAuth (Azure AD)
|
||||||
|
|
||||||
|
To use Microsoft OAuth, you will need to create an Azure AD application registration in the Microsoft Azure portal. This will allow users to sign in with their Microsoft accounts.
|
||||||
|
|
||||||
|
### Create and configure a new Azure AD application
|
||||||
|
|
||||||
|
1. Go to the [Azure Portal](https://portal.azure.com/)
|
||||||
|
2. Navigate to **Azure Active Directory** (or **Microsoft Entra ID** in newer Azure portals)
|
||||||
|
3. In the left sidebar, click **App registrations**
|
||||||
|
4. Click **New registration**
|
||||||
|
5. Enter a name for your application (e.g., "Documenso")
|
||||||
|
6. Under **Supported account types**, select **Accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g. Skype, Xbox)** to allow any Microsoft account to sign in
|
||||||
|
7. Under **Redirect URI**, select **Web** and enter: `https://<documenso-domain>/api/auth/callback/microsoft`
|
||||||
|
8. Click **Register**
|
||||||
|
|
||||||
|
### Configure the application
|
||||||
|
|
||||||
|
1. After registration, you'll be taken to the app's overview page
|
||||||
|
2. Copy the **Application (client) ID** - this will be your `NEXT_PRIVATE_MICROSOFT_CLIENT_ID`
|
||||||
|
3. In the left sidebar, click **Certificates & secrets**
|
||||||
|
4. Under **Client secrets**, click **New client secret**
|
||||||
|
5. Add a description and select an expiration period
|
||||||
|
6. Click **Add** and copy the **Value** (not the Secret ID) - this will be your `NEXT_PRIVATE_MICROSOFT_CLIENT_SECRET`
|
||||||
|
7. In the Documenso environment variables, set the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
NEXT_PRIVATE_MICROSOFT_CLIENT_ID=<your-application-client-id>
|
||||||
|
NEXT_PRIVATE_MICROSOFT_CLIENT_SECRET=<your-client-secret-value>
|
||||||
|
```
|
||||||
|
|||||||
@ -70,6 +70,7 @@ export type SignInFormProps = {
|
|||||||
className?: string;
|
className?: string;
|
||||||
initialEmail?: string;
|
initialEmail?: string;
|
||||||
isGoogleSSOEnabled?: boolean;
|
isGoogleSSOEnabled?: boolean;
|
||||||
|
isMicrosoftSSOEnabled?: boolean;
|
||||||
isOIDCSSOEnabled?: boolean;
|
isOIDCSSOEnabled?: boolean;
|
||||||
oidcProviderLabel?: string;
|
oidcProviderLabel?: string;
|
||||||
returnTo?: string;
|
returnTo?: string;
|
||||||
@ -79,6 +80,7 @@ export const SignInForm = ({
|
|||||||
className,
|
className,
|
||||||
initialEmail,
|
initialEmail,
|
||||||
isGoogleSSOEnabled,
|
isGoogleSSOEnabled,
|
||||||
|
isMicrosoftSSOEnabled,
|
||||||
isOIDCSSOEnabled,
|
isOIDCSSOEnabled,
|
||||||
oidcProviderLabel,
|
oidcProviderLabel,
|
||||||
returnTo,
|
returnTo,
|
||||||
@ -95,6 +97,8 @@ export const SignInForm = ({
|
|||||||
'totp' | 'backup'
|
'totp' | 'backup'
|
||||||
>('totp');
|
>('totp');
|
||||||
|
|
||||||
|
const hasSocialAuthEnabled = isGoogleSSOEnabled || isMicrosoftSSOEnabled || isOIDCSSOEnabled;
|
||||||
|
|
||||||
const [isPasskeyLoading, setIsPasskeyLoading] = useState(false);
|
const [isPasskeyLoading, setIsPasskeyLoading] = useState(false);
|
||||||
|
|
||||||
const redirectPath = useMemo(() => {
|
const redirectPath = useMemo(() => {
|
||||||
@ -271,6 +275,22 @@ export const SignInForm = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onSignInWithMicrosoftClick = async () => {
|
||||||
|
try {
|
||||||
|
await authClient.microsoft.signIn({
|
||||||
|
redirectPath,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
toast({
|
||||||
|
title: _(msg`An unknown error occurred`),
|
||||||
|
description: _(
|
||||||
|
msg`We encountered an unknown error while attempting to sign you In. Please try again later.`,
|
||||||
|
),
|
||||||
|
variant: 'destructive',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const onSignInWithOIDCClick = async () => {
|
const onSignInWithOIDCClick = async () => {
|
||||||
try {
|
try {
|
||||||
await authClient.oidc.signIn({
|
await authClient.oidc.signIn({
|
||||||
@ -363,7 +383,7 @@ export const SignInForm = ({
|
|||||||
{isSubmitting ? <Trans>Signing in...</Trans> : <Trans>Sign In</Trans>}
|
{isSubmitting ? <Trans>Signing in...</Trans> : <Trans>Sign In</Trans>}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{(isGoogleSSOEnabled || isOIDCSSOEnabled) && (
|
{hasSocialAuthEnabled && (
|
||||||
<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">
|
<span className="text-muted-foreground bg-transparent">
|
||||||
@ -387,6 +407,20 @@ export const SignInForm = ({
|
|||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{isMicrosoftSSOEnabled && (
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
size="lg"
|
||||||
|
variant="outline"
|
||||||
|
className="bg-background text-muted-foreground border"
|
||||||
|
disabled={isSubmitting}
|
||||||
|
onClick={onSignInWithMicrosoftClick}
|
||||||
|
>
|
||||||
|
<img className="mr-2 h-4 w-4" alt="Microsoft Logo" src={'/static/microsoft.svg'} />
|
||||||
|
Microsoft
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
|
||||||
{isOIDCSSOEnabled && (
|
{isOIDCSSOEnabled && (
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@ -66,6 +66,7 @@ export type SignUpFormProps = {
|
|||||||
className?: string;
|
className?: string;
|
||||||
initialEmail?: string;
|
initialEmail?: string;
|
||||||
isGoogleSSOEnabled?: boolean;
|
isGoogleSSOEnabled?: boolean;
|
||||||
|
isMicrosoftSSOEnabled?: boolean;
|
||||||
isOIDCSSOEnabled?: boolean;
|
isOIDCSSOEnabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -73,6 +74,7 @@ export const SignUpForm = ({
|
|||||||
className,
|
className,
|
||||||
initialEmail,
|
initialEmail,
|
||||||
isGoogleSSOEnabled,
|
isGoogleSSOEnabled,
|
||||||
|
isMicrosoftSSOEnabled,
|
||||||
isOIDCSSOEnabled,
|
isOIDCSSOEnabled,
|
||||||
}: SignUpFormProps) => {
|
}: SignUpFormProps) => {
|
||||||
const { _ } = useLingui();
|
const { _ } = useLingui();
|
||||||
@ -84,6 +86,8 @@ export const SignUpForm = ({
|
|||||||
|
|
||||||
const utmSrc = searchParams.get('utm_source') ?? null;
|
const utmSrc = searchParams.get('utm_source') ?? null;
|
||||||
|
|
||||||
|
const hasSocialAuthEnabled = isGoogleSSOEnabled || isMicrosoftSSOEnabled || isOIDCSSOEnabled;
|
||||||
|
|
||||||
const form = useForm<TSignUpFormSchema>({
|
const form = useForm<TSignUpFormSchema>({
|
||||||
values: {
|
values: {
|
||||||
name: '',
|
name: '',
|
||||||
@ -148,6 +152,20 @@ export const SignUpForm = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const onSignUpWithMicrosoftClick = async () => {
|
||||||
|
try {
|
||||||
|
await authClient.microsoft.signIn();
|
||||||
|
} catch (err) {
|
||||||
|
toast({
|
||||||
|
title: _(msg`An unknown error occurred`),
|
||||||
|
description: _(
|
||||||
|
msg`We encountered an unknown error while attempting to sign you Up. Please try again later.`,
|
||||||
|
),
|
||||||
|
variant: 'destructive',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const onSignUpWithOIDCClick = async () => {
|
const onSignUpWithOIDCClick = async () => {
|
||||||
try {
|
try {
|
||||||
await authClient.oidc.signIn();
|
await authClient.oidc.signIn();
|
||||||
@ -227,7 +245,7 @@ export const SignUpForm = ({
|
|||||||
<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 || isOIDCSSOEnabled) && 'h-[650px]',
|
hasSocialAuthEnabled && 'h-[650px]',
|
||||||
)}
|
)}
|
||||||
disabled={isSubmitting}
|
disabled={isSubmitting}
|
||||||
>
|
>
|
||||||
@ -302,7 +320,7 @@ export const SignUpForm = ({
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{(isGoogleSSOEnabled || isOIDCSSOEnabled) && (
|
{hasSocialAuthEnabled && (
|
||||||
<>
|
<>
|
||||||
<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" />
|
||||||
@ -330,6 +348,26 @@ export const SignUpForm = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{isMicrosoftSSOEnabled && (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
size="lg"
|
||||||
|
variant={'outline'}
|
||||||
|
className="bg-background text-muted-foreground border"
|
||||||
|
disabled={isSubmitting}
|
||||||
|
onClick={onSignUpWithMicrosoftClick}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
className="mr-2 h-4 w-4"
|
||||||
|
alt="Microsoft Logo"
|
||||||
|
src={'/static/microsoft.svg'}
|
||||||
|
/>
|
||||||
|
<Trans>Sign Up with Microsoft</Trans>
|
||||||
|
</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{isOIDCSSOEnabled && (
|
{isOIDCSSOEnabled && (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import { Link, redirect } from 'react-router';
|
|||||||
import { getOptionalSession } from '@documenso/auth/server/lib/utils/get-session';
|
import { getOptionalSession } from '@documenso/auth/server/lib/utils/get-session';
|
||||||
import {
|
import {
|
||||||
IS_GOOGLE_SSO_ENABLED,
|
IS_GOOGLE_SSO_ENABLED,
|
||||||
|
IS_MICROSOFT_SSO_ENABLED,
|
||||||
IS_OIDC_SSO_ENABLED,
|
IS_OIDC_SSO_ENABLED,
|
||||||
OIDC_PROVIDER_LABEL,
|
OIDC_PROVIDER_LABEL,
|
||||||
} from '@documenso/lib/constants/auth';
|
} from '@documenso/lib/constants/auth';
|
||||||
@ -23,6 +24,7 @@ export async function loader({ request }: Route.LoaderArgs) {
|
|||||||
|
|
||||||
// SSR env variables.
|
// SSR env variables.
|
||||||
const isGoogleSSOEnabled = IS_GOOGLE_SSO_ENABLED;
|
const isGoogleSSOEnabled = IS_GOOGLE_SSO_ENABLED;
|
||||||
|
const isMicrosoftSSOEnabled = IS_MICROSOFT_SSO_ENABLED;
|
||||||
const isOIDCSSOEnabled = IS_OIDC_SSO_ENABLED;
|
const isOIDCSSOEnabled = IS_OIDC_SSO_ENABLED;
|
||||||
const oidcProviderLabel = OIDC_PROVIDER_LABEL;
|
const oidcProviderLabel = OIDC_PROVIDER_LABEL;
|
||||||
|
|
||||||
@ -32,13 +34,15 @@ export async function loader({ request }: Route.LoaderArgs) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
isGoogleSSOEnabled,
|
isGoogleSSOEnabled,
|
||||||
|
isMicrosoftSSOEnabled,
|
||||||
isOIDCSSOEnabled,
|
isOIDCSSOEnabled,
|
||||||
oidcProviderLabel,
|
oidcProviderLabel,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SignIn({ loaderData }: Route.ComponentProps) {
|
export default function SignIn({ loaderData }: Route.ComponentProps) {
|
||||||
const { isGoogleSSOEnabled, isOIDCSSOEnabled, oidcProviderLabel } = loaderData;
|
const { isGoogleSSOEnabled, isMicrosoftSSOEnabled, isOIDCSSOEnabled, oidcProviderLabel } =
|
||||||
|
loaderData;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-screen max-w-lg px-4">
|
<div className="w-screen max-w-lg px-4">
|
||||||
@ -54,6 +58,7 @@ export default function SignIn({ loaderData }: Route.ComponentProps) {
|
|||||||
|
|
||||||
<SignInForm
|
<SignInForm
|
||||||
isGoogleSSOEnabled={isGoogleSSOEnabled}
|
isGoogleSSOEnabled={isGoogleSSOEnabled}
|
||||||
|
isMicrosoftSSOEnabled={isMicrosoftSSOEnabled}
|
||||||
isOIDCSSOEnabled={isOIDCSSOEnabled}
|
isOIDCSSOEnabled={isOIDCSSOEnabled}
|
||||||
oidcProviderLabel={oidcProviderLabel}
|
oidcProviderLabel={oidcProviderLabel}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
import { redirect } from 'react-router';
|
import { redirect } from 'react-router';
|
||||||
|
|
||||||
import { IS_GOOGLE_SSO_ENABLED, IS_OIDC_SSO_ENABLED } from '@documenso/lib/constants/auth';
|
import {
|
||||||
|
IS_GOOGLE_SSO_ENABLED,
|
||||||
|
IS_MICROSOFT_SSO_ENABLED,
|
||||||
|
IS_OIDC_SSO_ENABLED,
|
||||||
|
} from '@documenso/lib/constants/auth';
|
||||||
import { env } from '@documenso/lib/utils/env';
|
import { env } from '@documenso/lib/utils/env';
|
||||||
|
|
||||||
import { SignUpForm } from '~/components/forms/signup';
|
import { SignUpForm } from '~/components/forms/signup';
|
||||||
@ -17,6 +21,7 @@ export function loader() {
|
|||||||
|
|
||||||
// SSR env variables.
|
// SSR env variables.
|
||||||
const isGoogleSSOEnabled = IS_GOOGLE_SSO_ENABLED;
|
const isGoogleSSOEnabled = IS_GOOGLE_SSO_ENABLED;
|
||||||
|
const isMicrosoftSSOEnabled = IS_MICROSOFT_SSO_ENABLED;
|
||||||
const isOIDCSSOEnabled = IS_OIDC_SSO_ENABLED;
|
const isOIDCSSOEnabled = IS_OIDC_SSO_ENABLED;
|
||||||
|
|
||||||
if (NEXT_PUBLIC_DISABLE_SIGNUP === 'true') {
|
if (NEXT_PUBLIC_DISABLE_SIGNUP === 'true') {
|
||||||
@ -25,17 +30,19 @@ export function loader() {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
isGoogleSSOEnabled,
|
isGoogleSSOEnabled,
|
||||||
|
isMicrosoftSSOEnabled,
|
||||||
isOIDCSSOEnabled,
|
isOIDCSSOEnabled,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function SignUp({ loaderData }: Route.ComponentProps) {
|
export default function SignUp({ loaderData }: Route.ComponentProps) {
|
||||||
const { isGoogleSSOEnabled, isOIDCSSOEnabled } = loaderData;
|
const { isGoogleSSOEnabled, isMicrosoftSSOEnabled, isOIDCSSOEnabled } = loaderData;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SignUpForm
|
<SignUpForm
|
||||||
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"
|
||||||
isGoogleSSOEnabled={isGoogleSSOEnabled}
|
isGoogleSSOEnabled={isGoogleSSOEnabled}
|
||||||
|
isMicrosoftSSOEnabled={isMicrosoftSSOEnabled}
|
||||||
isOIDCSSOEnabled={isOIDCSSOEnabled}
|
isOIDCSSOEnabled={isOIDCSSOEnabled}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|||||||
1
apps/remix/public/static/microsoft.svg
Normal file
1
apps/remix/public/static/microsoft.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg" width="256" height="256" preserveAspectRatio="xMidYMid"><path fill="#F1511B" d="M121.666 121.666H0V0h121.666z"/><path fill="#80CC28" d="M256 121.666H134.335V0H256z"/><path fill="#00ADEF" d="M121.663 256.002H0V134.336h121.663z"/><path fill="#FBBC09" d="M256 256.002H134.335V134.336H256z"/></svg>
|
||||||
|
After Width: | Height: | Size: 356 B |
@ -222,6 +222,22 @@ export class AuthClient {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public microsoft = {
|
||||||
|
signIn: async ({ redirectPath }: { redirectPath?: string } = {}) => {
|
||||||
|
const response = await this.client['oauth'].authorize.microsoft.$post({
|
||||||
|
json: { redirectPath },
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.handleError(response);
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
|
||||||
|
if (data.redirectUrl) {
|
||||||
|
window.location.href = data.redirectUrl;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
public oidc = {
|
public oidc = {
|
||||||
signIn: async ({ redirectPath }: { redirectPath?: string } = {}) => {
|
signIn: async ({ redirectPath }: { redirectPath?: string } = {}) => {
|
||||||
const response = await this.client['oauth'].authorize.oidc.$post({ json: { redirectPath } });
|
const response = await this.client['oauth'].authorize.oidc.$post({ json: { redirectPath } });
|
||||||
|
|||||||
@ -26,6 +26,16 @@ export const GoogleAuthOptions: OAuthClientOptions = {
|
|||||||
bypassEmailVerification: false,
|
bypassEmailVerification: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const MicrosoftAuthOptions: OAuthClientOptions = {
|
||||||
|
id: 'microsoft',
|
||||||
|
scope: ['openid', 'email', 'profile'],
|
||||||
|
clientId: env('NEXT_PRIVATE_MICROSOFT_CLIENT_ID') ?? '',
|
||||||
|
clientSecret: env('NEXT_PRIVATE_MICROSOFT_CLIENT_SECRET') ?? '',
|
||||||
|
redirectUrl: `${NEXT_PUBLIC_WEBAPP_URL()}/api/auth/callback/microsoft`,
|
||||||
|
wellKnownUrl: 'https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration',
|
||||||
|
bypassEmailVerification: false,
|
||||||
|
};
|
||||||
|
|
||||||
export const OidcAuthOptions: OAuthClientOptions = {
|
export const OidcAuthOptions: OAuthClientOptions = {
|
||||||
id: 'oidc',
|
id: 'oidc',
|
||||||
scope: ['openid', 'email', 'profile'],
|
scope: ['openid', 'email', 'profile'],
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { Hono } from 'hono';
|
|||||||
|
|
||||||
import { AppError } from '@documenso/lib/errors/app-error';
|
import { AppError } from '@documenso/lib/errors/app-error';
|
||||||
|
|
||||||
import { GoogleAuthOptions, OidcAuthOptions } from '../config';
|
import { GoogleAuthOptions, MicrosoftAuthOptions, OidcAuthOptions } from '../config';
|
||||||
import { handleOAuthCallbackUrl } from '../lib/utils/handle-oauth-callback-url';
|
import { handleOAuthCallbackUrl } from '../lib/utils/handle-oauth-callback-url';
|
||||||
import { handleOAuthOrganisationCallbackUrl } from '../lib/utils/handle-oauth-organisation-callback-url';
|
import { handleOAuthOrganisationCallbackUrl } from '../lib/utils/handle-oauth-organisation-callback-url';
|
||||||
import type { HonoAuthContext } from '../types/context';
|
import type { HonoAuthContext } from '../types/context';
|
||||||
@ -45,4 +45,11 @@ export const callbackRoute = new Hono<HonoAuthContext>()
|
|||||||
/**
|
/**
|
||||||
* Google callback verification.
|
* Google callback verification.
|
||||||
*/
|
*/
|
||||||
.get('/google', async (c) => handleOAuthCallbackUrl({ c, clientOptions: GoogleAuthOptions }));
|
.get('/google', async (c) => handleOAuthCallbackUrl({ c, clientOptions: GoogleAuthOptions }))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Microsoft callback verification.
|
||||||
|
*/
|
||||||
|
.get('/microsoft', async (c) =>
|
||||||
|
handleOAuthCallbackUrl({ c, clientOptions: MicrosoftAuthOptions }),
|
||||||
|
);
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { sValidator } from '@hono/standard-validator';
|
|||||||
import { Hono } from 'hono';
|
import { Hono } from 'hono';
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { GoogleAuthOptions, OidcAuthOptions } from '../config';
|
import { GoogleAuthOptions, MicrosoftAuthOptions, OidcAuthOptions } from '../config';
|
||||||
import { handleOAuthAuthorizeUrl } from '../lib/utils/handle-oauth-authorize-url';
|
import { handleOAuthAuthorizeUrl } from '../lib/utils/handle-oauth-authorize-url';
|
||||||
import { getOrganisationAuthenticationPortalOptions } from '../lib/utils/organisation-portal';
|
import { getOrganisationAuthenticationPortalOptions } from '../lib/utils/organisation-portal';
|
||||||
import type { HonoAuthContext } from '../types/context';
|
import type { HonoAuthContext } from '../types/context';
|
||||||
@ -24,6 +24,20 @@ export const oauthRoute = new Hono<HonoAuthContext>()
|
|||||||
redirectPath,
|
redirectPath,
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Microsoft authorize endpoint.
|
||||||
|
*/
|
||||||
|
.post('/authorize/microsoft', sValidator('json', ZOAuthAuthorizeSchema), async (c) => {
|
||||||
|
const { redirectPath } = c.req.valid('json');
|
||||||
|
|
||||||
|
return handleOAuthAuthorizeUrl({
|
||||||
|
c,
|
||||||
|
clientOptions: MicrosoftAuthOptions,
|
||||||
|
redirectPath,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OIDC authorize endpoint.
|
* OIDC authorize endpoint.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -6,6 +6,7 @@ export const SALT_ROUNDS = 12;
|
|||||||
export const IDENTITY_PROVIDER_NAME: Record<string, string> = {
|
export const IDENTITY_PROVIDER_NAME: Record<string, string> = {
|
||||||
DOCUMENSO: 'Documenso',
|
DOCUMENSO: 'Documenso',
|
||||||
GOOGLE: 'Google',
|
GOOGLE: 'Google',
|
||||||
|
MICROSOFT: 'Microsoft',
|
||||||
OIDC: 'OIDC',
|
OIDC: 'OIDC',
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -13,6 +14,10 @@ export const IS_GOOGLE_SSO_ENABLED = Boolean(
|
|||||||
env('NEXT_PRIVATE_GOOGLE_CLIENT_ID') && env('NEXT_PRIVATE_GOOGLE_CLIENT_SECRET'),
|
env('NEXT_PRIVATE_GOOGLE_CLIENT_ID') && env('NEXT_PRIVATE_GOOGLE_CLIENT_SECRET'),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const IS_MICROSOFT_SSO_ENABLED = Boolean(
|
||||||
|
env('NEXT_PRIVATE_MICROSOFT_CLIENT_ID') && env('NEXT_PRIVATE_MICROSOFT_CLIENT_SECRET'),
|
||||||
|
);
|
||||||
|
|
||||||
export const IS_OIDC_SSO_ENABLED = Boolean(
|
export const IS_OIDC_SSO_ENABLED = Boolean(
|
||||||
env('NEXT_PRIVATE_OIDC_WELL_KNOWN') &&
|
env('NEXT_PRIVATE_OIDC_WELL_KNOWN') &&
|
||||||
env('NEXT_PRIVATE_OIDC_CLIENT_ID') &&
|
env('NEXT_PRIVATE_OIDC_CLIENT_ID') &&
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import type { HTMLAttributes } from 'react';
|
import type { HTMLAttributes } from 'react';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
import { Trans } from '@lingui/react/macro';
|
||||||
import { KeyboardIcon, UploadCloudIcon } from 'lucide-react';
|
import { KeyboardIcon, UploadCloudIcon } from 'lucide-react';
|
||||||
import { match } from 'ts-pattern';
|
import { match } from 'ts-pattern';
|
||||||
import { Trans } from '@lingui/react/macro';
|
|
||||||
|
|
||||||
import { DocumentSignatureType } from '@documenso/lib/constants/document';
|
import { DocumentSignatureType } from '@documenso/lib/constants/document';
|
||||||
import { isBase64Image } from '@documenso/lib/constants/signatures';
|
import { isBase64Image } from '@documenso/lib/constants/signatures';
|
||||||
|
|||||||
Reference in New Issue
Block a user