> ## Documentation Index
> Fetch the complete documentation index at: https://conductorone-docs-ia-reframe-draft.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# GitLab CI integration

> Set up secretless authentication from GitLab CI to C1 using OIDC id_tokens.

GitLab CI/CD can issue OIDC tokens for each job via the `id_tokens` keyword. You exchange this token for a C1 access token using a curl command in your pipeline.

## Prerequisites

* A service principal with a GitLab CI federation trust. See [set up federation](/product/admin/service-principals/federation-setup) if you haven't created one yet. Use the **GitLab CI/CD** preset.
* The trust's **client ID** (for example `bright-eagle-55012@yourcompany.conductor.one/wfe`)

## Configure the pipeline

Add `id_tokens` to your job to request a GitLab OIDC token, then exchange it for a C1 access token:

```yaml theme={"theme":{"light":"css-variables","dark":"css-variables"}}
# .gitlab-ci.yml
deploy:
  id_tokens:
    C1_TOKEN:
      aud: yourcompany.conductor.one
  script:
    - >
      C1_ACCESS_TOKEN=$(curl -s -X POST
      "https://yourcompany.conductor.one/auth/v1/token"
      -d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange"
      -d "subject_token=$C1_TOKEN"
      -d "subject_token_type=urn:ietf:params:oauth:token-type:jwt"
      -d "client_id=bright-eagle-55012@yourcompany.conductor.one/wfe"
      | jq -r '.access_token')
    - >
      curl -s "https://yourcompany.conductor.one/api/v1/apps"
      -H "Authorization: Bearer $C1_ACCESS_TOKEN"
```

The `id_tokens` block tells GitLab to generate a signed JWT with your C1 tenant domain as the audience. The token is available as the `C1_TOKEN` environment variable within the job.

## CEL expression examples

When creating the federation trust, the CEL expression controls which GitLab CI jobs can authenticate.

### Restrict to a project

```go theme={"theme":{"light":"css-variables","dark":"css-variables"}}
claims.project_path == "acme/infra"
```

### Restrict to a project on protected refs only

```go theme={"theme":{"light":"css-variables","dark":"css-variables"}}
claims.project_path == "acme/infra" && claims.ref_protected == "true"
```

### Restrict to a specific branch

```go theme={"theme":{"light":"css-variables","dark":"css-variables"}}
claims.project_path == "acme/infra" && claims.ref == "main" && claims.ref_protected == "true"
```

### Common GitLab OIDC claims

| Claim                   | Example value | Description                          |
| :---------------------- | :------------ | :----------------------------------- |
| `project_path`          | `acme/infra`  | Full project path including group    |
| `project_id`            | `12345`       | Numeric project ID                   |
| `namespace_path`        | `acme`        | Group or user namespace              |
| `ref`                   | `main`        | Branch or tag name                   |
| `ref_protected`         | `true`        | Whether the ref is protected         |
| `ref_type`              | `branch`      | `branch` or `tag`                    |
| `pipeline_source`       | `push`        | What triggered the pipeline          |
| `environment`           | `production`  | Environment name (if used)           |
| `environment_protected` | `true`        | Whether the environment is protected |

## Security best practices for GitLab CI

<Warning>
  Keep "Require protected ref" enabled (`claims.ref_protected == "true"`) to ensure only jobs running on protected branches or tags can authenticate. For high-privilege access, also bind to a specific ref value. GitLab lets you set the audience per-job via `id_tokens` -- your tenant domain is used as the expected audience.
</Warning>
