Skip to main content
Official PHP SDK for Westyx Nexus - the centralised secrets, feature flags, and config service.

Highlights

  • PHP 8.3+ - pure PHP, no framework required; tested on 8.3, 8.4 and 8.5
  • PSR-18 / PSR-17 - uses the HTTP client your project already has; nothing forced on you
  • Laravel service provider - auto-discovered, with the container’s HTTP client and logger wired in
  • TTL cache with ETag/304 support - reads never block the network after the first sync
  • SSE live updates via connectStream() (long-running CLI daemons and queue workers only)
  • Public-key vs secret-key access control - public-key clients get NexusPublicKeyException from getSecret
  • Workload Identity Federation - Kubernetes / AWS IRSA / GCP / Azure auto-detected; AWS IAM (aws_iam) for ECS/Fargate/Lambda/plain-EC2 (v0.9.0)
  • Write API (setSecret, deleteSecret, deleteSecretVersion) for secret keys
  • A/B testing (evaluateAb) for the AB Testing add-on
  • File-type secrets (getSecretFilePath) - materialised into a private per-client directory, files created 0600
  • PSR-3 logging - structured context, and never a secret value or key name in the output
  • 402/429 handling with quarantine detection (NexusQuarantinedException with $reason and $expiresAt)

What’s new in v0.16.0

  • AbstractProvider::getMetadata()->getName() reports the correct provider name on open-feature/sdk >=2.1 (the new floor) - NexusProvider reports Nexus, not the base class’s own name.
  • aws_iam’s signed request includes Content-Type in its signed headers on aws/aws-sdk-php >=3.386 (the new floor).
  • Every declared dependency floor builds and passes on PHP 8.5, verified by a permanent CI leg.

What’s new in v0.15.0

  • var_export() no longer prints the API key or a cached secret, on the config, the cache, or a live client. All three are held outside the object’s property table (a WeakMap keyed by instance), closing the one rendering channel that has no redaction hook.

What’s new in v0.14.0

  • aws_iam works on a non-default port. The signed X-Nexus-Server-ID now carries the port whenever it is not the scheme’s default, matching the host the backend validates against, so aws_iam authenticates against a deployment reached at https://host:8443 and not only on 443. See Workload identity.
  • A failing logger cannot break an SDK call. A PSR-3 logger that throws - a Monolog handler on a full disk is the usual case - no longer propagates out of a config, secret or WIF operation; the diagnostic write is contained. See Custom logging.
  • Leaner package, and an MIT LICENSE file. The published Composer package carries src/ and the Laravel config/ only; the test suite and development tooling are stripped from the dist.
  • Raised baselines - PHPStan at level 10, PHPUnit 12, plus code coverage and a SonarQube job.

What’s new in v0.13.0

  • The developer provider. A session westyx dev setup already issued is sent as the Bearer directly - no token exchange - so a laptop can authenticate to a WIF-enforced service. Probed last, behind every cloud provider.
  • WifProvider is a backed enum, so an invalid provider is a TypeError at construction rather than a failure on the first request, and the resolver is exhaustiveness-checked.
  • The credential extension point is an interface, WifCredentialSource, which can express a credential that is not a bearer token and survives php artisan config:cache.
  • The Azure IMDS path, so an Azure VM or App Service workload with no projected token file can authenticate. Needs audience: 'api://<client-id>'.
  • A dumped client shows a redacted view - var_dump, print_r, json_encode and serialize carry no credential, and a secret no longer reaches an exception trace.

What’s new in v0.12.0

  • Per-user targeting through OpenFeature - a boolean evaluation whose EvaluationContext carries a targetingKey is evaluated for that identity through the AB Testing add-on and reports TARGETING_MATCH. One request covers every flag in the snapshot and the results are memoised per identity, so a page resolving twenty flags for a user makes one call. See OpenFeature.
  • The OpenFeature provider is installable - it ships inside westyx/nexus as WestyxNexus\OpenFeature\NexusProvider, with open-feature/sdk as a Composer suggest. A project that does not use it installs nothing extra.
  • findFlag() - returns ?bool, so a flag that does not exist is distinguishable from one that exists and is off. See API reference.
  • NexusAbAddonNotAvailableException - the 403 from evaluateAb() has its own type. See Error handling.
  • Attribute values are strings, and are checked - evaluateAb() rejects a non-string attribute value naming the attribute and the type it received, before the request goes out.
  • Numbers resolve as numbers - the OpenFeature integer and float resolutions report TYPE_MISMATCH instead of coercing, so a config holding "8080" no longer resolves as the number 8080.
  • Available on Packagist - composer require westyx/nexus works with no repository configuration. See Installation.

