Skip to content

OIDC concepts

This page explains how workload identity federation works in Thalassa Cloud — the concepts, vocabulary, and access control model. Read this before configuring identity providers or federated identities.

The problem OIDC solves

CI/CD pipelines and other automated systems need to call the Thalassa Cloud API. The traditional approach is to create service account access credentials (a client ID and secret) and store them in GitHub Secrets, GitLab CI variables, or a vault.

That works, but long-lived secrets in CI are risky: they can leak through logs, forked PRs, or misconfigured workflows, and they require manual rotation.

Workload identity federation removes the secret from CI. Instead, your pipeline receives a short-lived OIDC ID token from the CI platform (GitHub, GitLab, etc.). Thalassa Cloud validates that token and, if it matches your rules, returns a bearer access token that acts as a specific service account.

In one sentence: your CI job proves who it is with a JWT; Thalassa Cloud checks that proof and issues a token that impersonates a service account you configured.

How the flow works

    sequenceDiagram
    participant CI as CI platform
    participant TC as Thalassa Cloud API
    participant SA as Service account

    CI->>CI: Job starts, issues OIDC ID token
    CI->>TC: POST /oidc/token (ID token + org + SA ID)
    TC->>TC: Verify signature (JWKS), issuer, audience, claims
    TC->>CI: Bearer access token (short-lived)
    CI->>TC: API call with bearer token
    TC->>SA: Evaluate SA roles + token scopes
    TC->>CI: Response
  
  1. CI platform issues an ID token — A signed JWT that describes the job (repository, branch, environment, etc.).
  2. Pipeline exchanges the token — Sends the ID token to https://api.thalassa.cloud/oidc/token.
  3. Thalassa Cloud validates and matches — Checks the signature, issuer, audience, and claim rules on the federated identity.
  4. Bearer token is returned — A short-lived Thalassa Cloud access token scoped to the service account.
  5. API calls use the bearer token — Same as any other Thalassa Cloud API authentication.

The cast of characters

ComponentWhat it isWhere you configure it
CI platformGitHub Actions, GitLab CI, or another OIDC issuerYour pipeline YAML
Identity providerTrust relationship with an external OIDC issuer (issuer URL + JWKS)IAM → Identity Providers
Service accountNon-human identity with IAM rolesIAM → Service Accounts
Federated identityRules linking an identity provider to a service accountService account → Federated Identities
OIDC ID tokenShort-lived JWT from the CI platformIssued automatically by CI
Bearer access tokenShort-lived Thalassa Cloud token after exchangeReturned by /oidc/token

Why two configuration steps?

Engineers often ask why there is both an identity provider and a federated identity. They serve different purposes:

StepScopePurpose
Identity providerOrganisation-wide, reusable“We trust tokens signed by GitHub” — defines the issuer and how to verify signatures (JWKS)
Federated identityPer service account“Only repo:myorg/myapp:ref:refs/heads/main may impersonate SA ci-deploy” — defines who can exchange tokens and what scopes the result gets

One identity provider (e.g. github-actions) can back many federated identities on different service accounts, each with different claim matching rules.

OIDC federation vs access credentials

Access credentialsOIDC workload federation
Secret in CI?Yes — client ID and secret stored in secrets/variablesNo — only organisation ID and service account ID (not secrets)
Token lifetimeLong-lived until revokedShort-lived (default 1 hour, configurable)
RotationManual — create new credentials, update CI, revoke oldAutomatic — each job gets a fresh ID token
Blast radius if leakedHigh — works from anywhere until revokedLimited — only jobs matching your claim rules can exchange
Setup complexityLowHigher — identity provider + federated identity + pipeline config
AuditabilityHarder to tie API calls to a specific repo/branchClaim rules tie access to repository, branch, or environment
Recommended forLocal dev, quick tests, legacy integrationsProduction CI/CD (GitHub Actions, GitLab CI, etc.)

For production pipelines, use OIDC federation. Use access credentials when you need a simple static secret for a system that cannot obtain OIDC ID tokens (for example, a long-running service outside CI).

See Service Accounts for creating and managing access credentials.

Three layers of access control

After a successful token exchange, three separate mechanisms control what the pipeline can do. Confusing these is a common source of “token exchange worked but API call failed” issues.

LayerConfigured onControls
1. Token matchingFederated identityWho is allowed to exchange a token (subject claim, additional claims, audience)
2. API scopesFederated identity (and optionally at exchange time)What the bearer token itself is allowed to do (api:read, api:write, containerRegistry:pull, etc.)
3. IAM rolesService accountWhat the service account can do in Thalassa Cloud (RBAC roles, IAM policy bindings)

All three must allow an action for it to succeed:

  1. The CI job’s ID token must match the federated identity rules.
  2. The returned bearer token must include the required API scope.
  3. The service account must have the IAM permission for the resource and action.

API scopes can narrow access below what the service account’s IAM roles allow, but they cannot grant permissions the service account does not have.

Glossary

TermMeaning
OIDCOpenID Connect — a standard for identity tokens (JWTs) issued by an identity provider
JWTJSON Web Token — a signed, base64-encoded token with three parts: header, payload, signature
ID tokenThe JWT your CI platform issues to the job. This is what you send to /oidc/token
Bearer tokenThe Thalassa Cloud access token returned after a successful exchange. Use this for API calls
Issuer (iss)The OIDC provider that signed the token (e.g. https://token.actions.githubusercontent.com). Must match the identity provider configuration exactly
Subject (sub)Primary claim identifying the caller. Format varies by provider — this is what federated identity matching uses
Audience (aud)Who the ID token is intended for. Must match Trusted Audiences on the federated identity and what you configure in your CI pipeline
JWKSJSON Web Key Set — public keys used to verify the ID token signature. Fetched automatically from the issuer’s well-known configuration
Token exchangeThe process of trading an external OIDC ID token for a Thalassa Cloud bearer token via POST /oidc/token
ImpersonationActing as a service account using a bearer token obtained through federation

Decode your ID token

When claim matching fails, decode the ID token to see what the CI platform actually issued:

# Print the JWT payload (middle segment) as JSON
echo "${OIDC_TOKEN}" | cut -d. -f2 | base64 -d 2>/dev/null | jq

On macOS, if base64 -d fails, use base64 -D instead.

Compare the output to your federated identity configuration:

JWT fieldFederated identity setting
issIdentity provider issuer URL
audTrusted Audiences
subSubject claim
Other fields (repository, ref, environment, etc.)Additional claims

Example: GitHub Actions token

A token from a push to main on myorg/myrepo might contain:

{
  "iss": "https://token.actions.githubusercontent.com",
  "sub": "repo:myorg/myrepo:ref:refs/heads/main",
  "aud": "https://api.thalassa.cloud",
  "repository": "myorg/myrepo",
  "repository_owner": "myorg",
  "ref": "refs/heads/main"
}

A matching federated identity would use:

  • Trusted Audiences: https://api.thalassa.cloud
  • Subject claim: repo:myorg/myrepo:ref:refs/heads/main

And the GitHub workflow must request the token with the same audience (see GitHub Actions and GitLab CI guides).

Project context

Many Thalassa Cloud resources are scoped to a project. When calling project-scoped APIs, set the active project using one of:

  • X-Project-Identity header
  • OIDC project claim on the bearer token (if configured)
  • ?project= query parameter

Without a project context, only organisation-scoped resources and organisation-level permissions apply. See IAM policy concepts for how project context affects permission checks.

Related documentation