STS
RFC 8693 token exchange for workload identity federation, OIDC provider management, and discovery.
Scope#
The Equinix Security Token Service exchanges an OIDC ID token from a registered identity provider for a short-lived Equinix access token. A workload in a CI system or a cloud runtime can then call the Equinix APIs without a stored client secret.
| Accessor | Covers | Authentication |
|---|---|---|
tokens() | Token exchange, and the access policies a subject token is granted | None |
discovery() | JWKS and OpenID configuration | None |
oidcProviders() | Registered OIDC providers: list, create, update, delete, suspend, resume | Equinix credentials |
The SDK sends STS requests to https://sts.eqix.equinix.com.
Token exchange#
import com.eqixiac.equinix.STS;
import com.eqixiac.equinix.sts.model.StsScope;
import com.eqixiac.equinix.sts.model.StsToken;
import com.eqixiac.equinix.sts.model.json.creators.TokenRequest;
STS sts = STS.withoutCredentials();
StsToken token = sts.tokens().generate(new TokenRequest()
.grantType("urn:ietf:params:oauth:grant-type:token-exchange")
.subjectToken(oidcIdToken)
.subjectTokenType("urn:ietf:params:oauth:token-type:id_token")
.scope(StsScope.accessPolicy("access-policy-id", "idp-name")));
System.out.println(token.getTokenType() + ", expires in " + token.getExpiresIn() + " s");The request is sent as application/x-www-form-urlencoded with the RFC 8693 field names grant_type, subject_token, subject_token_type and scope. The TokenRequest schema in the STS specification uses camelCase names, which the live service rejects and which release 3.0.0 sent. The SDK reads the snake_case response fields the service returns (access_token, expires_in, token_endpoint, jwks_uri).
Scopes#
StsScope builds the scope forms the live service accepted on 2026-11-11.
| Factory | Scope form |
|---|---|
StsScope.accessPolicyErn(ern) | An access-policy ERN |
StsScope.accessPolicy(policyId, idpName) | accesspolicy:<id>:idp:<name> |
StsScope.roleAssignments(...) | roleassignments: form |
StsScope.projectPolicies(...) | projectpolicies: form |
StsScope.principalPolicy(...) | principalpolicy: form |
The success shape of the exchange was not re-verified live on 2026-11-11, because the test account had no registered identity provider to issue a subject token. The request format, the discovery documents and the error shape {"error", "error_description"} were verified.
Use the token#
Any client accepts the token through a BearerTokenProvider. A provider built from a supplier repeats the exchange when the token nears expiry or after a 401, as the block under Authentication shows.
Discovery#
import com.eqixiac.equinix.sts.model.Jwks;
import com.eqixiac.equinix.sts.model.OpenIdConfiguration;
OpenIdConfiguration configuration = sts.discovery().getOpenIdConfiguration();
Jwks keys = sts.discovery().getJwks();
System.out.println(configuration.getIssuer() + " " + configuration.getTokenEndpoint());A service that receives Equinix STS tokens uses the JWKS to verify their signatures.
OIDC providers#
import com.eqixiac.equinix.sts.model.json.OidcProviderPage;
STS admin = new STS(credentials);
OidcProviderPage providers = admin.oidcProviders().list("organization-id");
admin.oidcProviders().suspend("organization-id", "provider-id");
admin.oidcProviders().resume("organization-id", "provider-id");suspend stops the exchange of a provider's tokens and keeps the registration, which suits the case where the signing keys of a CI system may be compromised.
Federation design notes#
- An access policy scoped to the projects and actions of one workload limits what an exchange can grant to that scope, whatever scope the workload requests.
- An access policy should constrain the subject claims to one repository, branch or service account. Without such a constraint, any token from the identity provider can obtain access.
- The exchanged token expires after
expires_inseconds and should not be cached beyond that time.