Display all Auth0 Users in production token in ASP.NET 5 MVC

Hi I am attempting to migrate my Management API Access Token from testing to production so I don’t have to manually refresh it in the dashboard anymore. While doing that I am also attempting to display all the Auth0 users in my ASP.NET client application from my Auth0 profile that the app is connected to.

Does anyone know how to do that with C# with the Management API SDK please? I’m using this document and it is showing me only how to connect the application using RestSharp. That doesn’t contain the methods I need to get all the Auth0 users. Get Management API Access Tokens for Production

Here is my code. The code that is commented out in UsersController.GetAllAuth0Users() is the one I used for Testing. The other block just below it is for Production. That is where my problem is.

UserController.cs

using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Pitcher.Data;
using Pitcher.Models;
using System.Security.Claims;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Auth0.ManagementApi;
using RestSharp;
using System.Net.Http;

namespace Pitcher.Controllers
{
    
    public class UsersController : Controller
    {        
        private readonly TeamContext _context;

        public UsersController(TeamContext context)
        {
            _context = context;
        }

        public async Task Login(string returnUrl = "/")
        {
            await HttpContext.ChallengeAsync("Auth0", new AuthenticationProperties() {RedirectUri = returnUrl});
        }

        [Authorize]
        public async Task Logout()
        {
            await HttpContext.SignOutAsync("Auth0", new AuthenticationProperties
            {
                // Indicate here where Auth0 should redirect the user after a logout.
                // Note that the resulting absolute Uri must be whitelisted in the
                // **Allowed Logout URLs** settings for the app.
                RedirectUri = Url.Action("Index", "Home")
            });
            await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
        }

        /// <summary>
        /// This is just a helper action to enable you to easily see all claims related to a user. It helps when debugging your
        /// application to see the in claims populated from the Auth0 ID Token
        /// </summary>
        /// <returns></returns>
        [Authorize]
        public IActionResult Claims()
        {
            return View();
        }

        public async Task <IActionResult> GetAllAuth0Users()
        {
            //TESTING
            // var apiClient = new ManagementApiClient(Pitcher.Models.ConstantStrings.strToken, new Uri ("https://dev-dgdfgfdgf324.au.auth0.com/api/v2/"));
            // var allUsers = await apiClient.Users.GetAllAsync(new Auth0.ManagementApi.Models.GetUsersRequest(), new Auth0.ManagementApi.Paging.PaginationInfo());
            // var renderedUsers = allUsers.Select(u => new User
            // {                
            //     UserFirstName = u.FullName.Contains(' ') ? u.FullName.Split(' ')[0] : "no space",
            //     UserLastName = u.FullName.Contains(' ') ? u.FullName.Split(' ')[1] : "no space",
            //     UserContactEmail = u.Email
            // }).ToList();
            // return Json(renderedUsers);
            
            // PRODUCTION
            var apiClient = new ManagementApiClient(Pitcher.Models.ConstantStrings.strToken, new Uri ("https://dev-dgdfgfdgf324.au.auth0.com/oauth/token"));
            var allUsers = await apiClient.Users.GetAllAsync(new Auth0.ManagementApi.Models.GetUsersRequest(), new Auth0.ManagementApi.Paging.PaginationInfo());
            var renderedUsers = allUsers.Select(u => new User
            {                
                UserFirstName = u.FullName.Contains(' ') ? u.FullName.Split(' ')[0] : "no space",
                UserLastName = u.FullName.Contains(' ') ? u.FullName.Split(' ')[1] : "no space",
                UserContactEmail = u.Email
            }).ToList();            
            return Json(renderedUsers);
        }

        // GET: Users/Create
        public IActionResult Create()
        {
            return View();
        }

        // POST: Users/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        // COPY AND PASTE THIS METHOD CUSTOMIZATION INTO OTHER CONTROLLERS.  
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Create([Bind("UserLastName,UserFirstName,UserIsLeader,UserContactEmail,UserPhoneNumber,UserAddress,UserPostCode,UserCountry,UserMobileNumber,UserState,UserLogInName,UserPassword")] User user)
        {
            try
            {
                if (ModelState.IsValid)
                {
                    _context.Add(user);
                    await _context.SaveChangesAsync();
                    return RedirectToAction(nameof(Index));
                }
            }
            catch(DbUpdateException /* ex */)
            {
                //Log the error (uncomment ex variable name and write a log.
                ModelState.AddModelError("", "Unable to save changes. " +
                    "Try again, and if the problem persists " +
                    "see your system administrator.");
            }

            return View(user);
        }
	}
}

User.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Pitcher.Models;
namespace Pitcher.Models
{
    public class User
    {      
        public int ID { get; set; }

        [Required]
        [StringLength(20, MinimumLength = 2, ErrorMessage = "* First Name be bettween 2 to 20 characters.")]
        [DataType(DataType.Text)]
        [Display(Name = "First Name")]
        [Column("UserFirstName")]
        public string UserFirstName { get; set; }   

        [Required]
        [StringLength(30, MinimumLength = 2, ErrorMessage = "* Last Name be bettween 2 to 30 characters.")]
        [DataType(DataType.Text)]
        [Display(Name = "Last Name")]
        [Column("UserLastName")]
        public string UserLastName { get; set; }        
                
        [Required]
        [StringLength(30, MinimumLength = 3, ErrorMessage = "Email address must be bettween 3 to 30 characters.")]
        [DataType(DataType.EmailAddress)]
        [Display(Name = "Email")]
        [Column("UserContactEmail")]
        public string UserContactEmail{get;set;}      
        
