> For the complete documentation index, see [llms.txt](https://docs.openiam.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.openiam.com/getting-started-guide/federation/openiam-idp-entra.md).

# OpenIAM as IdP for Microsoft Entra ID

Make OpenIAM the identity provider for Microsoft Entra ID using SAML 2.0.

**Goal:** users of one test Entra domain sign in to Microsoft 365 by authenticating at OpenIAM, via SAML domain federation.\
**Time:** 90–120 minutes, plus propagation waits (typically \~15 minutes; Microsoft warns changes can take up to 2 hours).\
**What this proves:** OpenIAM issues assertions Microsoft accepts; identifier matching works both ways; federation is cleanly reversible.\
**Prerequisites:** [shared prerequisites](/getting-started-guide/federation.md); a **verified, disposable test domain** in the Entra tenant (the default `*.onmicrosoft.com` domain cannot be federated); Microsoft Graph PowerShell module; an Entra role that can manage federation — **Domain Name Administrator**, External Identity Provider Administrator, Hybrid Identity Administrator, or Security Administrator (Global Administrator not required).

## Values worksheet

| Name                                                                             | Example                    | Yours |
| -------------------------------------------------------------------------------- | -------------------------- | ----- |
| Test Entra domain (lowercase!)                                                   | `poc.example.com`          |       |
| OpenIAM host                                                                     | `openiam.poc.example.com`  |       |
| Provider ID (after step 3)                                                       | `3012`                     |       |
| Issuer / IssuerUri (default = `https://<host>/idp/saml2/idp/login/<providerId>`) |                            |       |
| Test user UPN (both directories)                                                 | `fedtest1@poc.example.com` |       |
| Immutable ID for the test user                                                   | `fedtest1@poc.example.com` |       |

## Safety checks — do not skip

{% hint style="danger" %}
**Blast radius:** federating a domain redirects sign-in for **every user on that domain**, and Microsoft warns of **up to 2 hours of sign-in disruption** after the change. That's why this runs on a disposable test domain with test users only.
{% endhint %}

Before touching federation:

1. **Two or more break-glass admins**, per Microsoft's emergency-access guidance: cloud-only accounts on the tenant's original `*.onmicrosoft.com` domain, **not** federated or synced, **excluded from Conditional Access**, permanently assigned Global Administrator, phishing-resistant sign-in (FIDO2 recommended). They must not depend on OpenIAM in any way.
2. **Log in with both break-glass accounts now.** An untested break-glass account is a decoration.
3. Have the rollback command from the Rollback section copy-pasted and ready before you run step 5.
4. Test users on the domain hold no privileged roles.

{% stepper %}
{% step %}
**Understand the matching contract (this is where federation fails)**

For a federated domain, Microsoft requires the assertion to carry **two** identifiers, and both must match the Entra user object exactly:

* **NameID** (format `urn:oasis:names:tc:SAML:2.0:nameid-format:persistent`) must equal the user's **ImmutableID** (`onPremisesImmutableId`). No documented fallback to UPN exists — a user without a matching immutable ID cannot federate in.
* An **IDPEmail** attribute must equal the user's **UserPrincipalName**.

The simple POC contract used below: *the user's OpenIAM login = their Entra UPN = their immutable ID*. Authentication succeeding at OpenIAM but Microsoft rejecting the assertion is almost always one of these two values disagreeing.
{% endstep %}

{% step %}
**Prepare the test user's immutable ID in Entra**

Inspect first (the property isn't returned unless requested):

{% code overflow="wrap" %}

```powershell
Connect-MgGraph -Scopes "User.ReadWrite.All"
Get-MgUser -UserId fedtest1@poc.example.com -Property UserPrincipalName,OnPremisesImmutableId | Format-List
```

{% endcode %}

If unset, set it (allowed on cloud-only users; the `$` and `_` characters are not permitted in the value):

{% code overflow="wrap" %}

```powershell
Update-MgUser -UserId fedtest1@poc.example.com -OnPremisesImmutableId "fedtest1@poc.example.com"
```

{% endcode %}

Operational note: updating the immutable ID of a user whose UPN is already on a *federated* domain commonly fails — set it **before** federating (as here), or temporarily move the UPN to the `.onmicrosoft.com` domain to change it.
{% endstep %}

{% step %}
**Create the SAML Identity Provider in OpenIAM**

**Access Control → Authentication Providers** → create a new provider → type **SAML Identity Provider**. The efficient path is metadata import: download Microsoft's federation metadata from `https://nexus.microsoftonline-p.com/federationmetadata/saml20/federationmetadata.xml` and use **Import from Service Provider Metadata**. Whether imported or manual, the provider must end up with:

| Field                    | Value                                                                                                                                            |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| Provider Name            | `Entra POC`                                                                                                                                      |
| Linked to Managed System | the default OpenIAM managed system (the user's OpenIAM login feeds the NameID)                                                                   |
| Assertion Consumer URL   | `https://login.microsoftonline.com/login.srf`                                                                                                    |
| Request Issuer           | `urn:federation:MicrosoftOnline` (the issuer Entra sends in its AuthnRequests — OpenIAM uses it to find this provider)                           |
| Response Issuer          | leave default — it becomes `https://<host>/idp/saml2/idp/login/<providerId>`, your IssuerUri for step 5                                          |
| Audiences                | `urn:federation:MicrosoftOnline`                                                                                                                 |
| Name ID Format           | Persistent                                                                                                                                       |
| Signature                | **Generate a new key** (RSA-2048, 2-year self-signed) unless you have a managed keypair; assertions must be signed — enable assertion signing    |
| Attributes section       | add one row: Property Name `IDPEmail`, source *Property from User* → the user's principal/UPN-equivalent (email if your logins are email-format) |
| Resource                 | required — auto-created with the provider; you entitle users to it next                                                                          |

Entitle the test population: role → **Entitlements** → add this provider's resource (type *Authentication provider*), assign the role to `fedtest1`. Remember both gates from the [chooser](/getting-started-guide/federation.md): entitlement **and** a login on the linked managed system — and per step 1's contract, that login must equal `fedtest1@poc.example.com`.

Verify `https://<openiam-host>/idp/saml2/idp/metadata/<providerId>` returns XML in a browser.
{% endstep %}

{% step %}
**Download the signing certificate**

On the provider page: **Download Signing Public Key**. Load it for Graph:

{% code overflow="wrap" %}

```powershell
[string]$cer = Get-Content "path\to\downloaded-signing-key"
```

{% endcode %}
{% endstep %}

{% step %}
**Federate the test domain (the disruptive step — rollback below is ready?)**

{% code overflow="wrap" expandable="true" %}

```powershell
Connect-MgGraph -Scopes "Domain-InternalFederation.ReadWrite.All"
Get-MgDomain    # confirm the test domain is verified, and is NOT your production domain

New-MgDomainFederationConfiguration `
  -DomainId "poc.example.com" `
  -DisplayName "OpenIAM POC" `
  -ActiveSignInUri  "https://<openiam-host>/idp/saml2/idp/login" `
  -PassiveSignInUri "https://<openiam-host>/idp/saml2/idp/login" `
  -IssuerUri "https://<openiam-host>/idp/saml2/idp/login/<providerId>" `
  -SignOutUri "https://<openiam-host>/idp/saml2/idp/logout" `
  -PreferredAuthenticationProtocol "saml" `
  -SigningCertificate $cer `
  -FederatedIdpMfaBehavior "rejectMfaByFederatedIdp"
```

{% endcode %}

{% hint style="info" %}
`Domain-InternalFederation.ReadWrite.All` is Microsoft's documented least-privileged scope (`Domain.ReadWrite.All` also works but is broader). `-PreferredAuthenticationProtocol "saml"` is **mandatory** — federation silently misbehaves without it. `-DomainId` must be lowercase (mixed case can trigger `AADSTS50107`). `rejectMfaByFederatedIdp` means Entra always runs its own MFA and ignores IdP MFA claims — the predictable choice for a POC; the default if omitted is `acceptIfMfaDoneByFederatedIdp`..
{% endhint %}

Verify the domain state:

{% code overflow="wrap" %}

```powershell
Get-MgDomainFederationConfiguration -DomainId "poc.example.com" | Format-List
```

{% endcode %}
{% endstep %}

{% step %}
**Validate**

Wait \~15 minutes. In a private window, go to `office.com`, enter `fedtest1@poc.example.com` → Microsoft should redirect to your OpenIAM login → authenticate → land signed in. If it fails immediately, wait out the propagation before debugging.

**Negative tests:** (a) a user entitled in OpenIAM but with a *wrong* immutable ID in Entra must be rejected *by Microsoft after* successful OpenIAM login — that's authentication vs. matching, observed directly; (b) a user not entitled to the provider's resource must be refused *by OpenIAM*.
{% endstep %}
{% endstepper %}

## Evidence to capture

`Get-MgDomainFederationConfiguration` output; the metadata URL response; a screenshot of the office.com→OpenIAM redirect and the signed-in landing; both negative-test error screens; the rollback verification below.

## Rollback

{% code overflow="wrap" %}

```powershell
Get-MgDomainFederationConfiguration -DomainId "poc.example.com"
Remove-MgDomainFederationConfiguration -DomainId "poc.example.com" -InternalDomainFederationId <id>
```

{% endcode %}

Reversion to managed authentication can also take up to 2 hours; converting real users back involves password resets, which is another reason this ran on test users. Confirm with `Get-MgDomain` that the domain shows managed, and that the test user can no longer reach OpenIAM from office.com.

## You know this worked when…

{% hint style="success" %}
The test-domain user reaches Microsoft 365 by authenticating at OpenIAM, both negative tests fail in the expected place, and rollback returns the domain to managed auth.
{% endhint %}

## If it failed

| Symptom                                                 | Likely cause / where to look                                                                                            |
| ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `AADSTS50107`                                           | Domain case, wrong IssuerUri, or propagation not finished — compare IssuerUri to the provider's Response Issuer exactly |
| Redirect to OpenIAM works, Microsoft rejects afterwards | NameID ≠ ImmutableID, or IDPEmail ≠ UPN — re-run step 2's inspection; check the OpenIAM login value                     |
| No redirect at all                                      | Federation not propagated, or sign-in URL unreachable from the internet over trusted HTTPS                              |
| OpenIAM error before login                              | User not entitled to the provider resource, or no login on the linked managed system                                    |

More: [Federation troubleshooting and recovery](/getting-started-guide/federation/troubleshooting.md). Next: [OpenIAM as IdP for Google Workspace](/getting-started-guide/federation/openiam-idp-google.md).


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.openiam.com/getting-started-guide/federation/openiam-idp-entra.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
