Horizon

Test VMware Workspace ONE (Omnissa) webhooks locally

Receive Workspace ONE UEM event notifications on localhost with a Horizon tunnel, and check the credentials the console sends.

Receive Workspace ONE UEM event notifications on your laptop while you build, with a public HTTPS URL the console can reach. Workspace ONE is now an Omnissa product, formerly VMware.

Horizon has no Workspace ONE integration. UEM sends event notifications to a URL you choose, and Horizon provides that URL.

Workspace ONE doesn't sign webhooks

Workspace ONE UEM documents no signature header for event notifications. It documents one protection: the User Name and Password you enter on the notification rule, which Omnissa calls the basic user authentication method. The handler below checks those credentials. It is a shared secret, not a signature, so it proves the caller knows the password and nothing about the payload.

Before you begin

  • Node.js 18 or later
  • A Horizon account and the CLI (see Getting started)
  • A reserved subdomain for -s. Reserve one on the Subdomains page.
  • A Workspace ONE UEM console where you can edit system settings
  • A Next.js app that uses the App Router and runs on port 3000

Start your app

Create a route handler that compares the Authorization header with the credentials you will enter in the console. It assumes the console sends them as HTTP Basic credentials.

app/api/webhooks/workspace-one/route.ts
export async function POST(request: Request) {
  const username = process.env.WORKSPACE_ONE_USERNAME;
  const password = process.env.WORKSPACE_ONE_PASSWORD;
  if (!username || !password) {
    return new Response("Missing Workspace ONE credentials", { status: 500 });
  }

  const expected = `Basic ${Buffer.from(`${username}:${password}`).toString("base64")}`;
  if (request.headers.get("authorization") !== expected) {
    return new Response("Unauthorized", { status: 401 });
  }

  const body = await request.text();
  console.log("Received Workspace ONE event:", body);

  return new Response("ok", { status: 200 });
}

Choose a user name and a long random password for the notification rule. Store them:

.env.local
WORKSPACE_ONE_USERNAME=horizon-test
WORKSPACE_ONE_PASSWORD=replace-with-a-long-random-string

Start the app:

npm run dev

Start a tunnel

In a second terminal, open a tunnel to port 3000 on a subdomain you reserved, with -s:

hrzn tunnel http://localhost:3000 -s my-workspace-one-app
Output
HORIZON: Tunnel connected
  URL          https://my-workspace-one-app.hrzn.run (reserved)
  Forwarding   http://localhost:3000
  Request log  https://hrzn.run/dashboard/tunnels/my-workspace-one-app

Your public URL is https://my-workspace-one-app.hrzn.run. Without -s the subdomain is random and changes on every run, so the rule would point at a dead URL after a restart. Reserved subdomains are a paid feature, see Pricing.

Add the notification rule

Your target URL is the tunnel URL plus the route path: https://my-workspace-one-app.hrzn.run/api/webhooks/workspace-one.

  1. In the UEM console, go to Groups & Settings, then All Settings, then System, then Advanced, then API, then Event Notifications.
  2. Select Add Rule.
  3. Enter a Target Name. It labels the notification on the Event Notifications page.
  4. Enter the target URL as Target URL.
  5. Enter User Name and Password. Use the values from .env.local.
  6. Set Format to JSON.
  7. In the Events section, select the events that trigger the notification. The options include Device Enrollment, Device Wipe, Device Delete and Device Compliance Status Change.
  8. Save the rule.

Trigger an event

Workspace ONE has no resend button for event notifications. Cause one of the events you selected. For example, enroll a test device, or change an attribute you enabled under Device Attribute Change.

Check it works

When the event fires, the Horizon terminal prints one line:

Output
  POST    200  /api/webhooks/workspace-one

Your app terminal prints Received Workspace ONE event: followed by the body.

If the line shows [401], see Troubleshooting.

Troubleshooting

The handler returns 401

The Authorization header doesn't match the credentials in .env.local.

  • Check that User Name and Password in the rule match WORKSPACE_ONE_USERNAME and WORKSPACE_ONE_PASSWORD. Restart npm run dev after you edit .env.local.
  • Log request.headers.get("authorization") once to see what the console sends. If it isn't a Basic header, adjust the check to match.

Nothing reaches your app

  • Check that the Horizon terminal and npm run dev are both running.
  • Check that Target URL ends with /api/webhooks/workspace-one.
  • Check that the rule selects the event you triggered. The UEM server logs notification activity in ChangeEventOutboundQueueService.Log, in the Logs/Services folder of the install. This applies to on-premises installs.

The URL changed after a restart

You started the tunnel without -s, so Horizon gave you a new random subdomain. Restart with -s my-workspace-one-app and update Target URL if it differs.

Next steps

On this page