Skip to main content
For deployments that prefer not to manage static API keys, the Spring Boot 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 falls back to the static apiKey flow and behaves exactly as in v0.1.0.

Enabling via application.yml

When nexus.wif.enabled is true, nexus.api-key becomes optional.
Security note (v0.9.0): nexus.base-url must use https:// - NexusClient.create rejects plain-http endpoints (loopback/localhost excepted for development), since credentials travel on every request.

Enabling programmatically

Each provider has its own factory, and that factory owns the provider’s options - so a combination that has no meaning cannot be written down:

Supplying your own credential

The auto-configuration picks up any WIFConfig bean automatically, and a bean takes precedence over the nexus.wif.* properties. WIFConfig.custom(...) is where a credential the SDK has no provider for is expressed - it builds the whole token-exchange body, which a bearer-string producer structurally cannot do:
The source is called once per session refresh, on the calling thread, so blocking I/O inside it is fine. It cannot be selected from nexus.wif.provider - it needs an object, so it is a bean.

Supported providers

When provider is auto the SDK probes the environment in this order and picks the first provider whose credential material is actually present - a file stat or a live metadata probe with a ~1 s timeout, never an environment variable alone: developer is the last provider auto considers, so a real cloud identity always wins over a laptop credential. WIFProvider is an enum: wireValue() is the spelling the protocol and application.yml use, and fromWireValue(String) parses one. The property binds leniently - aws_iam, aws-iam, AWS_IAM and NEXUS_WIF_PROVIDER=aws_iam all resolve to the same constant - and an unknown value fails the context start naming the property, the value, its origin and every valid name. The OIDC providers use only java.net.http.HttpClient; aws_iam additionally uses software.amazon.awssdk:auth + :regions (optional dependencies) for the credential/region chain and the SigV4 signer. developer needs nothing - the credentials file is read through the SDK’s own JSON codec.

Local development (the developer provider)

An application on a developer machine has no workload OIDC token. The developer provider uses the session the Westyx CLI already obtained:
Discovery order
  1. $WESTYX_DEV_TOKEN, when set and non-blank - its value is the session token, and no file is read.
  2. The CLI’s dev-credentials.json, whose entry is selected by matching the configured base-url. Two local services on different ports therefore keep their own credentials.
Where the file lives, matching what the CLI writes: Expiry. The session is not renewed automatically. An entry that has expired - or that is close enough to expiry that the next request would refresh it anyway - is refused with the exact westyx dev setup --service=<name> command to run. Only token and expires_at are read from an entry; no Keycloak credential is ever opened or stored. File safety. The credentials file is refused if it is readable beyond its owner. The CLI writes it 0600 inside a 0700 directory. No exchange takes place - see Token exchange flow.

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. Add the optional AWS SDK dependencies (software.amazon.awssdk:auth + :regions), then:
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 base-URL 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 the AWS SDK dependencies present throws an actionable error naming the Maven coordinates.

Audience

GCP and Azure require an audience claim when issuing the OIDC token:
Azure IMDS is the exception: the generic default is refused with a clear error, because Azure AD rejects it as a resource. On the IMDS path (plain VM / App Service - no federated token file) you MUST set audience to your app registration’s Application ID URI (api://<client-id>). On AKS with Azure Workload Identity the projected federated token file ($AZURE_FEDERATED_TOKEN_FILE) is preferred automatically and no audience is needed. Default: westyx-nexus.

Token exchange flow

The developer provider skips this entirely. It yields an already-issued Nexus session token, which is used directly as the bearer; nothing is POSTed to /v1/auth/token-exchange. A refresh re-reads the source, so re-running westyx dev setup in another terminal is picked up without restarting the application.
  1. OIDC token fetch - the configured Supplier<String> returns a workload-identity JWT.
  2. Token exchange - the SDK POSTs {"oidc_token": "<jwt>"} to /v1/auth/token-exchange. The backend validates the OIDC issuer/signature and returns:
  3. Session storage - the SDK caches the session token in memory and uses Authorization: Bearer <session> on all subsequent /sync and /stream requests.
  4. Auto-refresh - ~60 s before expiry the SDK silently re-runs steps 1-2 from a background thread. The active SSE stream is not interrupted.
  5. auth_expiring event - when the server emits this control event over SSE, the SDK pre-emptively refreshes the session before the server force-closes the stream.

Split sync vs stream HttpClient

The SDK uses two separate HttpClient instances - one for short requests (/sync, /token-exchange, connectTimeout = 10s) and one for the long-lived SSE stream. This prevents a consumer-supplied short timeout from killing the stream after a few seconds.

Project-level vs service-level trust policies

The Nexus backend supports trust policies at two scopes:
A project-level trust policy is less restrictive than a service-level one. Any workload that satisfies the policy can connect to any service in the project by targeting its base-url. For services handling sensitive data (payments, credentials, PII) consider a dedicated service-level trust policy.