public static async Task <IActionResult> AddAuthorizationClaims(
            [HttpTrigger(AuthorizationLevel.Function, WebRequestMethods.Http.Post)] HttpRequest request,
            ILogger log)
        {
            try
            {
                log.LogInformation("Authorization claims are being requested.");

                // Parse and log the incoming request.
                var requestDocument = await ApiConnectorHelper.GetRequestJsonAsync(request, log);

                var step     = requestDocument.RootElement.GetProperty("step").GetString();
                var objectId = requestDocument.RootElement.GetProperty("objectId").GetString();
                var clientId = requestDocument.RootElement.GetProperty("client_id").GetString();

                // Retrieve the app roles assigned to the user for the requested client application.
                var appRoles = await GetAppRolesAsync(objectId, clientId);

                // Custom user attributes cannot be arrays, so we emit them into a single claim value
                // separated with spaces (Azure AD App Roles cannot contain spaces).
                var appRolesValue = string.Join(' ', appRoles);

                return(ApiConnectorHelper.GetContinueApiResponse("AddAuthorizationClaims-Succeeded", "Success", null, appRolesValue));
            }
            catch (Exception exc)
            {
                log.LogError(exc, "Error while processing request body: " + exc.ToString());
                return(ApiConnectorHelper.GetBlockPageApiResponse("AddAuthorizationClaims-InternalError", "An error occurred while validating your invitation code, please try again later."));
            }
        }
        public static async Task <IActionResult> Debug(
            [HttpTrigger(AuthorizationLevel.Function, WebRequestMethods.Http.Post)] HttpRequest request,
            ILogger log)
        {
            try
            {
                log.LogInformation("A debug request was received.");

                // Parse and log the incoming request.
                await ApiConnectorHelper.GetRequestJsonAsync(request, log);

                // Return a "Continue" API response without modifying any of the claims.
                return(ApiConnectorHelper.GetContinueApiResponse("Debug-Succeeded", "Success"));
            }
            catch (Exception exc)
            {
                log.LogError(exc, "Error while processing request body: " + exc.ToString());
                return(ApiConnectorHelper.GetBlockPageApiResponse("Debug-InternalError", "An error occurred while validating your invitation code, please try again later."));
            }
        }
        public static async Task <IActionResult> RedeemInvitationCode(
            [HttpTrigger(AuthorizationLevel.Function, WebRequestMethods.Http.Post)] HttpRequest request,
            IBinder binder,
            ILogger log)
        {
            // Azure AD B2C calls into this API when a user is attempting to sign up with an invitation code.
            // We expect a JSON object in the HTTP request which contains the input claims as well as an additional
            // property "ui_locales" containing the locale being used in the user journey (browser flow).
            try
            {
                log.LogInformation("An invitation code is being redeemed.");

                // Parse and log the incoming request.
                var requestDocument = await ApiConnectorHelper.GetRequestJsonAsync(request, log);

                // Look up the invitation code in the incoming request. The element name depends on the
                // extension App ID (e.g. "extension_bd88c9da63214d09b854af9cfbbf4b15_InvitationCode")
                // so to avoid hard-coding this or making it configurable, we just check if the element
                // name ends with the custom attribute name.
                var invitationCode = default(string);
                foreach (var element in requestDocument.RootElement.EnumerateObject())
                {
                    if (element.Name.EndsWith("InvitationCode", StringComparison.InvariantCultureIgnoreCase)) // E.g. "extension_bd88c9da63214d09b854af9cfbbf4b15_InvitationCode"
                    {
                        invitationCode = element.Value.GetString();
                    }
                }

                if (string.IsNullOrWhiteSpace(invitationCode) || invitationCode.Length < 10)
                {
                    // No invitation code was found in the request or it was too short, return a validation error.
                    log.LogInformation($"The provided invitation code \"{invitationCode}\" is invalid.");
                    return(ApiConnectorHelper.GetValidationErrorApiResponse("UserInvitationRedemptionFailed-Invalid", "The invitation code you provided is invalid."));
                }
                else
                {
                    // An invitation code was found in the request, look up the user invitation in persistent storage.
                    log.LogInformation($"Looking up user invitation for invitation code \"{invitationCode}\"...");
                    var invitationCodeBlob = binder.Bind <ICloudBlob>(new BlobAttribute($"userinvitations/{invitationCode}.json", FileAccess.Read));
                    if (invitationCodeBlob == null)
                    {
                        // The requested invitation code was not found in persistent storage.
                        log.LogWarning($"User invitation for invitation code \"{invitationCode}\" was not found.");
                        return(ApiConnectorHelper.GetValidationErrorApiResponse("UserInvitationRedemptionFailed-NotFound", "The invitation code you provided is invalid."));
                    }
                    else
                    {
                        // The requested invitation code was found in persistent storage, look up the pre-identified information.
                        log.LogInformation($"User invitation found for invitation code \"{invitationCode}\".");
                        using (var invitationCodeBlobStream = await invitationCodeBlob.OpenReadAsync(null, null, null))
                        {
                            var invitationCodeRequest = await JsonSerializer.DeserializeAsync <InvitationCodeRequest>(invitationCodeBlobStream);

                            // At this point, the blob can be deleted again as it was consumed.
                            await invitationCodeBlob.DeleteAsync();

                            return(ApiConnectorHelper.GetContinueApiResponse("UserInvitationRedemptionSucceeded", "The invitation code you provided is valid.", invitationCodeRequest.CompanyId));
                        }
                    }
                }
            }
            catch (Exception exc)
            {
                log.LogError(exc, "Error while processing request body: " + exc.ToString());
                return(ApiConnectorHelper.GetBlockPageApiResponse("UserInvitationRedemptionFailed-InternalError", "An error occurred while validating your invitation code, please try again later."));
            }
        }