Skip to main content
For deployments that prefer not to manage static API keys, the Python 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 None (the default), the SDK uses the static api_key flow. Both NexusClient (sync) and AsyncNexusClient (asyncio) support WIF.

Enabling

WIFConfig is constructed with keyword arguments only, and api_key is optional when WIF is enabled.
Security note: base_url must use https:// - NexusClient.create / AsyncNexusClient.create reject plain-http endpoints (loopback/localhost excepted for development), since credentials travel on every request.

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. The OIDC providers are httpx-only; aws_iam uses botocore (the optional [aws-iam] extra) for the credential/region chain and the SigV4 signer. developer needs no dependency at all - the credentials file is JSON. You can also pin a specific provider. WIFProvider is a StrEnum unioned with the equivalent Literal, so the enum member and the plain string are both accepted and both type-check, while a value outside the set is rejected by the checkers and raises ValueError at construction:
The six WIF_PROVIDER_* constants are aliases of the enum members, and WIF_PROVIDER_DEVELOPER joins them.

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 botocore dependency:
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 botocore installed raises an actionable error naming the extra.

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-empty - 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 SDK’s base_url host and port. 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, and a session the server rejects reports the same. 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 a symlink, or if its mode allows any group or other access. The CLI writes it 0600 inside a 0700 directory. No exchange takes place - see Token exchange flow.

Supplying your own credential

Two hooks exist, and exchange_payload is the general one.

exchange_payload - the whole body

exchange_payload receives an ExchangeContext and returns the entire POST /v1/auth/token-exchange body, so a credential that is not an OIDC token can be expressed:
ExchangeContext carries server_id, base_url and audience. The callable may be sync or async; AsyncNexusClient runs a synchronous implementation in a worker thread, so blocking I/O inside it is safe. It is invoked once per session refresh, not per API call. One consequence: reaching the aws_iam wire shape does not require botocore if you sign the STS request with your own tooling.

token_source - the short path

When your credential is a JWT, token_source returns it and the SDK wraps it in the standard body.
Precedence is exchange_payload > token_source > provider. The one combination that is refused is provider="aws_iam" with token_source: aws_iam proves identity with a signed STS request and has no OIDC token, so WIFConfig(...) raises ValueError naming the conflict. Both override paths report wif=custom in the SDK’s logs, which is what they are - the caller supplied the credential. aws_iam has its own branch, so naming the configured provider there would log a provider the SDK never contacted.

Audience

GCP and Azure require an audience claim when issuing the OIDC token:
The default is "westyx-nexus" if unset. 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.

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 process.
  1. OIDC token fetch - the configured token source 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 (sync) or task (async). 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 httpx clients

The SDK uses two separate httpx.Client instances - one for short requests (/sync, /token-exchange) with timeout=cfg.timeout_seconds on every phase, and one for the long-lived SSE stream that keeps the connect, write and pool deadlines but lifts the read deadline. This prevents a consumer-supplied short timeout from killing a stream that is merely idle, without leaving the connect unbounded. (Changed in v0.11.0: the stream client previously used timeout=None, which disabled all four.)

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.