Skip to content

Microsoft Entra ID

Microsoft Entra ID (Azure AD), registry key microsoft. OIDC with PKCE (S256) and id-token verification, including hand-rolled multi-tenant issuer validation.

Configure

python
from better_auth import BetterAuth
from better_auth.oauth.providers_ext import MicrosoftEntraId

auth = BetterAuth(
    secret=...,
    social_providers={
        "microsoft": MicrosoftEntraId(
            client_id="", client_secret="", tenant_id="common"
        ),
    },
)

Or name-keyed (no import):

python
auth = BetterAuth(
    secret=...,
    social_providers={
        "microsoft": {"client_id": "", "client_secret": ""},
    },
)

Options

FieldTypeDefaultNotes
client_idstr | list[str]required
client_secretstr""Optional — public clients (SPA/native + PKCE) are supported.
tenant_idstr | NoneNoneTenant segment of every endpoint; None means common. Also organizations, consumers, or a specific tenant id.
authoritystr | NoneNoneBase authority URL; None means https://login.microsoftonline.com (trailing slashes trimmed).
profile_photo_sizeint48Pixel size of the Microsoft Graph photo fetch.
disable_profile_photoboolFalseSkip the Graph photo fetch.
promptstr | NoneNoneForwarded as the prompt authorize param.
disable_id_token_sign_inboolFalseRefuse direct id-token sign-in.

All shared ProviderConfig options apply.

Notes

  • Default scopes: openid profile email User.Read offline_access.
  • Register {base_url}{base_path}/callback/microsoft as a redirect URI on the app registration.
  • Endpoints are {authority}/{tenant}/oauth2/v2.0/authorize|token with JWKS at {authority}/{tenant}/discovery/v2.0/keys.
  • Multi-tenant id-token verification: for common/organizations/consumers there is no single expected iss, so the token's tid claim is cross-checked against its iss ({authority}/{tid}/v2.0); organizations rejects consumer-tenant tokens, consumers requires them. Max token age is 1 hour, and the nonce is checked when present.
  • The profile photo is fetched from Microsoft Graph (/me/photos/{size}x{size}/$value) and inlined as a data: URI; a photo failure never blocks sign-in.
  • email_verified falls back to membership in verified_primary_email/verified_secondary_email when the optional claim is absent.

MIT licensed · API-compatible with better-auth