Created
March 31, 2025 02:52
-
-
Save rbrayb/adae315bc2465c04cfc014605e938239 to your computer and use it in GitHub Desktop.
Using Azure AD B2C custom policies to implement Profile Edit on Entra External ID with Native auth
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
if (method == "auth") | |
{ | |
Console.WriteLine("\n" + "Authenticating user"); | |
using (var httpClient = new HttpClient()) | |
{ | |
// Add Host header | |
httpClient.DefaultRequestHeaders.Host = "externaltenant.ciamlogin.com"; | |
// Step 1: Initiate | |
var initiateUrl = "https://externaltenant.ciamlogin.com/externaltenant.onmicrosoft.com/oauth2/v2.0/initiate"; | |
var initiateRequestBody = new Dictionary<string, string> | |
{ | |
// TODO | |
{ "client_id", "your client ID" }, | |
{ "challenge_type", "password redirect" }, | |
{ "username", email } | |
}; | |
var initiateContent = new FormUrlEncodedContent(initiateRequestBody); | |
Console.WriteLine("\n" + "Initiate URL: " + initiateUrl); | |
Console.WriteLine("\n" + "Initiate Request Body: " + JsonConvert.SerializeObject(initiateRequestBody)); | |
var initiateResponse = await httpClient.PostAsync(initiateUrl, initiateContent); | |
var initiateResponseContent = await initiateResponse.Content.ReadAsStringAsync(); | |
Console.WriteLine("\n" + "Initiate Response Status Code: " + initiateResponse.StatusCode); | |
Console.WriteLine("\n" + "Initiate Response Content: " + initiateResponseContent); | |
if (!initiateResponse.IsSuccessStatusCode) | |
{ | |
return new ConflictObjectResult(new B2CResponseModel($"Failed to initiate authentication. Response: {initiateResponseContent}", HttpStatusCode.Conflict)); | |
} | |
var initiateJson = JsonConvert.DeserializeObject<JObject>(initiateResponseContent); | |
var continuationToken = initiateJson["continuation_token"].ToString(); | |
// Step 2: Challenge | |
var challengeUrl = "https://externaltenant.ciamlogin.com/externaltenant.onmicrosoft.com/oauth2/v2.0/challenge"; | |
var challengeRequestBody = new Dictionary<string, string> | |
{ | |
// TODO | |
{ "client_id", "your client ID" }, | |
{ "challenge_type", "password redirect" }, | |
{ "continuation_token", continuationToken } | |
}; | |
var challengeContent = new FormUrlEncodedContent(challengeRequestBody); | |
var challengeResponse = await httpClient.PostAsync(challengeUrl, challengeContent); | |
if (!challengeResponse.IsSuccessStatusCode) | |
{ | |
return new ConflictObjectResult(new B2CResponseModel($"Failed to complete challenge.", HttpStatusCode.Conflict)); | |
} | |
var challengeResponseContent = await challengeResponse.Content.ReadAsStringAsync(); | |
var challengeJson = JsonConvert.DeserializeObject<JObject>(challengeResponseContent); | |
continuationToken = challengeJson["continuation_token"].ToString(); | |
// Step 3: Token | |
var tokenUrl = "https://externaltenant.ciamlogin.com/externaltenant.onmicrosoft.com/oauth2/v2.0/token"; | |
var tokenRequestBody = new Dictionary<string, string> | |
{ | |
// TODO | |
{ "client_id", "your client ID" }, | |
{ "password", password }, | |
{ "continuation_token", continuationToken }, | |
{ "grant_type", "password" }, | |
{ "scope", "openid offline_access" } | |
}; | |
var tokenContent = new FormUrlEncodedContent(tokenRequestBody); | |
var tokenResponse = await httpClient.PostAsync(tokenUrl, tokenContent); | |
if (!tokenResponse.IsSuccessStatusCode) | |
{ | |
return new ConflictObjectResult(new B2CResponseModel($"Failed to obtain token.", HttpStatusCode.Conflict)); | |
} | |
// Read the response content | |
var responseContent = await tokenResponse.Content.ReadAsStringAsync(); | |
var jsonObj = JsonConvert.DeserializeObject(responseContent); | |
Console.WriteLine("\n" + "jsonObject " + jsonObj.ToString()); | |
return new OkObjectResult(jsonObj); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://medium.com/the-new-control-plane/using-azure-ad-b2c-custom-policies-to-implement-profile-edit-on-entra-external-id-with-native-auth-1a2587bda05d