{"id":16675,"library":"remix-auth-microsoft","title":"Remix Auth Microsoft Strategy","description":"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.","status":"active","version":"3.0.1","language":"javascript","source_language":"en","source_url":"https://github.com/juhanakristian/remix-auth-microsoft","tags":["javascript","remix","remix-auth","auth","authentication","strategy","typescript"],"install":[{"cmd":"npm install remix-auth-microsoft","lang":"bash","label":"npm"},{"cmd":"yarn add remix-auth-microsoft","lang":"bash","label":"yarn"},{"cmd":"pnpm add remix-auth-microsoft","lang":"bash","label":"pnpm"}],"dependencies":[{"reason":"Core authentication framework for Remix applications.","package":"remix-auth","optional":false},{"reason":"Base OAuth2 strategy extended by remix-auth-microsoft.","package":"remix-auth-oauth2","optional":false}],"imports":[{"note":"remix-auth-microsoft is an ESM-first package. Use named imports.","wrong":"const MicrosoftStrategy = require('remix-auth-microsoft');","symbol":"MicrosoftStrategy","correct":"import { MicrosoftStrategy } from 'remix-auth-microsoft';"},{"note":"Authenticator is imported from the peer dependency remix-auth.","wrong":"const Authenticator = require('remix-auth');","symbol":"Authenticator","correct":"import { Authenticator } from 'remix-auth';"},{"note":"This is a static method on the strategy class used to fetch user details from Microsoft Graph after obtaining an access token.","symbol":"MicrosoftStrategy.userProfile","correct":"let profile = await MicrosoftStrategy.userProfile(accessToken);"}],"quickstart":{"code":"// app/services/auth.server.ts\nimport { MicrosoftStrategy } from \"remix-auth-microsoft\";\nimport { Authenticator } from \"remix-auth\";\n\ninterface User {\n  id: string;\n  // ... other user properties\n}\n\nexport let authenticator = new Authenticator<User>(/* SessionStorage */);\n\nlet microsoftStrategy = new MicrosoftStrategy(\n  {\n    clientId: process.env.MICROSOFT_CLIENT_ID ?? '',\n    clientSecret: process.env.MICROSOFT_CLIENT_SECRET ?? '',\n    redirectURI: process.env.MICROSOFT_REDIRECT_URI ?? 'http://localhost:3000/auth/microsoft/callback',\n    tenantId: process.env.MICROSOFT_TENANT_ID, // optional for multi-tenant apps\n    scopes: ['openid', 'profile', 'email', 'offline_access'], // recommended scopes\n    prompt: 'select_account' // 'login', 'consent', 'none', 'select_account'\n  },\n  async ({ request, tokens, profile }) => {\n    // Here you can fetch the user from your database or create a new user\n    // based on the profile data from Microsoft.\n    // `tokens` contains accessToken, refreshToken, idToken, etc.\n    // `profile` contains basic user info parsed from the ID token or user info endpoint.\n\n    // Example: Using a placeholder User.findOrCreate\n    // It's crucial to use a reliable identifier like 'sub' from the ID token\n    // or 'id' from the user profile, not email, to prevent spoofing.\n\n    const userProfileId = profile.id; // or profile.sub from the ID token\n    if (!userProfileId) {\n      throw new Error(\"Could not get user ID from Microsoft profile.\");\n    }\n\n    // Replace with your actual user management logic\n    const user = { id: userProfileId, email: profile.emails?.[0]?.value || 'unknown@example.com' };\n    console.log(`Authenticated user: ${user.id} (${user.email})`);\n\n    // The returned object is stored in the session by the authenticator\n    return user;\n  }\n);\n\nauthenticator.use(microsoftStrategy, \"microsoft\");\n\n// Example of a route to initiate authentication\n// app/routes/auth.microsoft.tsx\n// import type { ActionFunctionArgs } from \"@remix-run/node\";\n// import { redirect } from \"@remix-run/node\";\n// import { authenticator } from \"~/services/auth.server\";\n\n// export async function action({ request }: ActionFunctionArgs) {\n//   return authenticator.authenticate(\"microsoft\", request, {\n//     successRedirect: \"/dashboard\",\n//     failureRedirect: \"/login\",\n//   });\n// }","lang":"typescript","description":"Demonstrates how to set up the MicrosoftStrategy with Remix Auth, including environment variable usage for credentials, recommended scopes, and a basic user resolution logic. It also includes an example of an authenticator instance and how to use it with the strategy."},"warnings":[{"fix":"Update `remix-auth` and `remix-auth-oauth2` to their latest major versions. If your MicrosoftStrategy configuration previously relied on a default `prompt` behavior, you must now explicitly set `prompt: 'select_account'` (or 'login', 'consent', etc.) in the strategy options.","message":"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.","severity":"breaking","affected_versions":">=3.0.0"},{"fix":"Review your strategy configuration against the v2.0.0 documentation or examples to ensure all variable names are updated, e.g., to align with 'clientId', 'clientSecret', 'redirectURI', 'tenantId'.","message":"Version 2.0.0 introduced variable renames to better align with Microsoft documentation, which may require updates to existing strategy configuration objects.","severity":"breaking","affected_versions":">=2.0.0 <3.0.0"},{"fix":"Always use a robust, immutable identifier like the 'id' from the user profile (which maps to the 'sub' claim in the ID token) or the 'oid' claim for organizational IDs, to identify and retrieve users from your database.","message":"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.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Minimize the data stored directly in the session. Consider storing only a user ID in the session and fetching full user details from a database on each request. If storing tokens, only store what's absolutely necessary (e.g., refresh token for renewal) and keep other data external.","message":"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.","severity":"gotcha","affected_versions":">=1.0.0"},{"fix":"Ensure `tenantId: 'YOUR_DIRECTORY_TENANT_ID'` is set in your `MicrosoftStrategy` options when you intend to limit access to a single organization. Without it, the application might default to multi-tenant behavior if configured as such in Azure AD.","message":"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.","severity":"gotcha","affected_versions":">=1.0.0"}],"env_vars":null,"last_verified":"2026-04-22T00:00:00.000Z","next_check":"2026-07-21T00:00:00.000Z","problems":[{"fix":"Ensure 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.","cause":"The application lacks the necessary permissions, or an administrator has not granted consent for the requested scopes, especially common for delegated permissions.","error":"AADSTS65001: The user or administrator has not consented to use the application"},{"fix":"Verify 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.","cause":"The `redirectURI` configured in your `MicrosoftStrategy` instance does not exactly match one of the 'Redirect URIs' specified in your Azure App Registration.","error":"AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application."},{"fix":"Go 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.","cause":"The `clientSecret` configured in your `MicrosoftStrategy` is incorrect, expired, or doesn't match the secret generated in your Azure App Registration.","error":"AADSTS7000215: Invalid client secret provided."},{"fix":"Ensure `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.","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.","error":"Error: Authenticator already has a strategy with the name 'microsoft'"}],"ecosystem":"npm"}