        // [Required(AllowEmptyStrings = true)]
        [Display(Name = "Phone Number")]
        [Phone()]
        [Column("UserPhoneNumber")]
        public string UserPhoneNumber{get;set;}
        
        [StringLength(37,ErrorMessage = "Address cannot be longer than 37 characters.")]
        [DataType(DataType.Text)]
        [Display(Name = "Address")]
        [Column("UserAddress")]
        public string UserAddress{get;set;}
        
        //This regular expression allows valid postcodes and not just USA Zip codes.        
        [Display(Name = "Post Code")]
        [Column("UserPostCode")][DataType(DataType.PostalCode)]
        public string UserPostCode { get; set; }

        [StringLength(15,ErrorMessage = "Country cannot be longer than 15 characters.")]
        [DataType(DataType.Text)]
        [Display(Name = "Country")]
        [Column("UserCountry")] 
        public string UserCountry {get;set;}
        
        
        [Phone()]
        [Display(Name = "Mobile Number")]
        [Column("UserMobileNumber")]
        public string UserMobileNumber {get;set;}

        [StringLength(3,ErrorMessage = "State cannot be longer than 3 characters.")]
        [DataType(DataType.Text)]
        [Display(Name = "State")]
        [Column("UserState")]
        public string UserState {get;set;}           
        
        public string UserFullname => string.Format("{0} {1}", UserFirstName, UserLastName);

        public ICollection<Registration> Registrations {get;set;}
    }
}

Create.cshtml

@model Pitcher.Models.User
@{
    ViewData["Title"] = "Create";
}
<h1>Auth0 Users</h1>
<p>Please select Auth0 user from table and enter any additional information into database.</p>
<table id ="auth0UsersTable" style="width: 200px;">
        <thead>
        <tr>
            <th>
               First name
            </th>
            <th>
                Last name
            </th>   
            <th>
                Email
            </th>    
            <th>                
            </th> 
        </tr>        
        </thead>
        <tbody></tbody>
</table>
<h4>Create New User</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>            
            <div class="form-group">
                <label asp-for="UserFirstName" class="control-label"></label>
                <input id="UFirstNameInput" readonly="true" disabled="true" asp-for="UserFirstName" class="form-control"/>
                <span asp-validation-for="UserFirstName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="UserLastName" class="control-label"></label>
                <input id="ULastNameInput" readonly="true" disabled="true" asp-for="UserLastName" class="form-control"/>
                <span asp-validation-for="UserLastName" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="UserContactEmail" class="control-label"></label>
                <input id="UEmailInput" readonly="true" disabled="true" asp-for="UserContactEmail" class="form-control"/>
                <span asp-validation-for="UserContactEmail" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="UserPhoneNumber" class="control-label"></label>
                <input asp-for="UserPhoneNumber" class="form-control" />
                <span asp-validation-for="UserPhoneNumber" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="UserAddress" class="control-label"></label>
                <input asp-for="UserAddress" class="form-control" />
                <span asp-validation-for="UserAddress" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="UserPostCode" class="control-label"></label>
                <input asp-for="UserPostCode" class="form-control" />
                <span asp-validation-for="UserPostCode" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="UserCountry" class="control-label"></label>
                <input asp-for="UserCountry" class="form-control" />
                <span asp-validation-for="UserCountry" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="UserMobileNumber" class="control-label"></label>
                <input asp-for="UserMobileNumber" class="form-control" />
                <span asp-validation-for="UserMobileNumber" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="UserState" class="control-label"></label>
                <input asp-for="UserState" class="form-control" />
                <span asp-validation-for="UserState" class="text-danger"></span>
            </div>
            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-action="Index">Back to List</a>
</div>

@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
    <script>
            $.fn.dataTable.ext.errMode = 'throw';
            var Auth0Table = $('#auth0UsersTable').DataTable({
                    "ajax": {
                    'type': 'get',
                    'dataType': "json",                  
                    "url": "@Url.Action("GetAllAuth0Users")",
                    "dataSrc": function (result) {
                        return result;
                        }
                    },            
                    "columns": [                
                    { "data": "userFirstName"},
                    { "data": "userLastName"},
                    { "data": "userContactEmail"}
                    ]
            });

        
        $('#auth0UsersTable').on( 'click', 'tbody tr', function DisplaySelectedRowItems() {            
            //IF table row you click on is already selected. 
            if ( $(this).hasClass('selected') ) {
                //deselect the row you already selected.
                $(this).removeClass('selected');
            }
            else {
                //Search all visible rows and deselect them.  
                Auth0Table.$('tr.selected').removeClass('selected');
                //Select new row you clicked.
                $(this).addClass('selected');

                //Get ID of table and some property.
                var table = document.querySelector('#auth0UsersTable');
                var firstName = document.querySelector('#UFirstNameInput');
                var lastName = document.querySelector('#ULastNameInput');
                var email = document.querySelector('#UEmailInput');        
                
                //Add listener for table click event.
                table.addEventListener('click', onTableClick);  

                //Get click of Table.
                function onTableClick (e) 
                {
                    var tr = e.target.parentElement;        
                    var data = [];
                    
                    for (var td of tr.children) 
                    {
                        data.push(td.innerHTML);
                    }
                
                    firstName.value = data[0];
                    lastName.value = data[1];
                    email.value = data[2];
                }
            }        
        });
    </script>
}

The RestSharp code shows you how to get an access token for the management API. In your example, that token is hardcoded in a constant. You should first get the token with that restsharp sample or the equivalent one using httpclient, and then pass it in the constructor of the Management APi client instead of the constant.

I am using a constant class because the token string is very long and will freeze up the computer if I render it to screen which is why I am referencing it from another class. Does that sound reasonable?