v0.0.1 · system status
Open APIOpenAPI 3.1Zero token storage

Validate CI OIDC

Validate GitHub Actions or GitLab CI OIDC tokens with provider-specific claim assertions.

POST /v1/validate/ci-oidc Validate GitHub Actions or GitLab CI OIDC tokens with provider-specific claim assertions.

Validates an OIDC token issued by a CI provider against the matching built-in issuer profile and asserts provider-specific claims (repository, ref, project path, ref protection). Replaces the bespoke per-provider verification logic most teams write.

Built-in profiles

This endpoint applies a server-side issuer profile keyed off provider:

  • github_actions → issuer https://token.actions.githubusercontent.com, RS256
  • gitlab → issuer https://gitlab.com, RS256

You do not pass policy or issuer_profile_id here.

Request

body — application/json
Field Type Required Description
token string yes The OIDC ID token from the CI runner.
provider "github_actions" | "gitlab" yes Selects the issuer profile and the set of provider-specific claim checks.
expected_repository string no GitHub Actions only. Asserts the token's repository claim equals this value (e.g. "acme/api").
expected_ref string no GitHub Actions only. Asserts the token's ref claim equals this value (e.g. "refs/heads/main").
expected_project_path string no GitLab only. Asserts the token's project_path claim equals this value (e.g. "acme/api").
expected_ref_protected string no GitLab only. Asserts the token's ref_protected claim equals this string. Use "true" to require protected refs.

Response — 200

Same shape as /v1/validate/jwt: valid, statuses, findings[], summary. Provider-specific claim failures appear as findings alongside standard validation failures.

200 GitHub Actions token from the wrong repository
{
  "valid": false,
  "statuses": {
    "signature": "pass",
    "issuer": "pass",
    "audience": "pass",
    "algorithm": "pass",
    "time": "pass",
    "required_claims": "fail"
  },
  "findings": [
    {
      "code": "GITHUB_REPO_MISMATCH",
      "severity": "error",
      "message": "Token repository claim does not match expected_repository.",
      "evidence": {
        "token_repository": "fork/api",
        "expected_repository": "acme/api"
      }
    }
  ],
  "summary": "Token is NOT valid: repository mismatch."
}

Errors

ChannelCodeCause
400MALFORMED_TOKENToken is not a parseable JWT.
200, in findingsSIGNATURE_INVALIDToken signature failed against the provider JWKS.
200, in findingsGITHUB_REPO_MISMATCHrepository claim ≠ expected_repository.
200, in findingsGITHUB_REF_MISMATCHref claim ≠ expected_ref.
200, in findingsGITLAB_PROJECT_MISMATCHproject_path claim ≠ expected_project_path.
200, in findingsGITLAB_REF_PROTECTION_MISMATCHref_protected claim ≠ expected_ref_protected.
422CI_PROVIDER_UNKNOWNprovider is not one of the supported values.

Examples

GitHub Actions workflow that retrieves the token, validates it, and fails the build on rejection. Full version (with token masking and failure handling) in Examples and the CI · OIDC guide.

- name: Retrieve runner OIDC token
  id: token
  run: |
    JWT=$(curl -sSf \
      -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
      "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=api://jwtshield" \
      | python3 -c 'import json,sys; print(json.load(sys.stdin)["value"])')
    echo "::add-mask::$JWT"
    echo "jwt=$JWT" >> "$GITHUB_OUTPUT"

- name: Validate via JWTShield
  run: |
    curl -sSf -H "Authorization: Bearer ${{ secrets.JWTSHIELD_KEY }}" \
      -H "Content-Type: application/json" \
      -d '{
        "token": "${{ steps.token.outputs.jwt }}",
        "provider": "github_actions",
        "expected_repository": "${{ github.repository }}",
        "expected_ref": "${{ github.ref }}"
      }' \
      "$JWTSHIELD_URL/v1/validate/ci-oidc"

GitLab CI:

validate-oidc:
  stage: validate
  image: python:3.12-slim
  id_tokens:
    JWTSHIELD_OIDC_TOKEN:
      aud: "api://jwtshield"
  script:
    - |
      curl -sSf -H "Authorization: Bearer $JWTSHIELD_KEY" \
        -H "Content-Type: application/json" \
        -d "{\"token\":\"$JWTSHIELD_OIDC_TOKEN\",\"provider\":\"gitlab\",\"expected_project_path\":\"$CI_PROJECT_PATH\",\"expected_ref_protected\":\"true\"}" \
        "$JWTSHIELD_URL/v1/validate/ci-oidc"

See the CI · OIDC guide for the complete workflow including failure handling and protected-branch enforcement.