Skip to Content
🔐 Faable AuthSocial LoginMicrosoft (Entra ID)

Microsoft (Entra ID) Social Login

The Microsoft social connection lets users sign in with a Microsoft account — both work/school identities from Microsoft Entra ID (formerly Azure AD) and personal accounts (outlook.com, hotmail.com, Xbox). Faable Auth talks to the Microsoft identity platform on the common authority, which accepts both, so a single connection type covers what other providers split into two.

Faable Auth runs the standard Microsoft identity platform Authorization Code flow . After consent, Microsoft redirects back to Faable Auth’s /callback, which exchanges the code for a token, fetches the profile from https://graph.microsoft.com/oidc/userinfo, normalizes it, and issues your application its own OAuth 2.0 / OIDC tokens.

Two ways to enable it

Faable’s shared appYour own Entra app
SetupToggle the connection on. No Azure portal.Register an app in Entra ID, paste credentials.
Consent screen showsFaableYour company name
Redirect URI at Microsofthttps://faable.auth.faable.link/callback (already registered)https://{YOUR_DOMAIN}/callback
Restrict to one directory❌ Not possible✅ Yes
Good forTrying it out, side projectsProduction, anything branded

Leaving Client ID and Client Secret empty puts the connection on Faable’s shared app registration; filling them in switches it to yours. The connection’s read-only is_using_default_credentials field tells you which mode it’s in.

Switching modes changes user identities. Read Entra’s sub is pairwise before you move a live connection from the shared app to your own.


Option A — Use Faable’s shared app

  1. In the Faable Dashboard, go to Auth → Social Login and click Create.
  2. Choose Microsoft as the connection type.
  3. Name the connection (e.g. microsoft), leave Client ID and Client Secret empty, toggle Enabled on and save.

