How it works
- The SDK obtains an OIDC token from the local cloud metadata endpoint (or a custom
ExchangePayloadProvider). - It exchanges the token at
POST /v1/auth/token-exchangefor a short-lived Nexus session token. - All subsequent HTTP requests use
Authorization: Bearer <session_token>instead ofX-Nexus-API-Key. - When the server sends an
auth_expiringSSE event, the SDK proactively refreshes the session token before it expires.
Enabling WIF
apiKey = null when using WIF. If both are set, the session token takes precedence once exchanged, and the static key acts only as an explicit fallback.
Selection fails closed. If the configured credential - orauto- cannot resolve,NexusClient.createraisesNexusWifNotConfiguredExceptionnaming what was probed. A client that asked for workload identity is never quietly created with API-key authentication instead, because that is the one outcome a caller cannot detect.
Security note:baseUrlmust usehttps://-NexusClient.createrejects plain-http endpoints (loopback/localhost excepted for development), since credentials travel on every request.
Credentials
kubernetes
Reads the service account token projected into every Kubernetes pod.
- Token path:
/var/run/secrets/kubernetes.io/serviceaccount/token - Setup: Mount the service account token (default in Kubernetes 1.21+). Configure a trust policy in Nexus with the cluster’s OIDC issuer URL.
aws
Reads the web identity token file used by IAM Roles for Service Accounts (IRSA) on EKS.
- Environment variable:
AWS_WEB_IDENTITY_TOKEN_FILEmust point to an existing token file. - Setup: Attach an IAM role to the pod and configure a Nexus trust policy with the AWS account and role ARN.
aws_iam
For 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 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. 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>).
Requires the optional AWS SDK for Java v2 dependencies software.amazon.awssdk:auth + :regions; selecting aws_iam without them throws an actionable error naming the coordinates. Not auto-detected - select it explicitly.
X-Nexus-Server-ID is your service’s own base-URL host, verified by the backend against the host the request arrived on - so a captured signed request is valid for that ONE service only, and nothing needs configuring.
gcp
Fetches a signed OIDC ID token from the GCP instance metadata endpoint.
- Metadata URL:
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience=<audience> - Setup: Attach a service account to the Compute Engine instance, Cloud Run service, or GKE pod. Configure a Nexus trust policy with the service account email.
azure
Authenticates an Azure managed identity or AKS workload identity. On AKS with Azure Workload Identity the SDK prefers the projected federated token file ($AZURE_FEDERATED_TOKEN_FILE); otherwise it fetches a managed-identity token from the Azure IMDS.
- Federated file (preferred):
$AZURE_FEDERATED_TOKEN_FILE(AKS Workload Identity). - IMDS URL:
http://169.254.169.254/metadata/identity/oauth2/token - Setup: Assign a managed identity to the VM, AKS pod, or App Service. Configure a Nexus trust policy with the Azure tenant and client ID.
The audience is required on the IMDS path. It is your app registration’s Application ID URI; the generic default (westyx-nexus) is rejected at construction, because Azure AD does not accept it as a resource - and the SDK never requests an ARM (management.azure.com) token instead. On the federated-file path leave it null: the cluster sets it.
auto (default)
Probes the environment and returns the first credential whose material is actually present. Token files are stat-ed and the metadata servers live-probed with a ~2 s timeout:
Azure appears twice because those are two different mechanisms, not one checked twice: step 3 reads a token file the cluster projects into the pod, step 5 calls the link-local IMDS endpoint. They sit apart because every free filesystem check runs before every network probe - a stat costs nothing, a probe costs up to two seconds - and the developer credential is always last, so a real workload identity wins over a laptop one.
aws_iam is deliberately not in this chain. Resolvable AWS credentials alone - a dev laptop’s ~/.aws/credentials is enough - are too weak a signal that the machine is AWS compute, so it must be selected explicitly.
Step 5 needs an audience. Azure IMDS has no valid default, so reaching it through auto means giving Auto one: WifCredential.Auto(audience = "api://<client-id>"). Without it that step reports the audience to set rather than sending the generic westyx-nexus, which Azure AD rejects as a resource - and the SDK never substitutes an ARM token. AKS Workload Identity needs none, because step 3 gets there first and the projected file carries its own. If nothing matches at all, create raises NexusWifNotConfiguredException listing everything it probed.
Use auto when the same binary is deployed to multiple environments and you do not want to manage credential selection in config.
developer
A Nexus session token that westyx dev setup --service=<name> already obtained and stored on this machine. Discovery is $WESTYX_DEV_TOKEN first, then the CLI’s dev-credentials.json, whose entry is matched on the endpoint you configured as baseUrl.
auto, so the same code runs unchanged on a laptop and in a cluster.
No token exchange happens on this path. The CLI performed the exchange, so the stored value already is a Nexus session and the SDK sends it straight through as the bearer. The SDK reads only the token and its expiry - never a Keycloak refresh token.
An expired credential fails with the command that renews it. A credentials file readable by group or others is refused with a chmod 600 instruction rather than used, because a session token readable by every local user is a condition you need to see.
Custom credentials
For environments the built-in credentials do not cover, supply anExchangePayloadProvider. It returns the whole POST /v1/auth/token-exchange body, so a credential that is not an OIDC bearer token can be expressed - the built-in aws_iam credential is implemented against this same public interface.
oidcTokenProvider wraps it in the standard {"oidc_token": ...} body:
null or a blank string raises NexusWifNotConfiguredException rather than falling through to unauthenticated requests. Override close() when the provider owns something; it is called when the client is closed.
The audience field
An audience is carried by the credentials that request one, rather than shared across all of them.
WifCredential.Gcp(audience = ...)is sent to the GCE metadata endpoint as a query parameter. Default:"westyx-nexus".WifCredential.Auto(audience = ...)supplies both probed paths that need one: GCP, and Azure IMDS when auto-detection reaches it.WifCredential.Azure(audience = ...)is theresourceon the IMDS path and must be your app registration’s Application ID URI (api://<client-id>). A blank value or the generic default is rejected at construction. Leave it null on AKS Workload Identity, where the projected token file carries its own audience.- Kubernetes and AWS projected tokens carry the audience from their pod spec, so those cases take none.
Token exchange flow
At client creation, the SDK calls:session_token with an expiry of now + expires_in, and refreshes it pre-emptively 60 seconds before that expiry. expires_in is floored at 300 seconds - comfortably above the refresh window, so a freshly exchanged session never looks “expiring soon” and triggers a re-exchange on every call - and clamped at 24 hours, so a stale session cannot live effectively forever. All subsequent requests use Authorization: Bearer <session_token>.
A file-backed provider captures its token path at construction, so a later refresh reads the file the client was built with rather than whatever the environment names by then.
Project-level vs service-level trust policies
The Nexus backend supports trust policies at two scopes:How it works
The SDK always connects to a specific service via itsbaseUrl. The URL slug identifies the service - this works the same as API keys. At token exchange time, the backend checks service-level trust policies first, then falls back to project-level.
Example: one cloud identity for 50 services
You can configure one project-level trust policy and all services use it. Each service SDK instance still uses its ownbaseUrl, so each gets its own service’s data.
Security trade-off
Note: 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, PII) consider a dedicated service-level trust policy.
