Workload Identity Federation

Use Workload Identity Federation (WIF) with OIDC to let CI/CD workloads authenticate to Bright without storing a Bright project API key. The workload presents an OIDC ID token from its CI/CD provider. Bright validates the token against the project WIF configuration and returns a temporary Bright access token.

Use WIF for automation that can request OIDC ID tokens. Use a regular project API key for clients that cannot request OIDC ID tokens.

How it works

  1. Create a WIF configuration in the Bright project.
  2. Configure the CI/CD job to request an OIDC ID token.
  3. Send an RFC 8693 token exchange request to Bright. Bright accepts JSON and application/x-www-form-urlencoded requests.
POST /api/v1/token
Content-Type: application/json
{
  "grant_type": "urn:ietf:params:oauth:grant-type:token-exchange",
  "subject_token": "<oidc-id-token>",
  "subject_token_type": "urn:ietf:params:oauth:token-type:id_token",
  "resource": "https://app.brightsec.com/api/v1/projects/{projectId}"
}
  1. Bright validates the token issuer, audience, expiry, optional resource, and claim policy.
  2. Bright returns 200 OK with access_token in a response body.
  3. Use access_token as a Bright API key for API calls.
  4. Revoke the Bright access token per RFC 7009 when the job no longer needs it.
POST /api/v1/revoke
Content-Type: application/json
{
  "token": "<bright-access-token>",
  "token_type_hint": "access_token"
}

The resource field is optional. Use it when the same OIDC token could match WIF configurations in more than one Bright project.

The examples below use Acme sample values. Replace every sample value with values from your own CI/CD provider and Bright project.

Step 1: Create the WIF configuration in Bright

  1. In Bright, go to Projects and open the project.
  2. Select Settings > Federated Credentials. This page lists the project's federated credentials and contains the WIF configuration for OIDC-issued tokens.
Federated Credentials list
  1. Click Add credential.
Create federated credential dialog
  1. Select the CI/CD provider.
  2. Fill the Name, Allowed audiences, and provider-specific token claim fields.
  3. Click Create.

Use the row actions menu in the table to Disable (pause without deleting), Enable, or Remove an existing federated credential.

⚠️

A project can hold up to 20 federated credentials. Remove unused credentials before adding new ones if you hit the limit.

⚠️

Make sure every federated credential uniquely identifies one workload across all Bright projects. Constrain provider claims (for example, repository, branch, environment, or pipeline) tightly enough that only the intended workload matches.

If two credentials across different Bright projects could still accept the same token, the workload must include the resource parameter in the token-exchange request pointing to the exact target project. Ambiguous exchanges without resource are rejected.

Step 2: Configure the CI/CD provider

Use the section for your provider. Each provider example shows the Bright fields and the smallest CI/CD change needed to make an OIDC ID token available as OIDC_TOKEN.

GitHub Actions

GitHub Actions WIF settings

Configure these Bright fields:

Bright fieldDescription
IssuerGitHub OIDC issuer: https://token.actions.githubusercontent.com.
Allowed audiencesAudience requested by the workflow, for example https://github.com/acme-corp.
Organization or userGitHub owner of the repository.
RepositoryRepository name.
Branch / RefAllowed branch, tag, or ref, for example main.
Environment nameOptional GitHub Actions environment name.

Add id-token: write to the workflow and request the token in the job:

permissions:
  id-token: write
  contents: read

steps:
  - name: Request GitHub OIDC token
    run: |
      OIDC_TOKEN=$(curl -sS \
        -H "Authorization: Bearer ${ACTIONS_ID_TOKEN_REQUEST_TOKEN}" \
        "${ACTIONS_ID_TOKEN_REQUEST_URL}" | jq -r '.value')

This example uses GitHub's default audience (i.e. https://github.com/<org-or-user-name>). To use a custom audience, append &audience=<value> to ACTIONS_ID_TOKEN_REQUEST_URL and enter the same value in Allowed audiences.

GitLab CI/CD

GitLab CI/CD WIF settings

Configure these Bright fields:

