This post is going to be an incredibly short and sweet post covering the ability to test things like Webhooks or Azure B2C policies. If you are familiar with either, you will already know they require a generally publicly accessible service running in order to process the request. In my partuclar case, creating an invitation Policy within Azure B2C, I wanted to trigger a “Welcome” email from this policy, but really had no clue how the Claims or request headers came across. So I used what I knew: I created an Azure Function that would grab all the things of the request and email it to me.

In this case, I want a simple Http Triggered function with with Function auth level and supported GET|POST http methods. I gave it a name (WebhookPayloadEmail), dropped the below code in the run.csx and added entries for SmtpServer, SmtpUserName and SmtpPassword to the Application Settings of the Function App itself. Once done with all that, I ran it a few times locally to make sure it compiled, threw a few arbitrary values in the query, headers and request body to make sure they all got caught and once I confirmed that working, I figured we were ready to go and grabbed the Function url (</> Get function URL).

WebhookPayloadEmail Function

#r "Newtonsoft.Json"

using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;
using System.Net.Mail;

public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
{
    log.LogInformation("C# HTTP trigger function processed a request.");
    var smtpHost = GetEnvironmentVariable("SmtpServer");
    var smtpPort = 587;
    var smtpEnableSsl = true;
    var smtpUser = GetEnvironmentVariable("SmtpUserName");
    var smtpPass = GetEnvironmentVariable("SmtpPassword");
    string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
    string serializedQuery = JsonConvert.SerializeObject(req.Query);
    string seralizedHeader = JsonConvert.SerializeObject(req.Headers);

    using (var client = new SmtpClient(smtpHost, smtpPort))
    {
        client.UseDefaultCredentials = false;
        client.Credentials = new System.Net.NetworkCredential(smtpUser, smtpPass);
        client.DeliveryMethod = SmtpDeliveryMethod.Network;
        client.EnableSsl = smtpEnableSsl;
        MailMessage message = new MailMessage("from@test.test", "to@test.test");
        message.Subject = "Test Submission";
        message.IsBodyHtml = false;
        message.Body = requestBody + "\n\n" + serializedQuery + "\n\n" + seralizedHeader;
        
        try
        {
            client.Send(message);
            log.LogInformation("Success.");
            

            return (ActionResult)new OkObjectResult(
                new {
                    status = true,
                    message = string.Empty
                });
        }
        catch (Exception ex)
        {
            log.LogError("Failure: " + ex.ToString());
            return new BadRequestObjectResult(new
                {
                    status = false,
                    message = "Check Azure Function Logs for more information."
                });
        }
    }
}

public static string GetEnvironmentVariable(string name)
{
    return Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process);
}

Above is the main guts of this post but to round things out, in my Azure B2C scenario, I created a ClaimsProvider (see below) to trigger on the last OrchestrationStep of the Invitation of the invitation UserJourney:

<ClaimsProvider>
    <DisplayName>Azure Functions</DisplayName>
    <TechnicalProfiles>
        <!-- The following technical profile sends a mail message to a user. -->
        <TechnicalProfile Id="AzureFunctions-SendMailWebHook">
            <DisplayName>Send Mail Web Hook Azure Function</DisplayName>
            <Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
            <Metadata>
                <Item Key="ServiceUrl">https://yourtenant.azurewebsites.net/api/WebhookPayloadEmail?code=T4Isi2N0tAR3L1C0D3==</Item>
                <Item Key="AuthenticationType">None</Item>
                <Item Key="SendClaimsIn">Body</Item>
                <Item Key="AllowInsecureAuthInProduction">true</Item>
            </Metadata>
            <InputClaims>
                <InputClaim ClaimTypeReferenceId="objectId" />
                <!--<InputClaim ClaimTypeReferenceId="anotherValue" PartnerClaimType="claimNameInPayload" />-->
            </InputClaims>
            <UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
        </TechnicalProfile>
    </TechnicalProfiles>
</ClaimsProvider>

And there you have it, an Azure Function that could funcition as a Webhook recipient or a ServiceUrl for an Azure B2C Policy!

I realize this discusses the Azure Function more than Azure B2C, but after a little bit of headache and following this tutorial and this codebase pretty closely, I found Azure B2C to be extremely powerful for handling authentication (just in case you stumble on this page looking for help on B2C and not Azure Functions)…

</message>