MountainGoat · Single Sign-On & Provisioning
For Microsoft Entra administrators connecting a Microsoft 365 tenant to a MountainGoat instance for sign-in, and optionally for automatic user provisioning.
This guide walks you through enabling Sign in with Microsoft for your MountainGoat instance using OpenID Connect (OIDC), and optionally SCIM provisioning so Entra creates, updates, and deactivates MountainGoat users automatically. At a glance:
Looking for email sync instead? This guide covers signing in to MountainGoat. To let MountainGoat read purchase-order email from a Microsoft 365 mailbox, see the Outlook Email Sync (Microsoft Entra) guide. The sign-in registration in this guide is a separate app from the mailbox one; if you already registered an app for email sync, leave it as it is and create a new registration here.
MountainGoat supports Microsoft Entra ID as an OIDC single sign-on provider, a peer of Sign in with Okta. When SSO is enabled, your users see a Sign in with Microsoft button on the MountainGoat login page and can also launch MountainGoat from their My Apps portal.
common, organizations, and consumers are refused when the configuration is saved.objectId / oid) as the account's identity, so the identity survives app re-registration. This is also why SCIM provisioning must send that same object id as externalId (see section 9).Supported: SP-initiated SSO, the My Apps tile, Just-In-Time account creation, app-role mapping, and optional SCIM 2.0 provisioning. Not supported: Single Logout (SLO), multi-tenant app registrations, and force authentication.
SSO alone is a complete setup. Steps 1–9 give your users Sign in with Microsoft, app-role-driven MountainGoat roles, and Require SSO if you want it. You create one Entra app, you need no Entra ID license tier, and you are done. Most instances stop here; accounts are created by invitation from the Users tab, exactly as they are without SSO.
SCIM provisioning is optional, and it is what makes offboarding a push from Entra rather than a refusal at next login. Add it when you want Entra to create, update, and deactivate MountainGoat accounts for you. It requires Entra ID P1 and a second Entra app.
| Path | Entra apps | License | Steps |
|---|---|---|---|
| SSO only | 1: App registrations → New registration (single tenant) | Any tenant, no P1 | 1–9, then stop |
| SSO + provisioning | That one, plus an Enterprise applications → New application → Create your own application → Integrate any other application you don't find in the gallery (Non-gallery) | Entra ID P1 | 1–9, then 10–23 |
If you are adding provisioning, know this before you start, because it is the single most common surprise here: Entra offers Provisioning → Automatic only on a non-gallery enterprise application you create yourself. The enterprise application Entra generates automatically behind your sign-in App registration does not offer it; its Provisioning blade is empty or offers manual only. There is no setting that turns this on. The second app is the supported path.
The two apps are tied together by the user's directory object id, which is identical in both. That is why the externalId mapping in step 16a is mandatory. Assignments are per app: app roles on the sign-in app drive MountainGoat roles, and users and groups on the provisioning app decide who gets provisioned. Assign the same people to both.
https://{app.subdomain}.mountaingoat.ai. Throughout this guide, {app.subdomain} is a placeholder for your subdomain label. Replace it everywhere it appears with your own label (for example acme, producing acme.mountaingoat.ai).Test instance. The shared instance for review and testing is demo.mountaingoat.ai (for example, start SSO at https://demo.mountaingoat.ai/auth/entra/login). Production clients each use their own {app.subdomain}.mountaingoat.ai host.
Sign in to the Microsoft Entra admin center at https://entra.microsoft.com (or https://portal.azure.com → Microsoft Entra ID), then:
https://{app.subdomain}.mountaingoat.ai/auth/entra/callback
https://{app.subdomain}.mountaingoat.ai/auth/entra/login
MG-Admin, MG-Manager, MG-Editor, MG-Viewer), then assign users or groups to those roles on the app's Enterprise application entry. App-role names arrive in the token's roles claim, the recommended source, readable in the mappings JSON (see section 6).
groups, and map group GUIDs instead of names.https://{app.subdomain}.mountaingoat.ai/auth/entra/login. The tile launch is plain SP-initiated sign-in; no separate initiate-login URI exists for Entra.Already have a MountainGoat app registration for Outlook email sync? That app grants read-only mailbox access and stays as it is. Sign-in uses this new, separate registration; the two are never combined. See the Outlook Email Sync guide for the mailbox side.
Sign in to your MountainGoat instance as an administrator, click Settings under the user profile, then select the Admin tab → API & Credentials → SSO Credentials → Entra ID Credentials.
roles is the default); map roles under Group/Role Mappings; set the Default Role; set the JIT Mode: strict if you are doing SSO only, mapped if you are going on to set up provisioning (see section 7 for why); set Enabled to Yes; Save.About the Client Secret. The secret is write-only in the Admin UI: you can enter or replace it, but MountainGoat never displays it back and stores it encrypted. On a later edit, leave the Client Secret blank to keep the existing secret. Only type in the field when you intend to replace it.
Doing SSO only? You are done. Accounts stay invitation-managed from the Users tab, and nothing in section 9 applies to you.
MountainGoat has five access roles: No access, View only, PO edit, Manager, and Full admin.
| Role | What it grants |
|---|---|
Full admin full_admin | Full administrator. All Admin tabs, PO Dashboard edit, and PO assignment rights. |
Manager manager | PO Dashboard edit plus PO assignment management. No Admin access. |
PO edit po_edit | PO Dashboard edit and can be assigned POs. No Admin or manager access. |
View only view_only | PO Dashboard view-only access. Cannot be assigned POs. |
No access none | No default application access. |
App roles (step 4) are the recommended way to carry role information from Entra: they are assigned per application, their names arrive in the roles claim, and the Group/Role Mappings stay readable (MG-Admin → full_admin, and so on). Keep MountainGoat's Group Claim on roles.
If your organization does not use app roles, add the groups claim under the app registration's Token configuration, set MountainGoat's Group Claim to groups, and map group GUIDs instead of names.
Very large directories. When a user belongs to 200 or more groups, Entra can omit the group claim from the token. MountainGoat degrades safely: the sign-in still succeeds, new users receive the Default Role, existing users keep their current role (never a demotion), and a group_overage_default_role entry is written to the audit trail. App roles avoid this limit entirely, which is another reason to prefer them.
Mappings are optional. Without them, users receive the Default Role and your MountainGoat administrator assigns roles by hand under Settings → Admin → Users. Entra confirms who the person is, and MountainGoat controls what they can do.
The JIT Mode field decides what happens when someone signs in through Entra who has no MountainGoat account yet:
| JIT Mode | Behavior |
|---|---|
strictrecommended steady state |
Only existing active MountainGoat users can sign in; on first successful login the account links by verified email. Unknown users are refused with unknown_user_strict_mode. |
view_only |
Unknown users are created with PO Dashboard view-only access. |
mapped |
Unknown users are created using the Group/Role Mappings, falling back to the Default Role. |
strict is the recommended steady state either way; it keeps account creation a deliberate act. Which value you start on depends on which path you are taking:
strict from the start. Your people already have MountainGoat accounts (you invited them from the Users tab), so strict simply links each one by verified email on their first Microsoft sign-in. Nothing to loosen, and it is the safest posture. Anyone new gets invited first, then signs in.mapped, tighten to strict at step 22. Between the moment SSO goes live and the moment provisioning finishes its first cycle, the people Entra is about to create are not in MountainGoat yet. Under strict every one of those sign-ins is refused with unknown_user_strict_mode, which reads as a broken SSO setup when it is really an empty user table. mapped lets your assigned users in on their mapped role while you work through section 9; once Entra has run a full cycle and the Users tab shows the accounts it created, switch to strict. From then on, someone removed from the Entra app cannot re-create themselves by signing in.Changing the mode is a Save on the same form and takes effect on the next sign-in.
The sign-in email is resolved from the token by precedence: email, then preferred_username (when it contains @), then upn (when it contains @). Which claim was used is recorded in the audit trail per login, so a tenant whose UPNs are not real mailboxes is diagnosable. A token with no resolvable email is refused, never linked to a guessed identity.
This precedence is also why the SCIM userName mapping in step 16 matters: provisioning must write the same address sign-in will resolve, or the same person arrives twice.
Allowed Email Domains (optional): enter one or more domains separated by commas, for example acme.com, partner.com, to limit sign-in to those domains. Everyone else is denied with email_domain_not_allowed. The restriction applies to the resolved email value. Leave the field blank to allow any domain your Entra assignment permits.
Everything in this section is optional. If SSO alone is what you wanted, you finished at step 9: accounts stay invitation-managed from the Users tab, and nothing here applies to you.
Add this section when you want Entra's provisioning service to create, update, and deactivate MountainGoat users automatically over SCIM 2.0, chiefly so that offboarding is a push from Entra rather than a refusal at next login. It is a platform capability on every MountainGoat instance, no extra module required, but it requires Entra ID P1 (or above) on your tenant: Microsoft gates automatic provisioning behind it.
Before you start, re-read section 2. Steps 12–13 create the second Entra app it describes.
Entra prod) and click Generate Token. The token is shown exactly once; copy it now. It is stored hashed and can never be displayed again. Copy the read-only Tenant URL too:
https://{app.subdomain}.mountaingoat.ai/scim/v2?aadOptscim062020
MountainGoat Provisioning), choose Integrate any other application you don't find in the gallery (Non-gallery), and Create. This second app is required: automatic provisioning is not offered on the enterprise application behind your sign-in registration (see section 2).16a: Change externalId to objectId. This is mandatory. The default source for externalId on a non-gallery app is mailNickname. Click that row and change the source attribute to objectId.
If you leave externalId on mailNickname, identity correlation breaks. MountainGoat stores each Entra user's directory object id as the account's identity when they sign in. Provisioning looks a user up by externalId before deciding whether to create them. With mailNickname there, that lookup never matches an account that has already signed in, so Entra tries to create someone who already exists, MountainGoat refuses the duplicate email with a 409 uniqueness error, and the cycle reports errors on exactly the people who were working fine. mailNickname is also editable in the directory, so it can change out from under the link; objectId never does.
16b: Delete every mapping row that is not on this list. MountainGoat implements the attribute subset it actually stores. Entra sends changed attributes as explicit SCIM paths, and a path outside this list is refused with 400 invalidPath; one such row makes every update fail even though the initial create succeeded. Keep exactly these seven rows:
| Keep this SCIM attribute | Source it to |
|---|---|
userName | userPrincipalName (the default), but see the note below |
active | Not([IsSoftDeleted]) (the default) |
displayName | displayName (the default) |
name.givenName | givenName (the default) |
name.familyName | surname (the default) |
externalId | objectId (changed in 16a) |
emails[type eq "work"].value | mail (the default) |
Delete all the rest. The rows Entra adds by default that MountainGoat refuses include name.formatted, preferredLanguage, title, every addresses[...] row (streetAddress, locality, region, postalCode, country, formatted) and every phoneNumbers[...] row (work, mobile, fax). Anything under the enterprise-user extension schema (department, manager, employeeNumber) goes too. None of them map to a MountainGoat field, so deleting them loses nothing; job title in particular is a MountainGoat field you set in MountainGoat, not one provisioning fills in.
On userName: MountainGoat resolves the sign-in email as email → preferred_username → upn, and for most tenants the email claim comes from the user's mail attribute. If your users' UPNs are their real mailboxes, Entra's userPrincipalName default is fine; leave it. If they are not, change the source to the expression Coalesce([mail], [userPrincipalName]) so provisioning writes the address sign-in will resolve. Getting this wrong makes the same person arrive as two accounts.
userName, matching precedence 1). Save the mappings.First and Last name blank? That is not a MountainGoat fault. Entra sends whatever givenName and surname hold, and plenty of directories leave those empty even when the display name looks fine, so such a person reads as nameless in the Users table. Populate First name and Last name on the user in Entra and provision on demand again. A name typed into MountainGoat instead can be overwritten the next time Entra syncs that user.
strict on the Entra ID Credentials form, per section 7.active: false (and SCIM DELETE, which deactivates; MountainGoat never hard-deletes over SCIM) revokes every live session. The last active full administrator can never be deactivated via SCIM.Every failed Entra sign-in shows a short error code on a clear error page and writes the same code to the audit trail. The SSO Status panel shows the last error reason with its time; it never shows secrets, tokens, raw claims, or signing keys.
| Error code | Cause | Fix |
|---|---|---|
entra_not_configured |
The provider is disabled or a required field is missing. | Finish the Entra ID Credentials form and set Enabled to Yes. |
entra_discovery_unavailable |
login.microsoftonline.com discovery is unreachable and no cached document exists. |
Check the instance's egress to login.microsoftonline.com (firewall or proxy) and Microsoft service health. The Test connection button isolates this without a sign-in. |
invalid_tenant |
The token's tenant does not match the configured Tenant ID. | The app registration lives in a different tenant than configured, or a multi-tenant app is being reused. Register a single-tenant app in the right directory. |
missing_email_claim |
No usable email in email, preferred_username, or upn. |
Add an email claim in Token configuration, or populate the user's mail attributes. |
missing_object_id |
The token carries no oid claim. |
Almost always a token configuration problem; MountainGoat refuses rather than link an unstable identity. Review the app registration's token configuration. |
email_conflict_inactive_user |
A deactivated MountainGoat account already owns this email. | Reactivate (or rename) that account deliberately; sign-in is refused rather than silently resurrecting or duplicating it. |
unknown_user_strict_mode |
JIT Mode is strict and this person has no MountainGoat account yet. |
Invite them, provision them, or switch JIT Mode deliberately. During a first setup this usually means JIT was tightened to strict before provisioning had run; see section 7. |
email_domain_not_allowed |
The resolved email's domain is outside Allowed Email Domains. | Add the domain to Allowed Email Domains, or clear the restriction. |
group_overage_default_role |
Not a failure. The user belongs to 200+ groups, so the group claim was omitted; the sign-in succeeded on the Default Role or the user's existing role. | Prefer app roles (the roles claim), which do not hit the overage limit. |
invalid_state, invalid_nonce |
The sign-in session did not match, often from an old or reused callback link. | Start sign-in again from the MountainGoat login page. |
expired_token |
The ID token had already expired when it reached MountainGoat. | Start sign-in again. If it keeps happening, confirm the system clocks are accurate. |
Entra reports these on the provisioning app's Provisioning logs; the matching refusal also lands in MountainGoat's Provisioning Activity readout.
| Symptom | Cause | Fix |
|---|---|---|
invalidPath / "Unsupported PATCH path" |
A mapping row outside the seven-row keep-list. This typically shows up only after the first successful create, on the first update. | Redo step 16b. |
uniqueness / 409 on create |
The email already belongs to another MountainGoat account. | Either externalId is not sourced from objectId (step 16a), or userName is writing a different address than sign-in resolves (the userName note in step 16). |
| 401 on every request | The token is wrong, was rotated, or was revoked. | Generate a new token and paste it into Admin Credentials. |
| 403 on every request, including a token that used to work | Provisioning Enabled is off in MountainGoat. It is the kill switch, and it is checked before the token. | Switch Provisioning Enabled back on and save. |
| Quarantined | Entra quarantines an endpoint after repeated failures. | Fix the cause, then use Restart provisioning; a corrected mapping alone does not clear quarantine. |
login.microsoftonline.com for SSO. SCIM is inbound-only: Microsoft's provisioning service calls your instance, and MountainGoat calls nothing in your tenant for it.{app.subdomain}.mountaingoat.ai already satisfy this.For help configuring Microsoft Entra SSO or SCIM provisioning for MountainGoat, contact: