Authentication Overview

The Watchman Tower WordPress integration uses two stages of authentication:
  1. a register token to complete the initial pairing
  2. a paired shared secret + site ID for ongoing authenticated heartbeat traffic
This is different from a permanent manually managed API key workflow.

Stage 1: Register Token

The initial connection starts with a register token. The plugin stores that token in wthb_options and uses it to complete the first connection heartbeat. That first request is what allows Watchman Tower to return pairing data such as:
  • siteId
  • secretKey or hmacSecret
  • desiredIntervalSec
  • pause
The docs should not assume a public token format, fixed expiry window, or wp-config-based setup flow unless that behavior is explicitly implemented by the product.

Stage 2: Paired Authentication

After the first successful pairing heartbeat, the plugin stores:
  • site_id
  • hmac_secret
  • connected
From that point on, the plugin prefers HMAC-authenticated requests for outgoing heartbeat traffic. If HMAC data is not available yet, it can still fall back to bearer-token style authentication during the early connection phase.

Outgoing Heartbeat Authentication

For paired outbound requests, the plugin signs the heartbeat payload and sends headers such as:
  • X-WT-Key
  • X-WT-Timestamp
  • X-WT-Signature
The site ID acts as the key identifier, while the shared secret is used to sign the request body.

Inbound WT-Triggered Authentication

The plugin also exposes an authenticated REST route at:
/wp-json/wt/v1/heartbeat
When Watchman Tower triggers this endpoint, the request is verified with the stored site_id and hmac_secret before the heartbeat job is executed.

Where State Is Stored

Most pairing state is stored in:
wp option get wthb_options --format=json
The locally generated instance ID is stored separately:
wp option get wthb_instance_id
Useful auth-related fields in wthb_options:
  • token
  • agent_jwt
  • hmac_secret
  • site_id
  • connected

Practical Security Notes

The current plugin behavior supports these safe assumptions:
  • pairing is site-specific
  • ongoing traffic becomes secret-based after connection succeeds
  • unlinking clears pairing state locally
The current plugin does not document or implement a public workflow around:
  • fixed token prefixes
  • environment-specific token naming
  • wp-config constants as the primary setup path
  • dashboard-driven token rotation UI inside the plugin docs

Next Steps