Bright fieldDescription
IssuerGitLab OIDC issuer, for example https://gitlab.com.
Allowed audiencesAudience set in the job's id_tokens block.
Namespace / ProjectFull GitLab project path, for example acme-corp/payments-api.
Ref typeAllowed ref type, such as branch or tag.
RefAllowed branch or tag, for example main.

Request an ID token in the GitLab job:

deploy:
  id_tokens:
    BRIGHT_OIDC_TOKEN:
      aud: api://bright-security
  script:
    - OIDC_TOKEN="$BRIGHT_OIDC_TOKEN"

The aud value in .gitlab-ci.yml must match one value in Allowed audiences.

Bitbucket Pipelines

Bitbucket Pipelines WIF settings

Configure these Bright fields:

Bright fieldDescription
IssuerBitbucket workspace OIDC issuer.
Allowed audiencesBitbucket workspace audience, usually the workspace ARI.
Workspace UUIDBitbucket workspace UUID.
Repository UUIDBitbucket repository UUID.
Deployment environment UUIDOptional deployment environment UUID.

Enable OIDC in the pipeline step:

pipelines:
  default:
    - step:
        oidc: true
        script:
          - OIDC_TOKEN="$BITBUCKET_STEP_OIDC_TOKEN"

Copy the issuer, audience, workspace UUID, and repository UUID from Bitbucket repository settings.

CircleCI

CircleCI WIF settings

Configure these Bright fields:

Bright fieldDescription
Organization IDCircleCI organization UUID.
IssuerCircleCI organization issuer, for example https://oidc.circleci.com/org/<organization-id>.
Allowed audiencesUsually the CircleCI organization ID.
Project IDCircleCI project UUID.
VCS originOptional repository origin, for example github.com/acme-corp/payments-api.
VCS refOptional branch or tag ref, for example refs/heads/main.

Use CircleCI's OIDC token in the job:

jobs:
  bright:
    docker:
      - image: cimg/base:stable
    steps:
      - checkout
      - run: |
          OIDC_TOKEN="$CIRCLE_OIDC_TOKEN_V2"

Use $CIRCLE_OIDC_TOKEN_V2 when the WIF configuration checks VCS origin or VCS ref.

Custom OIDC

Custom OIDC WIF settings

Configure these Bright fields:

Bright fieldDescription
IssuerOIDC issuer URL.
Allowed audiencesAccepted token audience.
CEL ExpressionCEL expression matched against token claims.
Supported CEL policy syntax

Bright uses CEL expressions as claim policies for Custom OIDC claim checks and supports only the subset below. See the CEL language specification for the base language.

ItemSupported syntax
Inputssub, iss, aud, and claims
Nested claimsDot notation, for example claims.pipeline.id
Operators&&, ==, and in
FunctionstartsWith() with a non-empty string literal
Literal valuesStrings, booleans, integers, floats, and literal lists

Every expression must return a boolean and include a non-empty subject constraint: sub == "...", sub.startsWith("..."), or sub in ["...", "..."].

Unsupported syntax includes ||, !, !=, arithmetic operators, regex or matches functions, contains functions, bracket access, comprehensions, macros, and custom functions.

⚠️

Make the CEL policy expression specific to the exact workflow, repository, branch, tag, environment, project, or deployment context that should receive Bright access. Broad policy expressions can grant access to unrelated workloads that share the same issuer and audience.

Examples:

sub == "installation_id:12345"

sub.startsWith("repo:acme/web:") && claims.environment == "production"

sub in ["repo:acme/web", "repo:acme/api"] && claims.pipeline.id in [1001, 1002]

sub == "job:deploy" && claims.pipeline.protected == true && claims.score == 0.95

Request a token from your identity provider and assign it to OIDC_TOKEN:

OIDC_TOKEN="$(your-provider command that prints an OIDC ID token)"

Decode a sample token from a non-production run before saving the WIF configuration. Use exact claim names from the token payload in the CEL expression.

Step 3: Exchange the OIDC ID token for a Bright access token

After the provider step sets OIDC_TOKEN, exchange it with Bright in the same job:

