Skip to main content
Workload Identity Federation (WIF) lets your JVM application authenticate to Nexus using the cloud-provider identity of the workload itself - no static API keys to store or rotate.

How it works

  1. The SDK obtains an OIDC token from the local cloud metadata endpoint (or a custom ExchangePayloadProvider).
  2. It exchanges the token at POST /v1/auth/token-exchange for a short-lived Nexus session token.
  3. All subsequent HTTP requests use Authorization: Bearer <session_token> instead of X-Nexus-API-Key.
  4. When the server sends an auth_expiring SSE event, the SDK proactively refreshes the session token before it expires.

Enabling WIF

Leave 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 - or auto - cannot resolve, NexusClient.create raises NexusWifNotConfiguredException naming 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: baseUrl must use https:// - NexusClient.create rejects 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_FILE must 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.
The signed 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.
More usually you configure nothing: it is the last step of 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 an ExchangePayloadProvider. 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.
For a plain OIDC token, oidcTokenProvider wraps it in the standard {"oidc_token": ...} body:
Returning 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 the resource on 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.
The value must match the audience configured in the Nexus trust policy.

Token exchange flow

At client creation, the SDK calls:
The server validates the OIDC token against the trust policy and returns:
The SDK stores 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 its baseUrl. 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 own baseUrl, 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.

Error handling