Skip to main content
For deployments that prefer not to manage static API keys, the PHP SDK can authenticate via Workload Identity Federation (WIF). The SDK fetches a workload OIDC token from the running environment, exchanges it for a Nexus session JWT, and uses Authorization: Bearer <jwt> on every subsequent API call. WIF is opt-in. When NexusConfig::$wif is null (the default), the SDK uses the static apiKey flow and behaves identically to a client without WIF configuration.

Enabling WIF

Pass a WifConfig to NexusConfig::$wif:
apiKey becomes optional when wif is set. You can provide both - the SDK uses WIF and falls back to the static key if a session refresh fails after the initial connect.
Security note (v0.9.0): the baseUrl must use https:// - NexusClient::create() rejects plain-http endpoints (loopback/localhost excepted for development), since credentials travel on every request.

WifConfig reference

Provider auto-detection table

When provider is 'auto', the SDK probes the environment in this order, checking for actual credential material (the token files are stat-ed, not just env-var presence): The first matching provider is used. If none match and no tokenSource closure is provided, NexusClient::create throws a NexusException. aws_iam is not auto-detected - select it explicitly (resolvable AWS credentials alone, e.g. a dev laptop’s ~/.aws/credentials, are too weak a signal).

AWS IAM (non-EKS AWS compute)

ECS/Fargate tasks, Lambda functions, and plain EC2 instances have IAM credentials but no OIDC token, so the OIDC providers cannot serve them. The aws_iam provider closes this gap. It requires the optional aws/aws-sdk-php package:
The SDK SigV4-signs an STS GetCallerIdentity request with the standard AWS credential chain (task role, instance profile, env) - never sending it to AWS - and posts the signed headers + body to /v1/auth/token-exchange as {"provider":"aws_iam","aws_sts_request":...}. Nexus replays it against a pinned STS endpoint and matches the caller’s IAM role against an aws_iam trust policy (subject = arn:aws:iam::<account>:role/<name>). Nothing else to configure: the SDK signs your service’s own host (the baseUrl host) into X-Nexus-Server-ID inside the signature, and Nexus verifies it against the host the request arrived on - so a captured signed request is valid for that ONE service only. Selecting aws_iam without aws/aws-sdk-php installed throws an actionable NexusException.

Explicit provider

Pin a specific provider to skip auto-detection:

Custom tokenSource closure

Provide a Closure to bypass auto-detection entirely. This is useful for tests, custom CI flows, or environments the SDK does not natively recognise:
When tokenSource is non-null it takes precedence over provider.

Token exchange flow

Internally, the SDK runs this protocol at startup and on each session refresh:
  1. OIDC token fetch - calls tokenSource() (or the auto-detected built-in equivalent) to get a workload-identity JWT.
  2. Token exchange - POSTs {"oidc_token": "<jwt>"} to /v1/auth/token-exchange. No auth header is sent on this call. The backend validates the OIDC issuer and signature, then returns:
  3. Bearer auth on subsequent calls - every /v1/* request carries Authorization: Bearer <session_token>.
  4. Pre-emptive refresh - when a request finds the session expires within 60 seconds, the SDK refreshes (re-running steps 1-2) before issuing the call.

Session refresh within 60 s of expiry

The SDK stores the session expiry time after each token exchange. Before each sync, write, or A/B test call, it checks whether the JWT expires within 60 seconds. If yes, it runs a token exchange first, then proceeds with the original call. connectStream()’s auth_expiring SSE event triggers a non-blocking early refresh ~5 minutes before expiry, reducing the chance of a mid-stream expiry.

Error cases

Project-level vs service-level trust policies

The Nexus backend supports trust policies at two scopes: At token exchange time the backend applies this resolution order:
  1. Does a service-level trust policy match this workload’s OIDC token claims? - if yes, authorise.
  2. Does a project-level trust policy match? - if yes, authorise.
  3. Neither matches - return 401.
This means you can configure one project-level trust policy and all services in the project accept that workload’s tokens. Each service client still uses its own baseUrl, so each gets its own service’s data.
A project-level trust policy is less restrictive than a service-level one. Any workload satisfying the policy can connect to any service in the project by targeting its baseUrl. For services handling sensitive data (payments, credentials, PII) consider a dedicated service-level trust policy instead.