Remix Auth Microsoft Strategy
remix-auth-microsoft is a dedicated strategy for remix-auth that enables authentication against Microsoft Active Directory (work/school accounts) and personal Microsoft accounts (Skype, Xbox, Outlook.com). It extends remix-auth-oauth2 and simplifies the integration of Microsoft's OAuth 2.0 flow into Remix applications. The current stable version is 3.0.1, with major version releases often correlating with updates to its underlying remix-auth and remix-auth-oauth2 dependencies, alongside patch releases for bug fixes. Key differentiators include its tight integration with the Remix ecosystem via remix-auth, support for both Node.js and Cloudflare runtimes, and explicit guidance for multi-tenant and single-tenant configurations. It handles the intricacies of Microsoft's authentication endpoints, abstracting much of the OAuth 2.0 implementation details for developers, making it easier to implement secure Microsoft authentication flows in Remix applications.
Common errors
-
AADSTS65001: The user or administrator has not consented to use the application
cause The application lacks the necessary permissions, or an administrator has not granted consent for the requested scopes, especially common for delegated permissions.fixEnsure all required API permissions are configured in your Azure App Registration (API permissions blade). For organizational accounts, an administrator might need to grant tenant-wide consent. For personal accounts, the user needs to consent during the login flow. -
AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application.
cause The `redirectURI` configured in your `MicrosoftStrategy` instance does not exactly match one of the 'Redirect URIs' specified in your Azure App Registration.fixVerify that the `redirectURI` in your `MicrosoftStrategy` options (e.g., `http://localhost:3000/auth/microsoft/callback`) is identical to an entry in the 'Authentication' blade -> 'Redirect URIs' section of your Azure App Registration. Include scheme (http/https) and path. -
AADSTS7000215: Invalid client secret provided.
cause The `clientSecret` configured in your `MicrosoftStrategy` is incorrect, expired, or doesn't match the secret generated in your Azure App Registration.fixGo to your Azure App Registration -> 'Certificates & secrets' blade. Ensure you have an active client secret, copy its 'Value' (not 'Secret ID'), and update the `clientSecret` in your `MicrosoftStrategy` configuration. -
Error: Authenticator already has a strategy with the name 'microsoft'
cause You are attempting to register the MicrosoftStrategy with the same name ('microsoft' by default) more than once with the same Authenticator instance, or another strategy is using the 'microsoft' name.fixEnsure `authenticator.use()` for `MicrosoftStrategy` is called only once. If you need multiple Microsoft strategies, provide a unique second argument to `authenticator.use(strategy, 'unique-name')` for each instance.
Warnings
- breaking Version 3.0.0 upgraded remix-auth to v4 and remix-auth-oauth2 to v3. This also removed the default value for the `prompt` parameter in the strategy configuration, requiring explicit definition if desired.
- breaking Version 2.0.0 introduced variable renames to better align with Microsoft documentation, which may require updates to existing strategy configuration objects.
- gotcha Do not use the email address provided by Microsoft Entra ID (Azure AD) as the sole identifier for users, especially in multi-tenant applications. The email address is not validated and can be changed by users in the Azure Portal, creating a spoofing risk.
- gotcha When using cookie-based session storage with Remix Auth, be aware of the 4KB size limit for cookies. Storing large user objects or extensive token data directly in the session can exceed this limit.
- gotcha For single-tenant applications, it is crucial to explicitly set the `tenantId` attribute in the MicrosoftStrategy configuration to the 'Directory (tenant) ID' from your App Registration. This restricts logins to users within that specific organization, enhancing security.
Install
-
npm install remix-auth-microsoft -
yarn add remix-auth-microsoft -
pnpm add remix-auth-microsoft
Imports
- MicrosoftStrategy
const MicrosoftStrategy = require('remix-auth-microsoft');import { MicrosoftStrategy } from 'remix-auth-microsoft'; - Authenticator
const Authenticator = require('remix-auth');import { Authenticator } from 'remix-auth'; - MicrosoftStrategy.userProfile
let profile = await MicrosoftStrategy.userProfile(accessToken);
Quickstart
// app/services/auth.server.ts
import { MicrosoftStrategy } from "remix-auth-microsoft";
import { Authenticator } from "remix-auth";
interface User {
id: string;
// ... other user properties
}
export let authenticator = new Authenticator<User>(/* SessionStorage */);
let microsoftStrategy = new MicrosoftStrategy(
{
clientId: process.env.MICROSOFT_CLIENT_ID ?? '',
clientSecret: process.env.MICROSOFT_CLIENT_SECRET ?? '',
redirectURI: process.env.MICROSOFT_REDIRECT_URI ?? 'http://localhost:3000/auth/microsoft/callback',
tenantId: process.env.MICROSOFT_TENANT_ID, // optional for multi-tenant apps
scopes: ['openid', 'profile', 'email', 'offline_access'], // recommended scopes
prompt: 'select_account' // 'login', 'consent', 'none', 'select_account'
},
async ({ request, tokens, profile }) => {
// Here you can fetch the user from your database or create a new user
// based on the profile data from Microsoft.
// `tokens` contains accessToken, refreshToken, idToken, etc.
// `profile` contains basic user info parsed from the ID token or user info endpoint.
// Example: Using a placeholder User.findOrCreate
// It's crucial to use a reliable identifier like 'sub' from the ID token
// or 'id' from the user profile, not email, to prevent spoofing.
const userProfileId = profile.id; // or profile.sub from the ID token
if (!userProfileId) {
throw new Error("Could not get user ID from Microsoft profile.");
}
// Replace with your actual user management logic
const user = { id: userProfileId, email: profile.emails?.[0]?.value || 'unknown@example.com' };
console.log(`Authenticated user: ${user.id} (${user.email})`);
// The returned object is stored in the session by the authenticator
return user;
}
);
authenticator.use(microsoftStrategy, "microsoft");
// Example of a route to initiate authentication
// app/routes/auth.microsoft.tsx
// import type { ActionFunctionArgs } from "@remix-run/node";
// import { redirect } from "@remix-run/node";
// import { authenticator } from "~/services/auth.server";
// export async function action({ request }: ActionFunctionArgs) {
// return authenticator.authenticate("microsoft", request, {
// successRedirect: "/dashboard",
// failureRedirect: "/login",
// });
// }