What's still in preview
Part 1 covered everything that shipped GA in Entra External ID between November 2025 and February 2026 — regional data residency, machine-to-machine auth, per-app branding, custom banned passwords, alias sign-in, and device auth grant. This part covers what's still in public preview, which honestly has some of the more interesting features for teams planning a migration from an existing customer identity system.
Preview in Microsoft's terminology means the feature is available for use in production, but the API shape may still change, SLAs aren't guaranteed, and you're providing feedback that shapes the final version. For identity infrastructure, that's worth factoring in — don't build a hard dependency on a preview API's exact request/response format if you can avoid it.
Preview status as of February 2026: Just-in-time password migration entered public preview in December 2025. WAF integrations with Akamai and Cloudflare reached documentation GA status in late 2025 with ongoing updates. MFA with Conditional Access authentication context was updated in November 2025. All features are available for external tenants today.
Just-in-time password migration
This is the standout preview feature. If you're running a CIAM migration — moving customers from an existing identity system to External ID — the traditional approach requires a bulk password migration event. You export hashed passwords, reformat them, import them into the new system, and hope nothing goes wrong. In practice, something always goes wrong: hash format incompatibilities, accounts that haven't been touched in years, users who've forgotten they exist, regulatory restrictions on moving password hashes across systems.
Just-in-time (JIT) migration solves this differently. Instead of migrating all passwords upfront, you migrate each customer's password the first time they sign in after the cutover. The flow works like this:
- Customer tries to sign in to External ID for the first time after migration
- External ID checks whether the account has a local password set
- If not, it calls a custom REST API endpoint you control (the "legacy system connector")
- Your API validates the credential against your old system and returns a success/failure response
- If your API says the credential is valid, External ID sets the password on the account and completes sign-in
- On subsequent sign-ins, External ID handles authentication directly — no more calls to your legacy system
The result: customers never notice the migration. They sign in as normal on cutover day, and their password just works. No password reset emails, no "account not found" errors, no forced re-registration.
The legacy system connector API you need to build
The JIT migration feature doesn't talk to your old database directly — you build a REST API that acts as the bridge. External ID calls this API when it needs to verify a credential that isn't in the external tenant yet. The API has one job: take a credential verification request and return whether it's valid.
The request from External ID to your API includes an encryptedPasswordContext field
— a Base64-encoded, encrypted structure that contains the username and the password the user
just submitted. Your API decrypts it using a key you've configured in the External ID JIT
migration settings, verifies against your old system, and responds with a standardised JSON
body.
encryptedPasswordContext field in the request body was updated in January
2026 (preview iteration). Check the current docs for the latest field specification before
implementing — this is still in preview and the API shape can change.
A minimal implementation of the legacy connector API looks something like this. The key steps
are: receive the request from External ID, decrypt the encryptedPasswordContext to
get the username and password, verify against your old system, and return the right JSON
structure:
# Conceptual structure of the legacy credential verification endpoint
# Your implementation will vary based on language and old system type
POST /api/verify-credential
Content-Type: application/json
{
"type": "microsoft.graph.OnTokenIssuanceStartCustomExtensionHandler",
"source": "/tenants/{tenantId}/...",
"encryptedPasswordContext": "BASE64_ENCRYPTED_BLOB"
}
# Your API decrypts encryptedPasswordContext using the configured key
# Verifies username + password against your legacy database/system
# Returns one of:
# SUCCESS — credential is valid
HTTP 200 OK
{
"@odata.type": "microsoft.graph.onAttributeCollectionSubmitResponseSuccess",
"actions": [
{
"@odata.type": "microsoft.graph.validatePassword",
"passwordIsValid": true
}
]
}
# FAILURE — credential is not valid
HTTP 200 OK
{
"@odata.type": "microsoft.graph.onAttributeCollectionSubmitResponseSuccess",
"actions": [
{
"@odata.type": "microsoft.graph.validatePassword",
"passwordIsValid": false
}
]
}
Security note: The
encryptedPasswordContextcontains the raw password the customer typed. Handle this with the same care as any plaintext password in transit — decrypt it in memory, verify it, discard it. Don't log it, don't store it, don't pass it to a queue. Your legacy connector API should run in a private network segment accessible only to External ID's outbound IP ranges, and use mutual TLS or bearer token validation to reject requests from anything other than External ID.
JIT migration vs bulk migration — when to use which
JIT migration isn't always the right answer. The main trade-offs:
| Factor | JIT Migration | Bulk Migration |
|---|---|---|
| Customer disruption | None — transparent to users | May require password reset if hashes can't transfer |
| Cutover speed | Instant — flip DNS/app config, done | Requires import window, verification period, rollback plan |
| Old system dependency | Legacy API must stay up until all users migrate | Old system can be decommissioned after bulk import |
| Inactive accounts | Never migrate — accounts that don't sign in stay in limbo | All accounts migrated regardless of activity |
| Regulatory concern | Credential only leaves old system on user's sign-in | Bulk password hash export may face regulatory scrutiny |
| Implementation effort | Build and host the legacy connector API | Export/transform/import tooling, higher upfront effort |
For most consumer-facing CIAM migrations, JIT migration is the better choice. The sticking point is inactive accounts — if you have a large tail of dormant users who'll never sign in again, those accounts will sit in your external tenant without passwords indefinitely. You can address this with a parallel cleanup job that periodically removes accounts flagged as inactive past a threshold, or by running a batch migration alongside the JIT flow for accounts that haven't migrated within 90 days.
WAF integrations: Akamai and Cloudflare
External ID now has documented integration patterns for two major web application firewalls: Akamai and Cloudflare. Both reached documentation GA status in late 2025, with ongoing updates to the integration guides through early 2026.
The reason this matters: External ID's sign-in endpoints are public-facing by definition. Your customers need to reach them, which means anyone can reach them. Without a WAF in front, you're exposed to credential stuffing attacks (automated password guessing at scale), bot-driven account enumeration, and volumetric attacks that can degrade sign-in performance for real users.
Akamai integration
The Akamai integration uses Akamai's Bot Manager and Web Application Firewall products in front of your External ID sign-in domain. The setup involves pointing a custom domain for your External ID sign-in endpoint through Akamai's edge, then configuring Akamai's rules to protect the sign-in flow while allowing legitimate authentication traffic through.
A few things specific to the Akamai integration worth knowing:
- You configure a custom hostname in External ID (e.g.,
login.yourbrand.com) and then route that hostname through Akamai rather than directly to Microsoft's infrastructure - Akamai's bot detection runs on every request to the sign-in endpoints — it can distinguish automated credential-stuffing traffic from real browser sessions using behavioural signals
- Akamai can be configured to inject a challenge (JavaScript, CAPTCHA) for suspicious sessions before they reach External ID, which offloads the challenge handling to the WAF layer
- The integration supports Akamai's Security Information and Event Management (SIEM) connector, so sign-in attack telemetry flows into your security tooling
Cloudflare integration
The Cloudflare integration follows a similar pattern — your External ID custom domain routes through Cloudflare's network before reaching Microsoft's infrastructure. Cloudflare's WAF and bot management rules apply to the authentication traffic.
The Cloudflare integration was updated in December 2025 with revised configuration steps that account for changes in Cloudflare's proxy settings for custom domains. If you configured this before December 2025, check the current docs — the origin server configuration in Cloudflare's dashboard changed slightly.
Practically, both Akamai and Cloudflare provide similar protection capabilities for this use case. The choice between them usually comes down to what your organisation already has a contract with, rather than feature differentiation specific to External ID.
login.yourbrand.com rather than a
Microsoft-branded endpoint.
MFA with Conditional Access authentication context
Conditional Access authentication context lets you require step-up authentication at specific points in your application — not just at sign-in. The update in November 2025 extended this to MFA enforcement within external tenants, meaning you can trigger MFA challenges mid-session based on what the user is trying to do.
The practical use case: a customer signs in to your portal with password only (standard friction
for browsing). When they go to change their email address or initiate a high-value transaction,
your application requests the acrs claim with a specific authentication context
value. External ID checks whether the current session satisfies that context, and if not,
prompts for MFA before proceeding.
This is the right pattern for apps where you want low-friction browsing but high-friction for sensitive operations — it's much better UX than requiring MFA on every sign-in, and more secure than never requiring MFA during a session.
# In your application, when a sensitive action is triggered:
# Request a token with the acr_values or claims parameter
# specifying your configured authentication context class reference
# Example: initiating a high-value operation
POST /token
{
"grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
"claims": "{\"access_token\":{\"acrs\":{\"essential\":true,\"value\":\"c1\"}}}"
}
# If the current session doesn't satisfy context "c1",
# External ID returns an interaction_required error.
# Your app then redirects to the authorization endpoint with:
GET /authorize?
claims={"access_token":{"acrs":{"essential":true,"value":"c1"}}}
&prompt=login
# User is challenged for MFA, session is elevated, token re-issued.
Licensing: what the add-ons actually cost
External ID has two add-ons that are easy to miss if you're just looking at the base pricing:
| Component | What it covers | Billing model | Required for |
|---|---|---|---|
| Base External ID | User authentication, social IdP federation, user flows, Conditional Access, MFA, branding | Per MAU/month (50k free) | Everything basic |
| Go-Local add-on | Data residency in selected region (US, EU, AU, JP) | Per MAU/month (premium rate) | AU/JP data residency requirements |
| M2M Premium add-on | Client credentials grant (machine-to-machine auth), app-only token issuance | Per token (not per user) | Backend service auth, daemon flows |
The M2M Premium add-on pricing per-token can add up if your backend services call External ID frequently — for example, if every API request from your service requires a fresh token rather than caching and reusing tokens for their full lifetime. Standard OAuth 2.0 token caching applies: cache tokens until they're within a few minutes of expiry, then refresh. Don't fetch a new token on every API call.
When External ID is the right call
External ID makes sense when you need a managed CIAM platform without building and operating identity infrastructure yourself. But it's not the right answer for everything. A few factors worth thinking through:
A few things the decision tree doesn't capture:
- If you're already running Keycloak, Auth0, or another CIAM platform and it's working, factor in the switching cost — External ID isn't automatically better just because it's Microsoft's product.
- External ID is still catching up to more mature CIAM platforms in some areas. Check specifically for advanced progressive profiling, complex attribute mapping, and highly customised authentication flows before committing.
- If your identity team knows Entra ID well, External ID is a natural extension. If they know Okta or Auth0 deeply, the operational overhead of switching platforms is real.
Preview features summary
| Feature | Preview Since | Status (as of Feb 2026) | Production-ready? |
|---|---|---|---|
| JIT password migration | Dec 2025 | Public Preview — API updated Jan 2026 | Use with caution — API may still change |
| Akamai WAF integration | Nov 2025 | Documented — ongoing config updates | Yes — pattern is stable |
| Cloudflare WAF integration | Late 2025 | Documented — Dec 2025 config refresh | Yes — verify against latest docs first |
| MFA with CA authentication context | Nov 2025 | Updated — external tenant support | Yes — GA capability with updated config |
Official Microsoft docs
| Topic | Microsoft Learn link |
|---|---|
| JIT password migration (Preview) | learn.microsoft.com → JIT password migration |
| Configure Akamai WAF | learn.microsoft.com → Akamai integration |
| Configure Cloudflare WAF | learn.microsoft.com → Cloudflare integration |
| MFA in external tenants | learn.microsoft.com → MFA in external tenants |
| What's new (External ID) | learn.microsoft.com → What's new |
Where things stand in early 2026
External ID is in a noticeably better state in early 2026 than it was twelve months ago. The GA features in Part 1 fill meaningful gaps — machine-to-machine auth, regional data residency for APAC, per-app branding, and several authentication flow improvements that matter for specific industry verticals.
The preview features are the ones I'd watch most closely for migrations. JIT password migration in particular could significantly reduce the operational risk of moving a large customer base from a legacy CIAM platform — the fact that you don't need a coordinated cutover event, and customers never hit a "reset your password" wall, is a real practical win.
The platform still has gaps. If you need features that more mature CIAM platforms offer, do the feature comparison before committing. But if you're starting fresh on a Microsoft stack, or you've been deferring a CIAM migration because the tooling wasn't good enough, the gap has closed considerably.