Sign-in works immediately. Because Google, GitHub and Microsoft all require an exact, non-wildcard redirect URI — and per-tenant subdomains cannot all be registered in one app — connections on shared credentials send Microsoft to a single central callback (https://faable.auth.faable.link/callback). That host acts as a pure relay: it forwards ?code&state to your own auth domain, where the session cookie is set. Nothing to configure on your side, but it’s why the consent screen says Faable.


Option B — Register your own Entra ID app

Find your Faable Auth domain

  1. In the Faable Dashboard, go to Auth → Settings → Custom Domains.

  2. Without a custom domain, your Faable Auth domain is {YOUR_FAABLEAUTH_NAME}.auth.faable.link.

  3. Your redirect URI is:

    https://{YOUR_DOMAIN}/callback

    The path is always /callback — one account-wide callback handled by Faable Auth, not by your application. Your app’s own redirect URI (registered on the Faable Auth Client) is invoked later, once Faable finishes the handshake with Microsoft.

Register the app

  1. Open the Microsoft Entra admin center Identity → Applications → App registrationsNew registration. (The same blade exists in the Azure portal.)

  2. Fill in:

    FieldValue to Provide
    NameThe name users see on the consent screen (e.g. Acme Corp).
    Supported account typesAccounts in any organizational directory and personal Microsoft accounts for the widest reach, or Accounts in this organizational directory only to lock sign-in to your company — see Restricting sign-in.
    Redirect URIPlatform Webhttps://{YOUR_DOMAIN}/callback. Must match exactly: scheme, host, path, no trailing slash.
  3. Click Register and copy the Application (client) ID from the overview page.

  4. Go to Certificates & secrets → Client secrets → New client secret. Copy the Value (not the Secret ID) immediately — Entra shows it once.

  5. Under API permissions, confirm the delegated Microsoft Graph permissions openid, profile, email. They are granted by default and are all Faable needs.

Entra client secrets always expire. The maximum lifetime is 24 months and there is no “never expires” option. Put the expiry date in your calendar: when the secret lapses, every sign-in through this connection breaks at once with a token-exchange error.

Create the connection in Faable Auth

  1. Auth → Social Login → Create, choose Microsoft.

  2. Fill in:

    FieldValue to Provide
    Connection nameInternal identifier, e.g. microsoft.
    Client IDThe Application (client) ID from Entra.
    Client SecretThe secret Value from Entra. Stored encrypted at rest.
    ScopeOptional. Defaults to openid profile email — see Scopes.
    Enabled clientsOptional. Restrict which Faable Auth Clients can use this connection. Empty = every Client in the account.
    EnabledToggle on to make the connection live.
  3. Save.

The upstream URLs are preconfigured, so you do not enter them manually:

  • Authorize URL: https://login.microsoftonline.com/common/oauth2/v2.0/authorize
  • Token URL: https://login.microsoftonline.com/common/oauth2/v2.0/token
  • User Info URL: https://graph.microsoft.com/oidc/userinfo
  • Response type: code

Restricting sign-in to your own directory

The common authority accepts every Microsoft identity on earth, including personal accounts. To allow only members of your own Entra tenant, override both URLs on the connection, replacing common with your Directory (tenant) ID:

https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/authorize https://login.microsoftonline.com/{TENANT_ID}/oauth2/v2.0/token

This only works with your own app registration — the shared Faable app is multi-tenant by construction. Set Supported account types to this organizational directory only as well, so the restriction is enforced by Microsoft rather than by URL hygiene alone.


Scopes

The default scope is openid profile email:

ScopeWhat it grants
openidRequired. Without it the /oidc/userinfo endpoint rejects the token outright.
profileThe name claims (name, given_name, family_name).
emailThe user’s email address.

Faable deliberately requests no Microsoft Graph resource scopes (User.Read and friends). They widen the consent screen for every tenant on the shared app and buy nothing the login flow needs. If your application calls Graph itself, request those scopes from your own app with your own token — don’t bolt them onto the login connection.


User profile mapping

Faable normalizes the https://graph.microsoft.com/oidc/userinfo response into the internal user shape:

Faable user fieldSourceNotes
idsubPairwise — see the warning below.
namename, falling back to given_name + family_namename needs the profile scope and is absent on some guest accounts.
given_namegiven_name
family_namefamily_name
emailemailComes from the directory mail attribute.
pictureDeliberately dropped. Graph returns the literal string https://graph.microsoft.com/v1.0/me/photo/$value, an endpoint that demands a bearer token. Storing it would render a broken 401 image everywhere the avatar appears.
email_verifiedNever set to true. See below.

Entra’s sub is pairwise — plan before you switch apps

Unlike Google’s sub or GitHub’s numeric id, Microsoft’s sub is unique per (user, app registration). The same human signing in through Faable’s shared app and through your own app produces two different sub values, so Faable sees two different identities.

Consequence: moving a live connection from shared credentials to your own app registration makes every existing user look brand new — they get a fresh account instead of their old one. Do it before you have users, or plan an identity migration.

Why email_verified stays false

Microsoft does not return email_verified, and Entra’s email comes from the directory mail attribute — which a tenant admin can point at a domain they do not own. That’s the nOAuth class of account-takeover attack: an attacker who controls any Entra tenant sets mail to your user’s address and, on a server that trusts it, takes over the account.

Faable therefore lands Microsoft users with email_verified: false and never treats the Microsoft-supplied address as proof of ownership. If you want a verified address, run Faable’s own email verification on top.


Trigger a login

Send users straight to Microsoft by passing the connection on /authorize (the id is shown on the connection in the dashboard):

https://{YOUR_DOMAIN}/authorize ?client_id={YOUR_CLIENT_ID} &response_type=code &redirect_uri={YOUR_APP_CALLBACK} &scope=openid%20profile%20email &state={RANDOM_STATE} &connection_id=connection_abc123

Omit connection_id and the Universal Login screen appears with Microsoft as one of the options, provided the connection is enabled for that Client. See Authorization Code Flow for the full request reference.

Rotate or revoke credentials

  • Rotate the client secret: create a new secret in Certificates & secrets before the current one expires, paste it into the connection and save. Existing sessions are unaffected; only new sign-ins need the new secret.
  • Revoke a user’s grant: users manage this at myapplications.microsoft.com . Revoking does not end their Faable session — that lives until it expires — but they will re-consent on their next Microsoft sign-in.
  • Delete the app registration: cuts off everyone. Disable the Faable connection at the same time so users aren’t routed to a broken upstream.

Troubleshooting

SymptomLikely cause
AADSTS50011: redirect URI mismatchThe Redirect URI in Entra doesn’t match https://{YOUR_DOMAIN}/callback exactly. If you’re on shared credentials it must instead be Faable’s relay — you shouldn’t be registering anything at all.
AADSTS7000215: Invalid client secretThe Secret ID was pasted instead of the secret Value, or the secret expired.
AADSTS50020: user account from identity provider does not exist in tenantThe app is registered as single-tenant but the user belongs elsewhere. Widen Supported account types, or keep the restriction if that’s the intent.
Login works but the user has no nameThe profile scope was removed from the connection, or it’s a guest account with no name in the directory.
Users show up as new accounts after a config changeThe connection moved between the shared app and your own — sub is pairwise. See above.
All Microsoft logins break on the same dayThe Entra client secret expired. It always does, within 24 months at most.

Last updated on