native-title

TL;DR

With Azure AD B2C we can authenticate users via a browser-based feature - we run the OpenID Connect flow in the browser, authenticate the user via the Authorization Code flow, and get the token.

But what if we want to stay with the mobile application? On the Desktop application? With Entra External ID we can use the native authentication flow.

PS> Native Authentication is in preview mode - it is not for production use!

DEMO

Sign-UP via Web: https://portal.factorlabs.pl/external-id/ and Sign-In via: https://customer.factorlabs.pl

Solution Overview

The Native Auth API lacks CORS, so I needed to use a Proxy API to make a demo with the web application. The proxy API is stateless; the response is returned to the client’s browser. This is only a DEMO and sample. Please consider using a secure way to store the ContinuationToken (Secure and HttpOnly Cookie?).

Today, Entra External ID does not support MFA for ‘CIAM’ users. With the MFA, there will be an additional step in the flow (maybe an extra API call?) - we will see in the future.

Code Snippets

Initialize the flow - share username (email address) to start the flow:

private string _clientId = "71e0abe3-1111-2222-5555-acf032d43284";
private string _tenantNativeUrl = "https://my-tenant.ciamlogin.com/my-tenant.onmicrosoft.com";

var values = new Dictionary<string, string>
{
    { "client_id", _clientId },
    { "challenge_type", "oob redirect" },
    { "username", model.Username }
};

var content = new FormUrlEncodedContent(values);
var response = await _httpClient.PostAsync(
    $"{_tenantNativeUrl}/oauth2/v2.0/initiate",
    content);

As a result, we get the continuationToken. We will use it with the next REST Call to get the code.

Next API request is with challenge_type: oob - so we want to authenticate the user with OTP (One Time Password). In my opinion in a world, where we can log everything and everywhere, Terminating SSL traffic - is important to use a ’temporary’ password, is safer than sharing the password.

var values = new Dictionary<string, string>
{
    { "client_id", _clientId },
    { "challenge_type", $"oob redirect" },
    { "continuation_token", model.ContinuationToken }
};

var content = new FormUrlEncodedContent(values);
var response = await _httpClient.PostAsync(
    $"{_tenantNativeUrl}/oauth2/v2.0/challenge",
    content);

We are asking for Scope openid with the grant_type: oob. User needs to provide the OTP to get the token.

var values = new Dictionary<string, string>
{
        { "client_id", _clientId },
        { "continuation_token", model.ContinuationToken },
        {"scope", "openid"},
        {"grant_type", "oob"},
        {"oob", model.Password}
};
var content = new FormUrlEncodedContent(values);
var response = await _httpClient.PostAsync(
$"{_tenantNativeUrl}/oauth2/v2.0/token",
content);

A summary:

  • The context is client-id - so we run the flow for the application.
  • Enable the Native Authentication for your application.
  • Register User flow with OTP, use with the test user created with OTP (not password!) - the feature is in preview mode - so maybe some changes will be provided in the future.
  • FormUrlEncoded POST requests.
  • ContinuationToken is a key to the next step.
  • Needed to use Proxy API - Entra External ID is without CORS methods.
  • I decided to build a web application to test it. Feel free to run a test: Sign-UP via Web: https://portal.factorlabs.pl/external-id/ and https://customer.factorlabs.pl for Native Auth.
  • MS Documentation

What next?

My plan is to test SDK for Android and your?