The Azure Gateway Provisioner is a browser-based wizard that creates a complete Azure API proxy infrastructure for the Auvik network monitoring platform — without requiring the Azure CLI, PowerShell, Bicep, or Terraform. An engineer opens the HTML file, signs in with their Microsoft account, fills out a configuration form, and clicks Provision. The tool then calls the Azure Resource Manager API directly from the browser to deploy seven Azure resources in sequence.
The end result is a secure Azure Function App that sits between your MSP dashboards and the Auvik API. Auvik credentials never appear in browser code after provisioning — they are stored encrypted in Azure Key Vault and injected server-side on every request.
The provisioner creates a three-layer security architecture. The browser never touches the Auvik API directly after provisioning. Every request flows through the Function App, which reads credentials from Key Vault at runtime using its Managed Identity.
| LAYER | COMPONENT | ROLE | CREDENTIAL EXPOSURE |
|---|---|---|---|
| Client | Browser / Dashboard HTML | Calls Function App proxy endpoint | None — no credentials in client code |
| Proxy | Azure Function App | Receives requests, injects Auvik auth header, forwards to Auvik API | Credentials read from Key Vault — never in code |
| Secrets | Azure Key Vault | Stores Auvik username and API key encrypted at rest | Only accessible to Function App Managed Identity |
| Backend | Auvik API | Actual network data source | — |
rg-cyberadvisers-proxy. All resources below are created inside this group, making teardown a single delete operation.stcyberadvisers. Stores Function App files and the AzureWebJobs runtime state.kv-cyberadvisers. Holds two secrets: auvik-api-user and auvik-api-key. Configured with standard SKU and access policies for both the provisioning user and the Function App identity.{funcapp-name}-plan. Scales automatically with request volume.{funcapp-name}.azurewebsites.net. App settings include KV references so credentials are never stored as plaintext.The provisioner uses MSAL.js v2 (Microsoft Authentication Library) running entirely in the browser. When you click Sign In, a Microsoft popup opens — your credentials go directly to Microsoft's login servers, never through this page. On success, MSAL returns an access token scoped to management.azure.com/user_impersonation, which the provisioner uses to make ARM API calls on your behalf.
For Key Vault secret storage (Step 5), the provisioner acquires a separate token scoped to vault.azure.net/user_impersonation and calls the Key Vault Data Plane API directly. Tokens are acquired silently when possible and via popup when a fresh login is required.
The most important security mechanism is how the Function App reads credentials. Rather than storing the actual Auvik username and key in app settings (where they appear as plaintext in the Azure Portal), the provisioner stores Key Vault references — special strings that tell Azure to retrieve the secret from Key Vault at runtime.
APP SETTING VALUE IN THE FUNCTION APP (NOT THE ACTUAL SECRET)Azure resolves these references automatically using the Function App's Managed Identity. The actual secret values never appear in the portal, in logs, or in any ARM API response.
The ALLOWED_ORIGIN app setting on the Function App controls which origins can call the proxy. During initial provisioning you can leave this blank (*) for testing. Before going to production, update this to your SharePoint tenant URL. This ensures only your dashboards can use the proxy — external sites cannot make calls to it even if they discover the URL.
Before the provisioner can sign in with your Microsoft account, Azure needs to know this application exists. You register it once in Entra ID (Azure AD) and paste the resulting IDs into the form. This step takes about 3 minutes in the Azure Portal.
xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.After entering valid GUIDs for both fields and clicking Save & Continue, the provisioner initializes the MSAL instance and advances to Step 2. The step indicator turns green and shows a checkmark.
cyberadvisers-provisioner (or similar). The name is only for your reference in the Azure Portal — it has no effect on functionality.
Click Sign In with Microsoft. A Microsoft login popup opens. Sign in with a work account that has at least Contributor rights on the Azure subscription you want to provision into. Contributor is the minimum required role — Owner is needed only if you also need to assign RBAC roles, which this provisioner does not do.
On successful login the page shows your account name, email, initials badge, and a subscription dropdown populated from your Azure account. Select the target subscription and click Configure Resources to advance to Step 3.
sessionStorage — they are cleared when you close the browser tab.user_impersonation permission with admin consent granted.Step 3 is the configuration form. All fields have defaults pre-filled. Review each value before clicking Provision Gateway Server.
| FIELD | DEFAULT | CONSTRAINTS |
|---|---|---|
| Resource Group | rg-cyberadvisers-proxy | Any valid Azure resource group name. Does not need to be globally unique. |
| Location | eastus | Choose the region closest to your team. All seven resources deploy to this region. |
| Storage Account | stcyberadvisers | Globally unique. Lowercase letters and numbers only. No hyphens. 3–24 characters. Will fail with a conflict error if the name is already taken. |
| Function App Name | cyberadvisers-proxy | Globally unique. Becomes {name}.azurewebsites.net. Must be available — check at portal.azure.com if unsure. |
| Key Vault Name | kv-cyberadvisers | Globally unique. 3–24 characters. Letters, numbers, hyphens only. |
auvik-api-user secret in Key Vault. Used for Basic authentication on every proxied request.auvik-api-key secret in Key Vault. The field is masked (type="password") and the value is sent directly to Key Vault over HTTPS — it never appears in the terminal output.https://auvikapi.us1.my.auvik.com/v1. Swap us1 for your region: us1, us2, eu, or au. Check your Auvik account region in Account Settings.https://yourtenant.sharepoint.com. Leave blank during testing (allows all origins via *). Must be locked down before production — this is the CORS restriction that prevents external sites from using your proxy.Clicking Provision Gateway Server advances to Step 4 and begins the automated deployment. A real-time terminal output window shows every ARM API call, its result, and the generated resource URLs. A progress bar tracks overall completion across seven operations.
Total provisioning time is typically 3–8 minutes depending on Azure region latency and resource creation queues. The Function App creation step (Step 4/7) takes the longest — Azure provisions the consumption plan and registers the runtime before returning.
acquireToken() before each ARM operation and refreshes silently via MSAL. If the session has expired a login popup re-appears mid-run. Complete the login and the provisioning continues from where it left off on the next operation.
Step 5 confirms all resources were created successfully and shows six result cards with all generated URLs and resource names. Each value has a copy button. This is the screen to screenshot for your deployment record.
The page also shows a before/after code snippet for updating any Auvik console dashboards to use the proxy URL instead of the direct Auvik endpoint. See Section C5 for the full update process.
The Run Health Check button calls the /api/health endpoint and shows the raw JSON response. Note that this will return a 404 or connection error until the Function App code is deployed separately — the provisioner creates the Azure infrastructure but does not deploy the Node.js function code. See Section C4.
| # | RESOURCE | ARM METHOD | API VERSION | WAIT FOR COMPLETE |
|---|---|---|---|---|
| 1 | Resource Group | PUT /subscriptions/{sub}/resourcegroups/{rg} | 2022-12-01 | No |
| 2a | Storage Account | PUT .../storageAccounts/{name} | 2023-01-01 | Yes |
| 2b | Storage Keys | POST .../storageAccounts/{name}/listKeys | 2023-01-01 | — |
| 3 | Key Vault | PUT .../vaults/{name} | 2023-07-01 | Yes |
| 4a | Consumption Plan | PUT .../serverfarms/{plan} | 2023-12-01 | Yes |
| 4b | Function App | PUT .../sites/{funcapp} | 2023-12-01 | Yes |
| 5a | KV Access Policy (user) | POST .../vaults/{kv}/accessPolicies/add | 2023-07-01 | No |
| 5b | KV Secret — user | PUT https://{kv}.vault.azure.net/secrets/auvik-api-user | 7.4 (data plane) | — |
| 5c | KV Secret — key | PUT https://{kv}.vault.azure.net/secrets/auvik-api-key | 7.4 (data plane) | — |
| 6a | KV Access Policy (func) | POST .../vaults/{kv}/accessPolicies/add | 2023-07-01 | No |
| 6b | App Settings Update | PUT .../sites/{func}/config/appsettings | 2023-12-01 | No |
These are the app settings written to the Function App by the provisioner. Settings marked as KV Reference never contain the actual secret value — Azure resolves them at runtime using the Function App's Managed Identity.
| SETTING NAME | VALUE / PATTERN | PURPOSE |
|---|---|---|
FUNCTIONS_WORKER_RUNTIME | node | Tells the runtime to use Node.js |
FUNCTIONS_EXTENSION_VERSION | ~4 | Functions runtime version 4.x |
WEBSITE_NODE_DEFAULT_VERSION | ~18 | Node.js 18 LTS |
AzureWebJobsStorage | DefaultEndpointsProtocol=https;AccountName=... | Storage connection string for runtime state |
WEBSITE_CONTENTAZUREFILECONNECTIONSTRING | Same as AzureWebJobsStorage | File share for Function App code |
WEBSITE_CONTENTSHARE | {funcapp-name} | File share name |
AUVIK_API_USER | @Microsoft.KeyVault(VaultName=...;SecretName=auvik-api-user) | KV reference — actual value resolved by Managed Identity |
AUVIK_API_KEY | @Microsoft.KeyVault(VaultName=...;SecretName=auvik-api-key) | KV reference — actual value resolved by Managed Identity |
AUVIK_BASE_URL | https://auvikapi.us1.my.auvik.com/v1 | Auvik regional API base URL |
ALLOWED_ORIGIN | https://yourtenant.sharepoint.com (or *) | CORS allowed origin for proxy responses |
REQUIRE_AUTH | false | Whether incoming requests to the proxy require auth. Set to true and add auth logic in function code for production. |
| SECRET NAME | VALUE | STORED BY | READ BY |
|---|---|---|---|
auvik-api-user | Auvik account email address | Provisioner (Step 5) using provisioning user's KV token | Function App via Managed Identity at request time |
auvik-api-key | Auvik API key | Provisioner (Step 5) using provisioning user's KV token | Function App via Managed Identity at request time |
| ENDPOINT | METHOD | DESCRIPTION | AUTH REQUIRED |
|---|---|---|---|
/api/auvik | GET / POST | Main proxy endpoint. Forwards requests to Auvik API with injected Basic auth. Replace the Auvik base URL in dashboards with this endpoint. | REQUIRE_AUTH setting (default: no) |
/api/health | GET | Health check endpoint. Returns a JSON object showing KV secret resolution status and upstream Auvik reachability. Available once Function code is deployed. | No |
GET https://{funcapp}.azurewebsites.net/api/auvik/inventory/network/devicesThis is equivalent to calling the Auvik API directly but without credentials in the request. The Function App injects the Authorization header server-side.
http://localhost via a local dev server), register http://localhost as the redirect URI. When you move the file to SharePoint, add the SharePoint URL as a second redirect URI on the same app registration. MSAL will use whichever URI matches the current page.
This is done once in the Azure Portal before opening the provisioner for the first time. All steps below are in Entra ID (Azure Active Directory).
- 1Navigate to App registrations.Azure Portal → search "App registrations" → click New registration.
- 2Set the name.Use
cyberadvisers-provisioneror a name that clearly identifies the tool. This appears in your Entra ID app list. - 3Set supported account types.Select "Accounts in this organizational directory only (Single tenant)." Do not select multi-tenant unless you are provisioning across multiple Azure AD tenants.
- 4Set the redirect URI.Select type: Single-page application (SPA). Enter the URL where the provisioner HTML file will live. If testing locally:
http://localhost. If hosted on SharePoint:https://TENANT.sharepoint.com/sites/SITE/Shared%20Documents/azure-provisioner.html - 5Click Register.The app registration is created. You land on the Overview page.
- 6Copy the IDs.Copy both the Application (client) ID and the Directory (tenant) ID from the Overview page. These go into the provisioner's Step 1 form fields.
- 7Add API permission.In the app registration, go to API permissions → Add a permission → Azure Service Management → Delegated permissions → select user_impersonation → Add permissions.
- 8Grant admin consent.Still on the API permissions page, click "Grant admin consent for [your organization]" and confirm. The permission status changes to a green checkmark. Without this step the login popup will show a consent screen on every sign-in.
The provisioner is a single self-contained HTML file with one CDN dependency (MSAL.js from Cloudflare CDN). Deploy it anywhere that serves HTML over HTTPS.
npx serve . or python -m http.server from the file's directory. Open http://localhost:PORT/azure-provisioner.html. Register http://localhost as the redirect URI in the app registration. MSAL will use the current page URL automatically.file:///C:/azure-provisioner.html) will cause MSAL to fail. The redirect URI validation in Azure requires an HTTP/HTTPS origin — file:// is not a valid origin. You must use a local server even for local testing.
The provisioner creates the Azure infrastructure but does not deploy the Node.js function code. The Function App is live in Azure but will return a 404 on all routes until you push code to it. You need the Azure Functions Core Tools installed locally.
- 1Install Azure Functions Core Tools.
npm install -g azure-functions-core-tools@4 --unsafe-perm - 2Create your function project locally.
func init my-proxy --worker-runtime node --language javascript - 3Create the proxy function.
func new --name auvik --template "HTTP trigger". Then write the proxy logic: readAUVIK_BASE_URL,AUVIK_API_USER,AUVIK_API_KEYfrom process.env, build the Basic auth header, forward the request, and return the response. Add CORS headers using theALLOWED_ORIGINenv var. - 4Create the health function.
func new --name health --template "HTTP trigger". Return a JSON object showing KV secret resolution status (check that env vars are non-empty) and an Auvik API ping result. - 5Sign in to Azure CLI.
az loginandaz account set --subscription {your-subscription-id} - 6Publish to the Function App.
func azure functionapp publish {your-funcapp-name}. This deploys the code to the Function App created by the provisioner. After a minute the proxy endpoint will respond to requests.
AUVIK_API_USER and AUVIK_API_KEY env vars are KV references. They only resolve if the Function App's System Assigned Managed Identity is enabled and has the Key Vault Secrets User (or get secrets) access policy set — both of which the provisioner configures automatically. If process.env values appear as the raw @Microsoft.KeyVault(...) string rather than the actual secret, check Azure Portal → Function App → Identity → System assigned is On.
Once the Function App is live and the health check passes, update any Auvik console HTML pages that call the Auvik API directly. The change is minimal — swap the base URL and remove the Authorization header.
BEFORE — DIRECT AUVIK CALL (CREDENTIALS IN BROWSER)The proxy endpoint mirrors the Auvik API path structure. Any call that previously went to https://auvikapi.us1.my.auvik.com/v1/inventory/network/devices now goes to https://{funcapp}.azurewebsites.net/api/auvik/inventory/network/devices. Path, query parameters, and response format are identical.
ALLOWED_ORIGIN app setting on the Function App from * to your SharePoint tenant URL. In Azure Portal → Function App → Configuration → Application Settings → find ALLOWED_ORIGIN → edit → save. The Function App restarts automatically. Without this, any website that discovers your proxy URL can use it.
- ✓Step 1 completes with green checkmark. If you see "MSAL init error", the Tenant ID or Client ID is wrong — verify both GUIDs in the Azure Portal app registration Overview page.
- ✓Sign-in popup opens and returns to the page. If the popup opens but the page doesn't update, the redirect URI in the app registration doesn't match the current page URL. Update Authentication → Redirect URIs in the app registration to match exactly.
- ✓Subscription dropdown populates. If it stays empty, the ARM token didn't include the right scope. Verify the app registration has Azure Service Management → user_impersonation with admin consent granted.
- ✓Terminal reaches 100% with all ✓ green lines. Any red error line means a provisioning step failed. Read the error body — it contains the ARM error code and message.
- ✓Resource Group appears in Azure Portal. Go to portal.azure.com → Resource groups → search for your RG name. All five resources (storage, key vault, consumption plan, function app, and function app plan) should be inside it.
- ✓Key Vault secrets exist. Azure Portal → Key Vault → Secrets → confirm
auvik-api-userandauvik-api-keyare present and show as Enabled. - ✓Function App Managed Identity is On. Azure Portal → Function App → Identity → System assigned → Status shows On. If Off, the KV references will not resolve and the proxy will fail to read credentials.
- ✓Health check returns JSON after function code deploy. Click Run Health Check in Step 5. Should return a JSON object. A 404 means code hasn't been deployed yet. A 500 with "KeyVault" in the message means the access policy wasn't applied — check that the Function App's principalId has get-secrets permission on the vault.
| SYMPTOM | LIKELY CAUSE | FIX |
|---|---|---|
| redirect_uri_mismatch error on login | Redirect URI in app registration doesn't match page URL | Copy the URL shown at the bottom of Step 1 exactly. Add it to app reg → Authentication → Single-page application URIs. |
| ARM 403 on resource creation | Signed-in account lacks Contributor on the subscription | Azure Portal → Subscriptions → Access control (IAM) → add Contributor role for the account. |
| Storage account name conflict | Default name already taken globally | Change the storage account name in Step 3 — add a random suffix like stcyberadvisers4829. |
| KV secrets stored but app reads raw KV reference string | Managed Identity is Off, or KV access policy wasn't applied for principalId | Check Function App → Identity (must be On). Check Key Vault → Access policies — Function App identity must have Get on secrets. |
| Health check 404 after deployment | Function code not deployed yet | Run func azure functionapp publish {funcapp-name} from your local function project directory. |
| CORS error calling proxy from SharePoint | ALLOWED_ORIGIN is * but browser blocks mixed content, or origin mismatch | Set ALLOWED_ORIGIN to your exact SharePoint tenant URL in Function App → Configuration → Application Settings. |
| Popup blocked during sign-in | Browser popup blocker or enterprise proxy | Allow popups for the page URL. MSAL requires popup support — it cannot fall back to redirect mode without code changes. |
| Provision error on cleanup re-run | Previous partially-created resources conflict | Delete the resource group entirely in the Azure Portal (this removes all seven resources), then re-run the provisioner from Step 3. |