Sign in with a platform identity
Let a workload sign in with the identity token of the platform that runs it, such as GitHub Actions, GCP, Kubernetes, AWS, or Modal.
Let a workload sign in with a token from the
platform that runs it. There is no secret to store, copy, or rotate, because
the platform issues a new token for each run. Spiral checks each token
against a trust policy you attach to the workload, such as "GitHub Actions
runs from my-org/pipelines on main".
Prerequisites
- You created a workload and granted it a Project role.
- You have the Project
adminrole to manage the trust policies of the workload. A trust policy lets the matching job act as the workload, with all of the workload's grants. - The workload runs on a platform that issues OpenID Connect tokens.
Add a trust policy
Add a trust policy for the platform. This policy admits the
nightly-curation workload's GitHub Actions runs from one repository, on the
main branch only:
spiral workloads trust add work_01GHI --github my-org/pipelines \
--condition ref=refs/heads/mainThen set SPIRAL_WORKLOAD_ID where the job runs. The CLI and the SDKs find
the platform token and exchange it for you:
export SPIRAL_WORKLOAD_ID=work_01GHIThe platform token's audience must match the workload's trust policy. When a
policy omits an audience, Spiral expects
https://auth.spiraldb.com/oauth/token; automatic token acquisition in the
CLI and SDKs requests that value on platforms that allow it.
Studio's Add trust policy form prefills a workload-specific audience,
such as https://auth.spiraldb.com/workloads/work_01GHI. Copy the value shown
in Audience into your provider's token request. GitHub Actions jobs need
id-token: write to request a token. The form's optional named fields let you constrain a Git ref,
environment, repository ID, workflow, reusable workflow, actor, or other
GitHub OIDC claims.
When you choose an explicit audience, obtain the platform token with that
audience and provide it as SPIRAL_OIDC_PROVIDER_TOKEN alongside
SPIRAL_WORKLOAD_ID. This uses your token directly instead of automatic
platform-token acquisition. A provider with a fixed audience, such as Modal,
keeps that value on the policy.
| Platform | Trust policy options | Token source |
|---|---|---|
| GitHub Actions | --github OWNER/REPO | Detected automatically. The job needs the id-token: write permission. |
| GCP | --gcp-service-account UNIQUE_ID, with the numeric uniqueId of the service account | The metadata server, detected automatically. |
| Kubernetes | --kubernetes-service-account NAMESPACE/NAME --issuer URL, with the issuer of the cluster's service-account tokens | A projected service-account token with the audience above. Set SPIRAL_K8S_SA_TOKEN_PATH to the token file. |
| AWS | --aws-role ROLE_ARN --issuer URL. See AWS roles. | STS GetWebIdentityToken, detected automatically. |
| Modal | --modal-workspace WORKSPACE_ID. Modal tokens cannot name the audience above, so the policy accepts the audience oidc.modal.com. | MODAL_IDENTITY_TOKEN, detected automatically. |
| Any OIDC issuer | --issuer URL --condition CLAIM=VALUE | Set SPIRAL_OIDC_PROVIDER_TOKEN to the token. |
Add --condition CLAIM=VALUE to require more claims, as the example does
with ref. Every trust policy names at least one claim, because an issuer
alone would admit every token it signs, including tokens for other people's
jobs. The issuer must publish OpenID Connect discovery at a public HTTPS URL.
Its jwks_uri must also use HTTPS and resolve only to public addresses.
Spiral checks DNS answers when connecting, refuses redirects and private or
special-use addresses, and limits each fetched document to 64 KiB and five
seconds. A private Kubernetes issuer needs publicly reachable discovery and
signing-key documents before hosted sign-in can verify its tokens.
If SPIRAL_WORKLOAD_ID is set and the client finds no platform token,
sign-in fails with a diagnostic instead of prompting. See
How your code finds credentials.
Verify the trust policy
List the workload's trust policies:
spiral workloads trust ls work_01GHIRun the workload, then check the principal that it signs in as:
spiral whoamiThe command shows the workload ID. Remove a trust policy with
spiral workloads trust rm.
Exchange a platform token over HTTP
A client without the SDK sends the platform token to the token endpoint
itself, as a JWT bearer grant
(RFC 7523). assertion is the
platform token, and client_id is the workload ID, which is also the
workload's OAuth client ID:
curl -X POST https://auth.spiraldb.com/oauth/token \
-d grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer \
-d client_id=work_01GHI \
-d assertion="$PLATFORM_TOKEN"The response contains an access_token for the Spiral API.
AWS roles
An AWS role proves its identity with a token from STS GetWebIdentityToken.
AWS issues these tokens only after you enable outbound identity federation for
the account. The role also needs permission to request the token.
-
Enable outbound identity federation for the AWS account:
aws iam enable-outbound-web-identity-federationThe response contains the issuer URL of the account. To show it again, run
aws iam get-outbound-web-identity-federation-info. -
Add this statement to a policy of the role. It lets the role request tokens only for the Spiral authorization server:
{ "Effect": "Allow", "Action": "sts:GetWebIdentityToken", "Resource": "*", "Condition": { "ForAllValues:StringEquals": { "sts:IdentityTokenAudience": "https://auth.spiraldb.com/oauth/token" } } } -
Add a trust policy to the workload. Use the issuer URL from step 1 and the ARN of the role:
spiral workloads trust add work_01GHI \ --aws-role arn:aws:iam::123456789012:role/MyDeployRole \ --issuer https://4f9c2a7e-1b3d-4e5f-8a6b-7c8d9e0f1a2b.tokens.sts.global.api.aws
The policy matches the sub claim, which is the role ARN, not the ARN of the
role session, so it accepts every session of the role.
To see the token that the role presents, run this command where the workload runs. Then decode the token in the response:
aws sts get-web-identity-token \
--audience https://auth.spiraldb.com/oauth/token \
--signing-algorithm RS256If the command fails with AccessDenied, the role does not have the
permission from step 2.
Troubleshooting
| Problem | Cause | Fix |
|---|---|---|
SPIRAL_WORKLOAD_ID is set but no workload identity provider detected a valid token | The platform did not supply a token. | Check the token source in the platform table. For GitHub Actions, add the id-token: write permission. |
SPIRAL_OIDC_PROVIDER_TOKEN is set but SPIRAL_WORKLOAD_ID is not. | A custom OIDC token needs the workload ID. | Set SPIRAL_WORKLOAD_ID. |
| The token is rejected | No trust policy matches the issuer and claims. | Compare the decoded platform token with spiral workloads trust ls. |
Where next: the Workloads API lists the trust policy operations.