Skip to main content

Microsoft Provider

Package: @nauth-toolkit/social-microsoft Type: Social Auth Provider

npm install @nauth-toolkit/social-microsoft

Serves both populations the Microsoft identity platform covers: personal Microsoft accounts and work or school accounts from an Entra ID (Microsoft 365) directory. Which one is admitted depends on tenant.

Exports​

ExportTypeEntry
MicrosoftSocialAuthServiceClassDefault
MicrosoftOAuthClientClassDefault
MicrosoftOAuthConfigInterfaceDefault
TokenVerifierServiceClassDefault
VerifiedMicrosoftTokenProfileInterfaceDefault
VerifyMicrosoftTokenOptionsInterfaceDefault
MicrosoftSocialAuthModuleNestJS Module/nestjs

Tenant helpers (MSA_TENANT_ID, authorizeEndpoint, expectedIssuer, isPersonalAccountTenant, isTenantGuid, isValidTenant, jwksEndpoint, tokenEndpoint) are also exported from the default entry.

Configuration​

Configure Microsoft under config.social.microsoft (in @nauth-toolkit/core config).

KeyTypeRequiredDescription
allowedTenantsstring[]NoExtra directory ids permitted to sign in. Turns common/organizations into a closed allowlist. Ignored when tenant is a GUID.
allowSignupbooleanNoAllow creating new users on first login
autoLinkbooleanNoAuto-link to existing users by verified email
callbackUrlstringYes (if enabled)Backend callback URL (/auth/social/microsoft/callback)
clientIdstring | string[]Yes (if enabled)Application (client) ID from the app registration
clientSecretstringYes (if enabled)Client secret from the app registration
enabledbooleanNoEnable Microsoft OAuth
oauthParamsRecord<string, string>NoAdditional OAuth parameters appended to the authorization URL. Act as defaults, overridable per request.
requiredGroupsstring[]NoSecurity group object ids. User needs at least one. Checked on every sign-in.
requiredRolesstring[]NoApp roles from the roles claim. User needs at least one. Checked on every sign-in.
scopesstring[]NoDefault: ['openid', 'email', 'profile']
tenantstringNoDirectory selector. Default: 'common'.

Tenant values​

ValueWho can sign in
commonWork/school accounts from any directory, plus personal accounts
organizationsWork/school accounts from any directory
consumersPersonal Microsoft accounts only
A directory GUIDThat one organisation only
A verified domainThat one organisation only

An invalid value is rejected at startup by the config schema. The app registration's Supported account types must match the value chosen.

warning

common means everyone, not just consumers — it admits work accounts from directories you have never heard of. Pin a GUID when the application serves one organisation, or set allowedTenants.

Access gate​

requiredRoles and requiredGroups are evaluated on every authentication, not only at signup, so removing a user from a role or group takes effect at their next sign-in. A user who fails a check gets SOCIAL_ACCESS_DENIED (HTTP 403).

social: {
microsoft: {
enabled: true,
clientId: process.env.MS_CLIENT_ID,
clientSecret: process.env.MS_CLIENT_SECRET,
callbackUrl: 'https://api.myapp.com/auth/social/microsoft/callback',
tenant: '9f4c2a10-1b3c-4d5e-8f70-2a1b3c4d5e6f',
requiredRoles: ['nauth.access'],
},
}
tip

Entra's own Assignment required toggle (Enterprise Applications → your app → Properties) is simpler and stronger: Microsoft refuses unassigned users at the identity provider and they never reach your callback. Use requiredRoles when you need finer in-token granularity on top of it.

Prefer requiredRoles over requiredGroups. The groups claim carries object ids rather than names, and Entra omits it once a user belongs to more than roughly 200 groups, substituting a pointer to Graph. Sign-in is denied in that case rather than treated as "member of nothing" — configure the app registration to emit only groups assigned to the application, or use app roles.

Errors​

CodeWhenDetails
SOCIAL_ACCESS_DENIEDDirectory not permitted, or required role/group missingundefined
SOCIAL_CONFIG_MISSINGProvider disabled, or clientId/clientSecret/callbackUrl absentundefined
SOCIAL_EMAIL_REQUIREDToken carries no email and no email-shaped preferred_usernameundefined
SOCIAL_TOKEN_INVALIDSignature, audience or issuer check failed, or no ID token returnedundefined

Throws NAuthException with the codes listed above.

Usage​

import { MicrosoftSocialAuthModule } from '@nauth-toolkit/social-microsoft/nestjs';

@Module({
imports: [AuthModule.forRoot(config), MicrosoftSocialAuthModule],
})
export class AppModule {}

Profile Data​

The redirect flow reads the verified ID token rather than a userinfo endpoint, because the tenant and access-gate claims only exist there.

FieldTypeDescription
idstringThe oid claim — the user's immutable id within their directory
emailstringFrom the email claim, falling back to preferred_username when it is email-shaped
firstNamestring | nullgiven_name, or the first word of name
lastNamestring | nullfamily_name, or the remainder of name
verifiedbooleanWhether the email may be trusted for auto-linking — see below
warning

id is the oid claim, never sub or email. sub is pairwise per application and is not a durable identity across applications.

Email trust​

verified gates email-based auto-linking in the core social base class, where a true value both links to an existing account by email and promotes that account's verified flag. Microsoft emits no email_verified claim, so this provider derives it:

Account typeverified
Personal Microsoft accounttrue — Microsoft proves ownership before an address can become an account alias
Work/school with xms_edov: truetrue — the tenant is confirmed as owning the email domain
Work/school without xms_edovfalse — no auto-link

xms_edov is an optional claim that must be switched on in the app registration's token configuration. Without it a work account will not merge into an existing local account with the same email, because a tenant administrator can set a user's email to a domain they do not own.