SMS Codes Just Got an SLA: Native-App MFA Goes GA in Entra External ID

Step-up MFA for Native Authentication in Entra External ID reaches GA. Add email or SMS second-factor to mobile apps without browser redirects—but the phishing risks remain.

You can now bolt a second factor onto a customer sign-in inside your iOS or Android app without ever launching a browser, and Microsoft will stand behind it with a support contract. That’s the news: as of the identity dev blog post published this week, email and SMS one-time passcode MFA for Native Authentication in Entra External ID is generally available. Preview is over. There’s an SLA now.

Good. It was a sensible feature stuck behind a “don’t ship this to production” sign for too long. But before anyone treats “GA” as a synonym for “secure,” let’s put the two ways of doing customer MFA next to each other and score them on the things that actually decide whether you regret this in six months.

First, what Native Authentication actually is

Two clarifications, because both of these trip people up.

One: this is Entra External ID — the customer-and-consumer identity product, the thing that ate Azure AD B2C’s job. It runs in an external tenant, which is a separate object from your workforce tenant. None of this touches employee MFA. If you came here looking to change how your staff sign in, wrong article, close the tab.

Two: “Native Authentication” means the sign-up and sign-in screens are drawn by your app using Microsoft’s SDKs, and the credential exchange happens through API calls behind the scenes. No browser handoff. No system webview flashing a Microsoft-branded page in the middle of your carefully designed onboarding. The user types their email and a passcode into native text fields you control, and the SDK talks to the token endpoint. That’s the whole pitch: your brand, your UX, no redirect.

And keep the two OTP roles straight, because the blog is careful about this and you should be too:

  • First-factor email OTP — passwordless primary auth. The code is the credential. Already shipped separately.
  • Second-factor email/SMS OTP — the code comes after a password or a social login, as a step-up. This is what just went GA.

So the GA is specifically about adding a second factor to native flows. Now the head-to-head.

Embedded native MFA vs. browser-delegated MFA

Your two realistic options for stepping up a customer in a native app are: keep everything embedded with Native Authentication, or kick the MFA challenge out to the system browser (the classic MSAL delegated flow) and come back with a token. Six rounds.

Round 1 — User experience

Not close. Embedded native MFA keeps the user inside your app, in your fonts, with no jarring “you are now leaving” moment. Browser-delegated flows drop a Microsoft page into the middle of your funnel and pray the user doesn’t bail. For consumer apps where every extra tap costs conversions, the embedded flow is the reason this feature exists. Native wins.

Round 2 — Phishing resistance

Also not close, in the other direction. SMS and email OTP are shared-secret codes travelling over channels you don’t control. SIM-swap, SS7 interception, a compromised mailbox, or a real-time phishing proxy that relays the code — all defeat them. Embedding the code entry in a slicker UI does nothing for this; arguably it trains users that typing a texted code into an app screen is normal, which is exactly the muscle memory attackers exploit. Browser-delegated flows at least can reach passkeys and platform authenticators. Browser wins, decisively.

Round 3 — Engineering cost

Browser-delegated is less code: you call MSAL, it opens the browser, you get a token, the MFA logic lives server-side and you inherit whatever methods the tenant supports. Native Authentication means you own the screens, the error states, the resend-code timers, the “wrong code” copy, and every edge case in between. More control, more surface area, more of your bugs. Browser wins.

Round 4 — Method breadth and future-proofing

Here’s the quiet catch. Native Authentication supports a deliberately narrow set of methods — email and SMS OTP for second factor at GA. The browser-delegated path gets the full External ID method set as Microsoft ships it, including the phishing-resistant options you’ll want later. If you build everything native today, adding a stronger factor tomorrow may mean waiting for the SDK to catch up. Browser wins on headroom.

Round 5 — Cost and operational drag

SMS is not free and never was. External ID bills on monthly active users — the first tranche is free, then per-MAU — but SMS OTP carries telephony charges on top, per message, and those scale with your login volume and your fraudsters. “SMS pumping” — bots hammering your send-code endpoint to farm carrier payouts — is a real line item, not a hypothetical. Email OTP dodges the telephony bill. Browser-delegated flows that steer users to passkeys dodge both. Browser edges it, and email-only native is a respectable second. Verify current MAU tiers and per-message rates on the Entra External ID pricing page before you model this.

