Why does my GitHub OIDC token expire after 5 minutes when using Spacelift API?

Last updated: February 5, 2026

Context

When using GitHub Actions with OIDC authentication to access the Spacelift API, you may encounter token expiration errors after approximately 5 minutes, even though the Spacelift API documentation indicates tokens should be valid for 10 hours. This typically happens when there's a queue in your worker pool or when your workflow makes multiple API calls over an extended period.

Answer

The issue occurs because GitHub Actions OIDC tokens are intentionally short-lived (5 minutes) and are designed to be exchanged immediately for longer-lived credentials. The solution is to exchange your GitHub OIDC token for a Spacelift JWT token, which will be valid for the full 10 hours.

Instead of using the OIDC token directly, follow these steps to obtain a long-lived JWT token:

  1. Generate the GitHub OIDC token as usual:

    OIDC_TOKEN="$(curl -sS \
      -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
      "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=${SPACELIFT_OIDC_AUDIENCE}" \
      | jq -r .value)"
  2. Exchange the OIDC token for a Spacelift JWT token:

    JWT="$(curl -sS "${SPACELIFT_API_KEY_ENDPOINT}/graphql" \
      -H 'content-type: application/json' \
      -d "$(jq -nc --arg id "$SPACELIFT_API_KEY_ID" --arg secret "$OIDC_TOKEN" \
        '{query:"mutation($id:ID!,$secret:String!){apiKeyUser(id:$id,secret:$secret){jwt}}",
          variables:{id:$id,secret:$secret}}')" \
      | jq -r '.data.apiKeyUser.jwt')"
  3. Set the JWT token as your authentication method and unset the OIDC token:

    export SPACELIFT_API_TOKEN="$JWT"
    unset SPACELIFT_API_KEY_SECRET

Perform this exchange immediately before your first Spacelift API call, not at the beginning of your workflow. This ensures the OIDC token is still valid when exchanged, and the resulting JWT token will be valid for the full 10 hours as documented.

The key insight is that GitHub OIDC tokens are meant to bootstrap authentication by exchanging them for longer-lived credentials, not to be used directly for extended periods. This pattern is similar to how AWS credentials work with GitHub Actions OIDC.