GitHub Action
The kanoniv/auth-action GitHub Action issues delegation tokens for CI/CD pipelines. Every pipeline run gets a scope-confined, time-bounded token - not a long-lived secret.
Quick Start
- uses: kanoniv/auth-action@v1
with:
root_key: ${{ secrets.KANONIV_ROOT_KEY }}
scopes: deploy.staging,test.run
ttl: 4hHow It Works
The action runs as a composite step:
- Installs
kanoniv-authfrom PyPI (version configurable) - Loads the root key - either from the
root_keysecret (direct mode) or via GitHub OIDC token exchange (OIDC mode) - Issues a delegation token with the specified scopes and TTL using
delegate() - Verifies the token works by calling
verify()on the first scope - Sets
KANONIV_TOKENas an environment variable for all subsequent steps - Exports
tokenandagent_didas step outputs
Subsequent steps can use the token directly:
- run: kanoniv-auth verify --scope deploy.staging
- run: kanoniv-auth exec --scope deploy.staging -- ./deploy.shInputs
| Input | Required | Default | Description |
|---|---|---|---|
root_key | No* | - | Base64-encoded root private key |
oidc | No | false | Use GitHub OIDC for ephemeral root key |
api_key | No | - | Kanoniv Cloud API key (required if oidc: true) |
scopes | Yes | - | Comma-separated scopes |
ttl | No | 4h | Token time-to-live |
version | No | 0.1.0 | kanoniv-auth package version to install |
post_audit | No | false | Post delegation audit comment on PR |
*Either root_key or oidc must be provided.
Outputs
| Output | Description |
|---|---|
token | The delegation token (base64url-encoded) |
agent_did | The delegated agent's did:agent: identifier |
The token is also set as the KANONIV_TOKEN environment variable, available to all subsequent steps in the job.
Direct Mode
Use a root key stored as a GitHub secret. This is the simplest setup.
steps:
- uses: kanoniv/auth-action@v1
with:
root_key: ${{ secrets.KANONIV_ROOT_KEY }}
scopes: deploy.staging
ttl: 2hGenerate the root key and base64-encode it:
kanoniv-auth init
cat ~/.kanoniv/root.key | base64
# Add the output as KANONIV_ROOT_KEY secret in GitHub repo settingsINFO
The root key is a JSON file containing the Ed25519 private key. Base64 encoding is required because GitHub secrets are strings.
OIDC Mode
OIDC mode exchanges a GitHub OIDC token for an ephemeral root key from Kanoniv Cloud. No long-lived root key secret needed - the root key is generated per-run and never stored.
permissions:
id-token: write # Required for OIDC
steps:
- uses: kanoniv/auth-action@v1
with:
oidc: "true"
api_key: ${{ secrets.KANONIV_API_KEY }}
scopes: deploy.staging,test.run
ttl: 4hThe OIDC flow:
- GitHub issues an OIDC token with audience
kanoniv - The action sends this token to
https://api.kanoniv.com/v1/auth/oidc/root-key - Kanoniv Cloud verifies the GitHub OIDC token and returns an ephemeral root key
- The action uses this root key to issue the delegation token
WARNING
OIDC mode requires a Kanoniv Cloud account. The api_key input authenticates the OIDC token exchange. You must also set permissions: id-token: write in your workflow - without it, the ACTIONS_ID_TOKEN_REQUEST_URL environment variable is not available and the action will fail.
PR Audit Comments
With post_audit: "true", the action posts a comment on pull requests showing the delegation details. This only runs when the triggering event is a pull_request.
- uses: kanoniv/auth-action@v1
with:
root_key: ${{ secrets.KANONIV_ROOT_KEY }}
scopes: deploy.staging,test.run
ttl: 4h
post_audit: "true"The comment includes:
| Field | Description |
|---|---|
| Agent DID | The delegated agent's identifier (truncated) |
| Scopes | Comma-separated list of granted scopes |
| Chain depth | Number of links in the delegation chain |
| TTL | Time remaining on the token |
A collapsible "Delegation Chain" section shows the full chain from root to leaf agent.
INFO
The audit comment uses the GITHUB_TOKEN provided by the workflow. No additional permissions are needed beyond the default pull-requests: write permission.
Example: Full Deploy Pipeline
name: Deploy
on: push
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: kanoniv/auth-action@v1
with:
root_key: ${{ secrets.KANONIV_ROOT_KEY }}
scopes: test.run,deploy.staging
ttl: 1h
- run: kanoniv-auth exec --scope test.run -- npm test
- run: kanoniv-auth exec --scope deploy.staging -- ./deploy.sh stagingEvery step is scope-verified. The deploy script cannot access production (no deploy.prod scope). The token expires in 1 hour even if the pipeline hangs.
Example: OIDC with PR Audit
name: Deploy with Audit
on: pull_request
permissions:
id-token: write
pull-requests: write
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: kanoniv/auth-action@v1
with:
oidc: "true"
api_key: ${{ secrets.KANONIV_API_KEY }}
scopes: test.run,deploy.staging
ttl: 4h
post_audit: "true"
- run: kanoniv-auth exec --scope test.run -- npm test
- run: kanoniv-auth exec --scope deploy.staging -- ./deploy.sh stagingScope Design for CI/CD
Scopes are hierarchical. Design them to match your pipeline stages:
| Scope | Grants access to |
|---|---|
test.run | Running tests |
test.run.unit | Only unit tests (covered by test.run) |
deploy.staging | Staging deploys |
deploy.prod | Production deploys |
build | Build steps |
publish.npm | npm package publishing |
A token with scopes: test.run,deploy.staging can run any test and deploy to staging, but cannot deploy to production or publish packages.
Next Steps
- wrap-mcp - MCP server auth proxy
- Delegation Chains - How chains, caveats, and attenuation work
- Overview - Back to Kanoniv Auth overview
