Chapter 20Lesson 01~185 minutes

Secrets, Configuration Variables, GITHUB_TOKEN, Fine-Grained Permissions, and OIDC: Concepts, Architecture, and Mental Model

Chapter 19 governed where an artifact may be deployed. Chapter 20 governs the identities and configuration that make those workflows powerful: which values are public configuration, which are confidential, which token acts on GitHub, and when a cloud should trust a short-lived identity instead of a stored key.

SecretsVariablesGITHUB_TOKENLeast privilegeOIDC

Learning objectives

  • Classify repository data, configuration variables, environment variables, and Actions secrets by sensitivity, scope, storage, and log behavior.
  • Explain how repository, environment, and organization scopes affect secret/variable availability and precedence.
  • Trace the lifecycle and repository boundary of GITHUB_TOKEN, then reason about workflow-level and job-level permissions.
  • Choose between GITHUB_TOKEN, a GitHub App installation token, and a fine-grained personal access token when GitHub automation crosses resource boundaries.
  • Explain OIDC issuance, aud/sub claims, cloud trust policy, and the post–July 15, 2026 immutable default subject format.

Availability: The mandatory path targets GitHub.com and a disposable public personal repository. Repository secrets/variables and GITHUB_TOKEN are available without a paid plan. Environment-scoped configuration depends on the environment features from Chapter 19. Organization-wide sharing is optional and policy/plan dependent. OIDC itself does not require buying a cloud service; this chapter uses a provider-neutral trust-policy simulation.

1. The practical problem: configuration and authority look similar in YAML

A workflow often contains four visually similar substitutions: a normal repository value such as a test fixture path, a configurable deployment region, a confidential credential, and an authorization token. Treating them as interchangeable creates two opposite failures. Teams either hide harmless configuration in secrets—making operations hard to inspect—or expose authority as ordinary data—making compromise much easier.

The safer question is not “where can I put this string?” It is what power does the value convey, who should be able to read or change it, when should it exist, and what evidence proves that the workflow received only the authority it needed?

2. Four data classes before credentials

Data class Example Visibility/lifecycle Use when
Repository file config/test-policy.json Versioned, reviewable, readable to repository readers. The value is not secret and should change through code review.
Configuration variable vars.CH20_MODE Hosted configuration; not masked; repository/environment/organization scope. The value is operational configuration and may change independently of source.
Environment variable env.MODE / shell variable Exists in workflow/job/step process context; may originate from files, variables, or secrets. A process needs a value at execution time; this is a transport mechanism, not a secrecy class.
Actions secret secrets.CH20_DEMO_SECRET Encrypted hosted value; plaintext is not returned by listing APIs/CLI; log redaction is best-effort. Disclosure would matter: token, key, password, webhook secret, or synthetic secret used to teach the boundary.

A configuration variable is deliberately not secret: GitHub may show it in UI/API and a workflow may print it. An environment variable is just a process-level name/value; putting a secret into env does not make the value non-secret, and putting public text into secrets does not make it sensitive.

3. Scope answers “which automation receives the value?”

Scope Typical owner Availability rule Important boundary
Repository Repository administrator / appropriately permitted collaborator Workflows in that repository. Broadest repository-local choice; anyone able to modify trusted workflow code may be able to cause the workflow to use it.
Environment Repository environment administrator/policy Only jobs that reference that environment, after applicable environment gates. Useful when production authority should appear only after the production gate is reached.
Organization Organization owner / delegated role Selected repositories according to org policy; plan/visibility restrictions can apply. Centralizes reuse, but increases blast radius if access policy is too broad.

When the same secret or variable name is defined at multiple supported scopes, the narrower scope takes precedence: environment over repository over organization. Reason from the job's effective scope rather than assuming the organization value wins. Environment-scoped values are intentionally tied to a job's environment transition. Also remember timing: hosted configuration can be evaluated at different stages, so do not design a policy that depends on a late environment variable changing an expression that GitHub already evaluated earlier.

4. GITHUB_TOKEN: identity created for the job