Round 6 — Rollback and blast radius

When a native flow misbehaves, the fix ships through the app stores — Apple’s review queue does not care about your incident. A server-side policy change in a browser-delegated flow takes effect for everyone on the next sign-in with no client update. If you need to disable a broken method at 2 a.m., the browser flow is the one you can actually turn off. Browser wins.

Score: browser-delegated 5, native embedded 1. Which looks damning until you remember what the one round was.

The verdict, and the case for the loser

On security, cost, maintainability and rollback, browser-delegated MFA is the safer default and I’d reach for it first. But it loses the single round that made anyone build a native app in the first place: the experience. If your product is a consumer app where onboarding friction directly moves revenue, and a browser redirect measurably costs you sign-ups, Native Authentication with a second factor is now a legitimate, supported choice rather than a preview gamble.

So the honest recommendation is a split: use Native Authentication for the UX, but make email OTP or a phishing-resistant factor your default and treat SMS as the fallback you tolerate, not the front door. GA changes the support posture. It does not change the threat model of a texted six-digit code.

Turning it on

All of this is configured against an external tenant, so switch tenants in the Entra admin center first — doing this against your workforce tenant will, correctly, get you nowhere.

  1. In the Entra admin center, switch to your external tenant.
  2. Enable Native Authentication on the app registration for your mobile/desktop client (it’s a per-app setting, off by default).
  3. Under External Identities → User flows, attach the flow to the app and set the MFA requirement.
  4. Confirm Email OTP and SMS are enabled in the tenant’s authentication methods policy.

The exact menu labels shift between admin-center revisions, so trust the live blade over any screenshot — including this list. Before you flip MFA to required for real users, read the current tenant config so you know what you’re changing. Read first, decide, then change:

audit.ps1PowerShell
# Requires: Microsoft.Graph
# Inspect the external tenant's authentication methods policy BEFORE changing anything.
Connect-MgGraph -Scopes "Policy.Read.All" -TenantId "<your-external-tenant-id>"
​
try {
    $policy = Get-MgPolicyAuthenticationMethodPolicy -ErrorAction Stop
​
    # authenticationMethodConfigurations is a small collection, but page defensively.
    $configs = @()
    $configs += $policy.AuthenticationMethodConfigurations
    while ($policy.'[email protected]') {
        $page = Invoke-MgGraphRequest -Method GET `
            -Uri $policy.'[email protected]'
        $configs += $page.value
    }
​
    $configs |
        Where-Object { $_.Id -in @('Email','Sms') } |
        Select-Object Id, State |
        Format-Table -AutoSize
}
catch {
    Write-Error "Failed to read authentication methods policy: $($_.Exception.Message)"
}
finally {
    Disconnect-MgGraph | Out-Null
}

When you’re ready to change state, do it from a reviewed variable — never straight off a live query — and dry-run it first. Confirm the exact Graph resource for your tenant against Microsoft’s current docs before running; the method IDs and update shape are versioned:

audit.ps1PowerShell
# Dry-run by default. Review $target, then re-run with -WhatIf:$false to apply.
[CmdletBinding(SupportsShouldProcess)]
param()
​
$target = 'Sms'   # reviewed, deliberate — not piped from a bulk query
​
if ($PSCmdlet.ShouldProcess("External ID auth method '$target'", "Enable")) {
    try {
        Update-MgPolicyAuthenticationMethodPolicyAuthenticationMethodConfiguration `
            -AuthenticationMethodConfigurationId $target `
            -BodyParameter @{ state = 'enabled' } `
            -ErrorAction Stop
        Write-Host "Enabled '$target'."
    }
    catch {
        Write-Error "Update failed for '$target': $($_.Exception.Message)"
    }
}

On the client side, the SDKs are the iOS, Android and .NET/MAUI native-auth libraries Microsoft already ships for External ID — check the sample repos for the exact package versions rather than trusting a number in a blog post, this one included.

GA is the right call and the feature deserved it. Just don’t let “production-supported” quietly upgrade in your head to “secure.” A texted code with an SLA is still a texted code.