Pub from GitHub Actions
GitHub Actions jobs read and publish your private packages with no stored secret: each job exchanges its own identity token for a Pub token that lasts 15 minutes. How it works on every provider is on Pub from CI.
1. Trust the issuer
GitHub.com is trusted already. For GitHub Enterprise Server, an Owner adds its issuer, https://<your host>/_services/token, as this organization's own.
2. Bind the repository
In the Control Room, open Organization, then CI access, Bind a repository, and choose GitHub Actions. The form asks for:
- Repository: owner/name, as in the repository's URL: acme/app.
- Owner: the user or organization that owns it: acme.
- Workflow file, optional: the workflow allowed to publish: .github/workflows/release.yml. A reusable workflow in another repository is owner/repo/.github/workflows/<file>.yml.
- Environment name, optional: a GitHub environment the job runs in, such as release. Its protection rules then gate every exchange.
- Ref pattern, optional: a branch, tag or pull request ref: refs/tags/v* or refs/heads/main.
Then grant the binding its packages with its Packages button: read, or read and publish.
3. Exchange in the job
Put your organization id, from the same Organization screen, in DARTASTIC_ORG_ID. This job publishes; for one that only reads, drop dart pub publish and grant the binding read only.
# .github/workflows/publish.yml: publish on a version tag
on:
push:
tags: ['v*']
permissions:
contents: read
id-token: write # lets the job request its OIDC token
jobs:
publish:
runs-on: ubuntu-latest
environment: release # optional: bind the environment too, so its reviewers gate publishing
env:
DARTASTIC_ORG_ID: <your organization id>
steps:
- uses: actions/checkout@v4
- uses: dart-lang/setup-dart@v1
- name: Exchange this job's identity for a 15-minute Pub token
run: |
set -euo pipefail
OIDC=$(curl -sS --fail-with-body \
-H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=https://dartastic.io" | jq -er .value)
RESP=$(curl -sS --fail-with-body -X POST https://api.dartastic.io/v1/ci/exchange \
-H "Authorization: Bearer $OIDC" -H "Content-Type: application/json" \
-d "{\"orgId\":\"$DARTASTIC_ORG_ID\"}") || { echo "$RESP" >&2; exit 1; }
export PUB_TOKEN=$(echo "$RESP" | jq -er .token)
dart pub token add https://pub.dartastic.io --env-var PUB_TOKEN
echo "::add-mask::$PUB_TOKEN"
echo "PUB_TOKEN=$PUB_TOKEN" >> "$GITHUB_ENV"
- run: dart pub get
- run: dart pub publish --force- The workflow needs permissions: id-token: write, or GitHub gives the job no token to exchange.
- Request the token with audience https://dartastic.io: the ACTIONS_ID_TOKEN_REQUEST_URL call in the snippet does that.
- ::add-mask:: keeps the Pub token out of the job's log.
When it is refused
The job's log shows the reason first, such as TRUSTED PUBLISHER REF MISMATCH. Every reason and what to do is on Pub from CI. GitHub Actions's own guide to its tokens is in its documentation.