Skip to content

Phase 10: REST API

Expose all licensing operations over a versioned REST API with per-key read/write scopes and HTTP Basic authentication.

  • src/Rest/Auth/BasicAuth.php
  • src/Rest/Controllers/BaseController.php
  • src/Rest/Controllers/LicensesController.php
  • src/Rest/Controllers/ActivationsController.php
  • src/Rest/Controllers/ValidateController.php
  • src/Rest/Controllers/HeartbeatController.php
  • src/Rest/Controllers/RevocationController.php
  • src/Rest/Controllers/GeneratorsController.php
  • src/Rest/Controllers/ApiKeysController.php
  • src/Rest/Controllers/WebhooksController.php
  • src/Rest/Controllers/ReleasesController.php
  • src/Rest/Controllers/SubscriptionsController.php
  • src/Rest/Controllers/AnalyticsController.php

BasicAuth hooks determine_current_user at priority 20.

Request flow:

Authorization: Basic base64(consumer_key:consumer_secret)
1. Decode header.
2. Hash consumer_key with sha256() → look up in wp_wplm_api_keys.
3. Verify consumer_secret with hash_equals() against stored bcrypt hash.
4. Touch last_access timestamp.
5. Store static $current_api_key for permission callbacks.
6. Return WP_User for the key owner so WP REST core accepts the request.

hash_equals() prevents timing attacks on the secret comparison.

API keys carry a permissions field: read, write, or read_write.

BaseController provides three permission callbacks used in register_rest_route():

$this->require_read() // read or read_write key required
$this->require_write() // write or read_write key required
$this->public_route() // no auth (validate, heartbeat, CRL)
MethodEndpointScope
GET/wplm/v1/licensesread
POST/wplm/v1/licenseswrite
GET/wplm/v1/licenses/{id}read
PUT/wplm/v1/licenses/{id}write
DELETE/wplm/v1/licenses/{id}write
POST/wplm/v1/validatepublic
POST/wplm/v1/activatepublic
POST/wplm/v1/deactivatepublic
POST/wplm/v1/heartbeatpublic
GET/wplm/v1/revocation/crlpublic
POST/wplm/v1/licenses/{id}/revokewrite
POST/wplm/v1/licenses/{id}/suspendwrite
POST/wplm/v1/licenses/{id}/terminatewrite
GET/wplm/v1/generatorsread
POST/wplm/v1/generatorswrite
POST/wplm/v1/generators/{id}/generatewrite
GET/wplm/v1/subscriptionsread
POST/wplm/v1/subscriptions/{id}/pausewrite
POST/wplm/v1/subscriptions/{id}/resumewrite
POST/wplm/v1/subscriptions/{id}/cancelwrite
GET/wplm/v1/analytics/overviewread
GET/wplm/v1/analytics/anomaliesread
GET/POST/wplm/v1/webhooksread/write
GET/POST/wplm/v1/releasesread/write

All responses use standard WP REST WP_REST_Response. Error responses follow:

{
"code": "wplm_not_found",
"message": "License not found.",
"data": { "status": 404 }
}