set -euo pipefail

exchange_payload=$(jq -n \
  --arg token "${OIDC_TOKEN}" \
  --arg resource "${BRIGHT_BASE_URL}/api/v1/projects/${BRIGHT_PROJECT_ID}" \
  '{
    grant_type: "urn:ietf:params:oauth:grant-type:token-exchange",
    subject_token: $token,
    subject_token_type: "urn:ietf:params:oauth:token-type:id_token",
    resource: $resource
  }')

exchange_response=$(curl -sS --fail-with-body \
  -X POST "${BRIGHT_BASE_URL}/api/v1/token" \
  -H 'Content-Type: application/json' \
  --data "${exchange_payload}")

BRIGHT_TOKEN=$(jq -r '.access_token // empty' <<< "${exchange_response}")

if [[ -z "${BRIGHT_TOKEN}" ]]; then
  echo "OIDC exchange response did not include access_token." >&2
  exit 1
fi

Set BRIGHT_BASE_URL to your Bright URL, for example https://app.brightsec.com. Set BRIGHT_PROJECT_ID to the project ID that contains the WIF configuration. The resource field is optional, but it is recommended when the OIDC token could match WIF configurations in more than one Bright project.

Use BRIGHT_TOKEN as an API key in Bright API requests: Authorization: Api-Key ${BRIGHT_TOKEN}.

📘

When using MCP, the same token may be provided as a bearer token instead: Authorization: Bearer ${BRIGHT_TOKEN}

Step 4: Revoke the Bright access token

Revoke the temporary Bright token after the job finishes or when the job no longer needs Bright access:

revoke_payload=$(jq -n \
  --arg token "${BRIGHT_TOKEN}" \
  '{ token: $token, token_type_hint: "access_token" }')

curl -sS --fail-with-body \
  -X POST "${BRIGHT_BASE_URL}/api/v1/revoke" \
  -H 'Content-Type: application/json' \
  --data "${revoke_payload}"
⚠️

Do not print OIDC_TOKEN or BRIGHT_TOKEN to CI/CD logs.

Security recommendations

  • Restrict claim conditions to the specific repository and branch, tag, environment, project, or deployment environment that should authenticate.
  • Use a Bright-specific audience when the provider lets you choose the audience.
  • Request the OIDC token inside the job that needs it. Do not store OIDC tokens as CI/CD secrets.
  • Revoke the temporary Bright access token with POST /api/v1/revoke when the job no longer needs it.
  • Remove static project API keys that the OIDC flow replaces.
  • Disable or remove the WIF configuration when the CI/CD workflow no longer needs Bright project access.

Troubleshooting

Bright does not find a matching WIF configuration

Decode the OIDC ID token payload and compare the actual claims with the Bright project settings:

  • iss must match the configured issuer exactly.
  • At least one aud value must match an allowed audience.
  • Provider-specific fields or the Custom OIDC CEL policy must match the token claims.

Use the exact claim names and values from the token payload. Do not rely on provider UI labels when writing a CEL policy.

These checks apply to the OIDC ID token issued by the CI/CD provider.

Common provider checks:

  • GitHub Actions: workflow includes id-token: write.
  • GitLab CI/CD: job uses id_tokens, and aud matches Bright.
  • Bitbucket Pipelines: step includes oidc: true.
  • CircleCI: job uses $CIRCLE_OIDC_TOKEN_V2 when matching VCS origin or VCS ref.

The same token can match more than one project

Pass resource in the token exchange request:

{
  "resource": "https://app.brightsec.com/api/v1/projects/{projectId}"
}

Also narrow the WIF configuration. Match a specific repository, branch, tag, environment, deployment context, pipeline ID, or other stable claim that identifies the intended workload.

The Bright token should no longer be usable

Call POST /api/v1/revoke with the Bright access_token returned by /token:

{
  "token": "<bright-access-token>",
  "token_type_hint": "access_token"
}

Revocation applies to the temporary Bright access token only. It does not revoke the OIDC ID token issued by the CI/CD provider.

Learn more