> ## Documentation Index
> Fetch the complete documentation index at: https://docs.formal.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# OIDC

> Log in to the Formal Endpoint with OIDC or an API key

## Log In with OIDC

Use OIDC when the Formal Endpoint should authenticate as a machine identity. This flow avoids long-lived Formal credentials on the host.

The Endpoint exchanges source OIDC tokens for short-lived Formal credentials. It refreshes those credentials while the source can provide valid tokens.

<Steps>
  <Step title="Create an OIDC integration">
    Create an [OIDC integration](/docs/guides/integrations/oidc) for the workload. Map the integration to a Formal machine user.

    Configure a claim condition that restricts access to the intended workload. You can also configure an end-user email expression.

    Copy the integration ID after creating the integration.
  </Step>

  <Step title="Configure a token source">
    Add one token source to `~/.formal/config.toml`.

    <Tabs>
      <Tab title="AWS">
        Use AWS on hosts with credentials from the standard AWS credential chain.

        ```toml theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
        auth_mode = "oidc"

        [oidc]
        provider = "aws"
        integration_id = "integrationoidc_<id>"
        ```

        The Endpoint uses the standard AWS credential chain. Supported sources include environment variables, shared configuration, IRSA, EKS Pod Identity, and EC2 instance profiles.

        If no region is set in the environment or shared config, the Endpoint uses EC2 instance metadata.
      </Tab>

      <Tab title="Azure">
        Use Azure on AKS with Workload Identity or on Azure compute with managed identity.

        ```toml theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
        auth_mode = "oidc"

        [oidc]
        provider = "azure"
        integration_id = "integrationoidc_<id>"
        ```

        Set `AZURE_FEDERATED_TOKEN_FILE` for Workload Identity. Set `AZURE_CLIENT_ID` when using a user-assigned managed identity.

        Azure uses the fixed Azure Resource Manager audience. Your integration must validate that audience and the expected Azure identity claims.

        This token source does not support Azure DevOps Pipelines.
      </Tab>

      <Tab title="GCP">
        Use GCP on GKE, Compute Engine, or Cloud Run. You can also use Application Default Credentials for a service account.

        ```toml theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
        auth_mode = "oidc"

        [oidc]
        provider = "gcp"
        integration_id = "integrationoidc_<id>"
        ```

        On Google Cloud, the Endpoint requests a Google-signed ID token from the metadata server. Elsewhere, it uses Application Default Credentials.

        Supported credentials include service account keys, impersonated service accounts, and Workload Identity Federation with service account impersonation. User credentials from `gcloud auth application-default login` are not supported.

        On GKE, annotate the Kubernetes ServiceAccount with `iam.gke.io/gcp-service-account`. Google only issues ID tokens for IAM service accounts.

        Set the integration issuer to `https://accounts.google.com`. Restrict the claim condition to the expected service account:

        ```cel theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
        claims.email == "<SERVICE_ACCOUNT>@<PROJECT_ID>.iam.gserviceaccount.com" &&
        claims.email_verified == true
        ```
      </Tab>

      <Tab title="Environment variable">
        Use this source when your CI system provides an OIDC JWT.

        ```toml theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
        auth_mode = "oidc"

        [oidc]
        env = "GITLAB_OIDC_TOKEN"
        ```

        Request `oidc.formal.ai/<INTEGRATION_ID>` as the token audience.

        For providers with a fixed audience, also set the integration ID:

        ```toml theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
        auth_mode = "oidc"

        [oidc]
        env = "SPACELIFT_OIDC_TOKEN"
        integration_id = "integrationoidc_<id>"
        ```

        The Endpoint reads the variable when it starts. Start it from the same environment:

        ```bash theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
        export GITLAB_OIDC_TOKEN="<OIDC_JWT>"
        formal agent --headless
        ```

        <Warning>
          The Endpoint cannot renew a token supplied through an environment variable. Restart it with a new token before the current token expires.
        </Warning>
      </Tab>

      <Tab title="File">
        Use this source when a JWT is written to disk and rotated in place, such as a projected Kubernetes ServiceAccount token.

        ```toml theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
        auth_mode = "oidc"

        [oidc]
        file = "/var/run/secrets/formal/token"
        ```

        The Endpoint reads the file on every refresh, so it picks up rotated tokens without a restart. Set `integration_id` when the JWT audience is not `oidc.formal.ai/<INTEGRATION_ID>`.

        On Kubernetes, project a ServiceAccount token with the Formal audience:

        ```yaml theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
        volumes:
          - name: formal-token
            projected:
              sources:
                - serviceAccountToken:
                    path: token
                    audience: oidc.formal.ai/<INTEGRATION_ID>
                    expirationSeconds: 3600
        ```

        Mount the volume at `/var/run/secrets/formal` in the Endpoint container.

        Set the integration issuer to the cluster's ServiceAccount issuer. Formal must reach its discovery document or JWKS over public HTTPS. Find the issuer with:

        ```bash theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
        kubectl get --raw /.well-known/openid-configuration | jq -r .issuer
        ```

        The token `sub` is `system:serviceaccount:<NAMESPACE>:<SERVICE_ACCOUNT>`. Restrict the claim condition to the expected workloads:

        ```cel theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
        claims.sub.startsWith("system:serviceaccount:<NAMESPACE>:")
        ```
      </Tab>
    </Tabs>
  </Step>

  <Step title="Start the Formal Endpoint">
    Unset `FORMAL_API_KEY` because API key authentication takes precedence.

    Restart the desktop app, or start a headless agent:

    ```bash theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
    unset FORMAL_API_KEY
    formal agent --headless
    ```
  </Step>

  <Step title="Verify">
    Run these commands from another terminal:

    ```bash theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
    formal auth whoami
    formal ls
    ```

    `formal auth whoami` should show the integration's machine user. `formal ls` should show resources available to that identity.
  </Step>
</Steps>

## Log In with an API Key

Use an API key when the Formal Endpoint should skip the browser login flow. This works for human users and machine users.

<Steps>
  <Step title="Create an API key">
    Go to [API Keys](https://app.formal.ai/api-keys) and click **Create API Key**.

    To authenticate as a machine user, assign the key to that machine user.
  </Step>

  <Step title="Start the Formal Endpoint">
    ```bash theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
    FORMAL_API_KEY=<api-key> formal agent
    ```

    For a server without a GUI or keyring, add `--headless`:

    ```bash theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
    FORMAL_API_KEY=<api-key> formal agent --headless
    ```
  </Step>

  <Step title="Verify">
    ```bash theme={"languages":{"custom":["/languages/cel.json","/languages/rego.json"]}}
    formal auth whoami
    ```

    The output should show the human or machine user that owns the key.
  </Step>
</Steps>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.