When a workflow job starts, GitHub creates a unique GITHUB_TOKEN. It is a GitHub App installation access token for the repository containing the workflow. It is not your personal login token, and it is not a cross-organization master key. The token expires with the job (subject to the platform's effective maximum lifetime) and its permissions are the intersection of repository/org policy, workflow/job permissions, and event-specific restrictions.

That means authentication and authorization remain separate. A request may prove “this is the workflow's GitHub App token” yet still receive 403 because issues: write or another permission was not granted.

permissions: {}

jobs:
  inspect:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      issues: read

Setting an explicit permission set also makes absence meaningful: configurable permissions not granted are effectively unavailable to that job. This is much easier to audit than relying on repository defaults.

5. The event can reduce what a token or secret may do

Trust is event-dependent. A pull request from a fork contains code and metadata controlled outside the base repository. GitHub therefore withholds Actions secrets from ordinary fork pull-request workflows and restricts the token unless administrators intentionally choose riskier settings. Dependabot-triggered events are similarly treated as untrusted for Actions secrets: the default GITHUB_TOKEN is read-only and Dependabot secrets are a separate secret class.

Do not “fix” these failures by switching to a more privileged event and immediately executing untrusted code. The correct design is to separate untrusted validation from privileged follow-up, keep write authority out of code paths the contributor controls, and make the privilege transition explicit.

6. When GITHUB_TOKEN cannot reach the resource

Credential Identity Best fit Primary risk
GITHUB_TOKEN Repository-installed GitHub App for current workflow job Most same-repository Actions operations. Granting more permissions than the job needs.
GitHub App installation token App installation, independent of a human account Long-lived organization automation, multi-repository integrations, policy-driven bots. App private-key/install permissions must be governed; installation token still needs least privilege.
Fine-grained PAT A specific user, constrained by selected resources/permissions/expiration Short-lived user-context scripts or API gaps where an App is disproportionate. Automation lifecycle depends on the human account; token must expire and remain minimal.

GitHub currently recommends fine-grained PATs instead of classic PATs where possible, but also recommends a GitHub App for long-lived organization integrations. A token never grants a human permissions they do not already possess.

7. OIDC replaces a stored cloud key with a short-lived assertion

OIDC changes the direction of trust. Instead of storing a cloud access key in GitHub, a job with id-token: write can request a signed JWT from GitHub's OIDC issuer. The cloud or identity provider validates that JWT against a trust policy and, if the claims match, exchanges it for its own short-lived credential.

Concept / workflow diagram
flowchart TD
  E[Repository event] --> J[Actions job]
  V[vars / env] --> J
  S[Actions secret] --> J
  J --> G[GITHUB_TOKEN: GitHub repository API]
  J --> O[GitHub OIDC issuer]
  O -->|signed JWT: iss aud sub claims| P[Cloud trust policy]
  P -->|short-lived provider credential| C[Cloud resource]
  J --> L[Logs / artifacts]

The GitHub token and the OIDC token solve different trust problems. GITHUB_TOKEN authorizes GitHub operations. The OIDC JWT proves workload identity to an external verifier. id-token: write allows requesting the OIDC token; it does not itself grant write access to GitHub or to a cloud account.

Important claims include iss (issuer), aud (intended audience), sub (subject), repository_id, repository_owner_id, ref, environment, and workflow identity claims. The provider must bind trust tightly enough that an unintended repository, branch, environment, or reusable workflow cannot impersonate the intended deployment workload.

8. Current GitHub.com OIDC subjects use immutable repository identity for new repositories

As of this chapter's August 2026 verification, GitHub.com repositories created after July 15, 2026 use an immutable default sub that contains the owner and repository numeric IDs. That prevents a deleted/recycled name from silently inheriting the same default subject. GitHub Enterprise Server is excluded from this rollout.

# Historical branch-oriented default:
repo:octo-org/octo-repo:ref:refs/heads/main

# New GitHub.com default for a repository created after 2026-07-15:
repo:octo-org@123456/octo-repo@456789:ref:refs/heads/main

# If the job references an environment, the subject context is the environment:
repo:octo-org@123456/octo-repo@456789:environment:production

Do not invent a subject that concatenates both mutually exclusive default contexts. If the subject is environment-oriented, bind the branch/ref with another claim where the provider supports it or enforce the branch before the environment job. Always inspect the actual token/official subject format before deploying a provider trust policy.

9. Read-only inspection before changing anything

These commands reveal configuration metadata without retrieving secret plaintext. They also show the repository's default workflow-token policy; that repository default is not the same thing as proving the effective permissions of a specific job.

REPO="OWNER/REPO"

gh secret list -R "$REPO" --json name,updatedAt
gh variable list -R "$REPO" --json name,value,updatedAt

gh api   -H "X-GitHub-Api-Version: 2026-03-10"   "repos/$REPO/actions/permissions/workflow"

For a job's effective authority, combine configuration inspection with a controlled API operation and preserve the resulting HTTP status. That is the pattern used in Lesson 2.

Security boundary: Never print secrets.GITHUB_TOKEN, OIDC request tokens, PATs, GitHub App private keys, or a whole secrets/github context. GitHub masks recognized secret values, but transformations can defeat redaction. A credential leak response begins with revocation/rotation, not with editing the old log or Git history.

Knowledge checks

Why is env.MY_VALUE not a security classification?

What is GITHUB_TOKEN actually authenticating as?

A fork PR cannot read a repository Actions secret. Is that a bug to work around with a privileged event?

What does id-token: write authorize?

Why can a 2026 trust policy copied from an older example be wrong?

Lesson summary

Workflow security starts by separating data from authority. Repository files and variables are inspectable configuration; secrets carry confidential values; GITHUB_TOKEN is a short-lived repository identity; GitHub Apps and fine-grained PATs cover different GitHub access cases; and OIDC lets an external provider trust an attested workflow context without storing a long-lived cloud key.

Next: Lesson 2 makes these boundaries observable in a disposable repository: one secret, one variable, one allowed metadata read, one intentionally denied write, and a provider-neutral OIDC capability exercise.

Next lesson

Secrets, Configuration Variables, GITHUB_TOKEN, Fine-Grained Permissions, and OIDC: Guided Hands-On Workflow and Core Operations

Further reading

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.