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
NexusPublicKeyExceptionfromgetSecret - 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 created0600 - PSR-3 logging - structured context, and never a secret value or key name in the output
- 402/429 handling with quarantine detection (
NexusQuarantinedExceptionwith$reasonand$expiresAt)
What’s new in v0.16.0
AbstractProvider::getMetadata()->getName()reports the correct provider name onopen-feature/sdk >=2.1(the new floor) -NexusProviderreportsNexus, not the base class’s own name.aws_iam’s signed request includesContent-Typein its signed headers onaws/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 (aWeakMapkeyed by instance), closing the one rendering channel that has no redaction hook.
What’s new in v0.14.0
aws_iamworks on a non-default port. The signedX-Nexus-Server-IDnow carries the port whenever it is not the scheme’s default, matching the host the backend validates against, soaws_iamauthenticates against a deployment reached athttps://host:8443and not only on443. 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
MITLICENSEfile. The published Composer package carriessrc/and the Laravelconfig/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
developerprovider. A sessionwestyx dev setupalready 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. WifProvideris a backed enum, so an invalid provider is aTypeErrorat 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 survivesphp 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_encodeandserializecarry 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
EvaluationContextcarries atargetingKeyis evaluated for that identity through the AB Testing add-on and reportsTARGETING_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/nexusasWestyxNexus\OpenFeature\NexusProvider, withopen-feature/sdkas a Composersuggest. 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 fromevaluateAb()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_MISMATCHinstead of coercing, so a config holding"8080"no longer resolves as the number8080. - Available on Packagist -
composer require westyx/nexusworks 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/nexusbrings 6 packages and about 1 MB. See HTTP client. - Laravel service provider -
composer require westyx/nexusin 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
$contextarray. 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 created0600at creation time, withO_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 Modifiedand 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-Afterand 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_iamWIF 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 STSGetCallerIdentityrequest (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 signedX-Nexus-Server-IDis 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 optionalaws/aws-sdk-phppackage. 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-positiveexpires_inis clamped.
What’s new in v0.8.2
- WIF GCP fix - the
gcpprovider now fetches a real Google-signed OIDC identity token from the GCE metadata server. It previously read theGOOGLE_APPLICATION_CREDENTIALSkey 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.devto the correcthttps://<slug>.westyx.dev(the deployed host format). No API or behavior change.
What’s new in v0.8.0
- OpenFeature provider - new
westyx/nexus-openfeaturesub-package implementing the OpenFeature PHP SDK provider interface, wrapping an existingNexusClientwith 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 yourbaseUrlto<slug>.westyx.dev. - Quarantine handling - new
429quarantine response pauses sync until expiry;NexusQuarantinedExceptionexposes$reasonand$expiresAt. - Write API -
setSecret,deleteSecret,deleteSecretVersionfor services using a secret key. is_publicremoved - PK keys now see all configs and flags without theis_publicfilter.
Installation
aws_iam signs Content-Type again, both from raised dependency floors).