What’s new in v0.11.0

  • Bring your own HTTP client - the SDK is built on PSR-18 and PSR-17, so it uses whatever HTTP stack your project already has. Guzzle still works and is no longer required; installing westyx/nexus brings 6 packages and about 1 MB. See HTTP client.
  • Laravel service provider - composer require westyx/nexus in a Laravel app is the whole setup: app('nexus') and constructor injection both work, and SDK diagnostics reach your application log automatically. See Laravel.
  • PSR-3 logging, wired through - syncs, stream activity and WIF session exchanges are reported through the logger you pass, with values in the PSR-3 $context array. Secret values and secret key names never appear in log output. See Custom logging.
  • File-type secrets live in a private directory - each client creates its own directory with a runtime-chosen name and mode 0700; the files inside are created 0600 at creation time, with O_EXCL. Two clients holding the same secret get independent files.
  • Stream deadlines - the live-update stream has a connection deadline (10 s) and a liveness deadline (60 s) that resets on every byte, so a connection dropped by a load balancer is detected rather than read as healthy. See SSE live updates.
  • The cache serves what it has - a 304 Not Modified and a brief network failure both keep serving the last snapshot the server sent, so reads return real values rather than their defaults. See Caching behaviour.
  • One status-code contract - every endpoint reports the same condition the same way, with Retry-After and quarantine details preserved wherever they occur. See Error handling.

What’s new in v0.10.0

  • Version alignment across the Westyx Nexus SDK suite.

What’s new in v0.9.0

  • aws_iam WIF provider (AWS IAM Caller Identity) - authenticates non-EKS AWS compute (ECS/Fargate, Lambda, plain EC2) that has IAM credentials but no OIDC token. The SDK SigV4-signs an STS GetCallerIdentity request (never sent to AWS) and posts it to /v1/auth/token-exchange; Nexus replays it against a pinned STS endpoint to prove your IAM role. The signed X-Nexus-Server-ID is your service’s own base-URL host - a captured request is valid for that one service only, and there is nothing to configure. Requires the optional aws/aws-sdk-php package. See Workload identity.
  • Security hardening - the base URL must be https:// (loopback excepted); expired WIF sessions refresh transparently on every request path and fail closed (a WIF-only client never falls back to an empty API key); the GCP metadata and token-exchange reads are size-bounded; auto-detection stats the AWS/Azure token files instead of trusting a bare env var; a non-positive expires_in is clamped.

What’s new in v0.8.2

  • WIF GCP fix - the gcp provider now fetches a real Google-signed OIDC identity token from the GCE metadata server. It previously read the GOOGLE_APPLICATION_CREDENTIALS key file, which is not a JWT and was rejected by the token exchange. Auto-detection was aligned with the actual token sources. Verified end-to-end against a real GCE workload.

What’s new in v0.8.1

  • Docs fix - corrected the example service base URL from the non-existent https://<slug>.api.westyx.dev to the correct https://<slug>.westyx.dev (the deployed host format). No API or behavior change.

What’s new in v0.8.0

  • OpenFeature provider - new westyx/nexus-openfeature sub-package implementing the OpenFeature PHP SDK provider interface, wrapping an existing NexusClient with no additional network calls. It was never actually installable this way - a Composer package must sit at the root of its own git repository - and moved into the main package itself in v0.12.0; see What’s new in v0.12.0.

What’s new in v0.5.1

  • Requires PHP 8.3+ - PHP 8.1 and 8.2 are EOL; the SDK now requires PHP 8.3 or later.
  • Security improvements - exception messages contain only status codes; file-type secret paths are fully hashed.
  • Reliable streaming - improved quarantine handling and full SSE event coverage.

What’s new in v0.5.0

  • Path prefix update - API endpoints use /v1/; update your baseUrl to <slug>.westyx.dev.
  • Quarantine handling - new 429 quarantine response pauses sync until expiry; NexusQuarantinedException exposes $reason and $expiresAt.
  • Write API - setSecret, deleteSecret, deleteSecretVersion for services using a secret key.
  • is_public removed - PK keys now see all configs and flags without the is_public filter.

Installation

The package is on Packagist, so nothing else is needed; to install it from the Westyx GitLab Composer registry instead, see Installation for the repository setup. Latest release: v0.16.0 (2026-08-29 - the OpenFeature provider reports its own name correctly, and aws_iam signs Content-Type again, both from raised dependency floors).

Quick start

Pages