Forgejo Actions | Security OpenID Connect

Forgejo Actions allows for workflows to request OpenID Connect compatible JWT ID tokens from Forgejo to exchange with external systems for credentials once a trust relationship between the external service and Forgejo is established.

These trust relationships can be configured in platforms such as AWS, GCP, and Azure, to make assertions on metadata in Forgejo ID tokens and exchange them for granularly scoped and short-lived access tokens.

Benefits

  • Eliminates the needs for secrets stored in Forgejo for compatible external systems
  • Access tokens generated by external systems are short-lived and expire automatically
  • Allows for granular control over authentication and authorization in external systems via assertions on metadata in the Forgejo ID tokens

High level flow

diagram

  1. A workflow run makes a request to Forgejo to generate an OIDC (OpenID Connect) ID token.
  2. Forgejo generates and returns an OIDC ID token that contains metadata about the run, repo, actor, and other information.
  3. The returned OIDC ID token can be exchanged with external platforms for short-lived credentials in these systems.
  4. The external platform will make a request to Forgejo for required metadata and keys to validate the received token.
  5. Forgejo responds to these requests with OIDC metadata, including where to find signing keys.
  6. The external platform uses this metadata, the keys, and a configured trust relationship to validate access and provide short-lived credentials if these validations pass.
  7. The workflow run receives these short-lived credentials, and can now use them to access the external platform.

Prerequisites

A trust relationship must be established in a compatible external system to allow for exchanging an ID token for short-lived credentials.

Setup instructions for some compatible external systems are as follows:

NOTE: Improperly configured trust relationships can allow for unintended access to third party systems. The sub, iss, and aud claims should be validated in the trust relationship at the minimum. Trust relationships should be configured to be as strict and narrowly scoped as is possible for your usecase.

Token structure

JWT tokens are comprised of three main components:

  1. A header which contains information about the signing algorithm and key used for signing the token
  2. A body or payload which contains
  3. A signature of the other two sections based on the signing algorithm used

These sections are Base64 URL encoded and joined by . to form the JWT. Examples of what the decoded sections look like follow below.

{
  "alg": "RS256",
  "kid": "iSrBtRq6EaN6605cSatQEnafFF82rOfm_22_d_V6ehQ",
  "typ": "JWT"
}
Body
{
  "actor": "user1",
  "aud": "exampleAudience",
  "event_name": "push",
  "exp": 1767217099,
  "iat": 1767213499,
  "iss": "https://example.com/api/actions",
  "nbf": 1767213499,
  "ref": "refs/heads/master",
  "ref_protected": "false",
  "ref_type": "branch",
  "repository": "user1/testing",
  "repository_owner": "user1",
  "run_attempt": "1",
  "run_id": "43",
  "run_number": "43",
  "sha": "76cb2978acb72029ac23277a6192eea1707c6a2c",
  "sub": "repo:user1/testing:ref:refs/heads/master",
  "workflow": "test.yml",
  "workflow_ref": "user1/testing/.forgejo/workflows/test.yml@refs/heads/master"
}

Signature

The format of the signature will depend on the algorithm used for signing the JWT ID token.

Reference

Requesting an ID token

OpenID connect must be enabled in workflow files at either the workflow or individual job level to be able to generate ID tokens from action runs.

When enabled, ACTIONS_ID_TOKEN_REQUEST_TOKEN and ACTIONS_ID_TOKEN_REQUEST_URL will be injected into the runners environment. A token can then be generated by running:

curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL&audience=exampleCustomAudience"

where the audience is an optional query param can be customized to match the value of the aud claim expected by the trust relationship in the external platform.

When unspecified, the aud value will default to the Forgejo instance’s URL with the repository owner as a suffix.

For example, https://example.com/user1.

Subject format

When the event that triggered the workflow is a pull_request the subject format is:

repo:[repository]:pull_request

where [repository] is the owner and repository name (e.g., forgejo/docs).

For all other events that trigger workflows, the subject format is:

repo:[repository]:ref:[ref]

where [ref] is the fully formed git reference (i.e. starting with refs/) associated with the event that triggered the workflow, if any (e.g. refs/heads/main)

Standard claims

The Forgejo ID token contains a number of well-known standard (also known as registered) claims as defined by RFC 7519.

ClaimSummaryDescription
audAudienceThe intended audience of the ID token. This can be configured using the audience URL param when requesting a token, and defaults to [forgejo instance URL]/[repository owner].
issIssuerThe issuer of the ID token. This will be in the format: [forgejo instance URL]/api/actions. For example, https://example.com/api/actions.
subSubjectThe subject claim for the token. See subject format for more details.
iatIssued atThe time that the token was issued.
expExpires atThe expiry time of the token.
nbfNot beforeThe time after which this token is valid.

Custom claims

The Forgejo ID token contains a number of custom claims that contain Forgejo specific information.

ClaimSummaryDescription
actorTriggering actorThe name of the user that triggered the workflow.
base_refBase referenceThe name of the base branch of the pull request (e.g. main). Only defined when a workflow runs because of a pull_request or pull_request_target event.
event_nameEvent nameThe name of the event that triggered the workflow (e.g. push).
refReferenceThe fully formed git reference (i.e. starting with refs/) associated with the event that triggered the workflow, if any (e.g. refs/heads/main).
ref_protectedIs reference protectedtrue if branch protections are configured for the ref that triggered the workflow run.
ref_typeReference typeThe type of the ref (branch or tag for example).
repositoryRepositoryThe owner and repository name (e.g. forgejo/docs).
repository_ownerRepository ownerThe repository owner’s name (e.g. forgejo)
run_attemptRun attemptAttempt number for this run, beginning at 1 and incrementing when the job is re-run.
run_idRun identifierA unique id for the current workflow run in the Forgejo instance.
run_numberRun numberA unique id for the current workflow run in the repository of the workflow.
shaGit SHAThe commit SHA that triggered the workflow. The value of this commit SHA depends on the event that triggered the workflow.
workflowWorkflow nameThe name of the workflow that triggered the run.
workflow_refWorkflow refRef path to the workflow, for example, owner/example-respository/.forgejo/workflows/test-workflow.yaml@refs/heads/main