diff --git a/.env.example b/.env.example index 7b8872b69..6190dfb03 100644 --- a/.env.example +++ b/.env.example @@ -13,6 +13,10 @@ NEXT_PRIVATE_ENCRYPTION_SECONDARY_KEY="DEADBEEF" # https://docs.documenso.com/developers/self-hosting/setting-up-oauth-providers#google-oauth-gmail NEXT_PRIVATE_GOOGLE_CLIENT_ID="" 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_CLIENT_ID="" diff --git a/apps/documentation/pages/developers/self-hosting/setting-up-oauth-providers.mdx b/apps/documentation/pages/developers/self-hosting/setting-up-oauth-providers.mdx index 0ba359142..efebb4092 100644 --- a/apps/documentation/pages/developers/self-hosting/setting-up-oauth-providers.mdx +++ b/apps/documentation/pages/developers/self-hosting/setting-up-oauth-providers.mdx @@ -27,3 +27,33 @@ NEXT_PRIVATE_GOOGLE_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. + +## 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:///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= +NEXT_PRIVATE_MICROSOFT_CLIENT_SECRET= +``` diff --git a/apps/remix/app/components/forms/signin.tsx b/apps/remix/app/components/forms/signin.tsx index a9b7000ea..3ce7a935b 100644 --- a/apps/remix/app/components/forms/signin.tsx +++ b/apps/remix/app/components/forms/signin.tsx @@ -70,6 +70,7 @@ export type SignInFormProps = { className?: string; initialEmail?: string; isGoogleSSOEnabled?: boolean; + isMicrosoftSSOEnabled?: boolean; isOIDCSSOEnabled?: boolean; oidcProviderLabel?: string; returnTo?: string; @@ -79,6 +80,7 @@ export const SignInForm = ({ className, initialEmail, isGoogleSSOEnabled, + isMicrosoftSSOEnabled, isOIDCSSOEnabled, oidcProviderLabel, returnTo, @@ -95,6 +97,8 @@ export const SignInForm = ({ 'totp' | 'backup' >('totp'); + const hasSocialAuthEnabled = isGoogleSSOEnabled || isMicrosoftSSOEnabled || isOIDCSSOEnabled; + const [isPasskeyLoading, setIsPasskeyLoading] = useState(false); 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 () => { try { await authClient.oidc.signIn({ @@ -363,7 +383,7 @@ export const SignInForm = ({ {isSubmitting ? Signing in... : Sign In} - {(isGoogleSSOEnabled || isOIDCSSOEnabled) && ( + {hasSocialAuthEnabled && (
@@ -387,6 +407,20 @@ export const SignInForm = ({ )} + {isMicrosoftSSOEnabled && ( + + )} + {isOIDCSSOEnabled && ( + + )} + {isOIDCSSOEnabled && ( <>