OIDC for CI
OIDC lets an authorized GitHub Actions or GitLab.com CI job pull one environment from a personal Pro or organization project. CI stores no long-lived Registry token.
This flow is an explicit exception to ordinary end-to-end encrypted cloud sync. LPM.dev Registry decrypts the selected environment on the server after verifying the workflow identity and policy.
The supported workflow requires:
- A personal Pro project or an organization project on an active Organization or Enterprise plan.
- GitHub Actions or GitLab.com CI.
- A repository checkout that contains the project's
lpm.jsonand vault ID.
Organization projects require an explicit owner or admin opt-in for server decryption. OIDC here authorizes CI workloads. It does not configure organization SSO.
Push the Personal Vault First
Create the local vault, sign in, and upload its encrypted cloud copy:
lpm env set --env=production API_TOKEN=secret
lpm login
lpm env push
OIDC escrow cannot be enabled before that personal cloud vault exists.
Authorize a Workflow
Run this on the LPM CLI installation that holds the personal wrapping key:
lpm env oidc allow \
--provider=github \
--repo=owner/repository \
--workflow=.github/workflows/deploy.yml \
--branch=main \
--env=production \
--events=push
The command creates the policy and then uploads protected escrow material that lets LPM.dev Registry decrypt this vault for an authorized CI pull.
After the command succeeds, it prints a server-issued policy ID. Copy this UUID into the CI configuration as LPM_OIDC_POLICY_ID.
The policy ID is a selector, not a bearer credential. It cannot authorize a pull without a valid CI identity token. Protect its integrity because a changed value can select the wrong policy.
By default, LPM CLI gets the immutable numeric repository ID from the GitHub API. Public repository requests do not need GitHub authentication.
If the repository is private, set GITHUB_TOKEN or GH_TOKEN. You can also pass --repository-id=<numeric-id> directly.
The policy binds the repository name and numeric ID. Both values must match during the OIDC exchange and the CI pull.
If a repository is renamed or transferred, run lpm env oidc allow again with its current name. A different repository cannot reuse the old policy.
Existing GitHub policies without a repository ID fail closed. If lpm env oidc list reports a missing ID, run lpm env oidc allow again.
Continue only when LPM CLI reports that CI escrow is enabled. If the escrow upload fails, the command exits with an error.
The policy can already exist after this error, but the CI pull is not ready. Correct the error and run the same command again.
List the vault's current policies with:
lpm env oidc list
The current LPM CLI can create and list policies, but it does not yet provide an oidc revoke command.
Authorize an Organization Workflow
An owner or admin must first share or pull the current organization revision. Run the complete policy command with an explicit decryption opt-in:
lpm env pull --org=acme
lpm env oidc allow \
--org=acme \
--allow-server-decryption \
--provider=github \
--repo=owner/repository \
--workflow=.github/workflows/deploy.yml \
--branch=main \
--env=production \
--events=push
lpm env oidc list --org=acme
The command transfers only this project's current content key over TLS. The Registry encrypts the key before storage. Your sharing private key and personal wrapping key stay on your machine.
The organization owns the policy and CI credentials. Access does not depend on the original policy creator remaining an admin. Each pull checks current billing, policy restrictions, token validity, and content-key state.
Owners and admins can add, replace, or delete policies from the project's Access page. They can also disable CI decryption there or through the CLI:
lpm env oidc disable --org=acme
Disabling decryption revokes issued credentials. Enabling it again does not restore those credentials. Disabling remains available when organization billing lapses.
Content-key rotation or membership key invalidation clears CI escrow and revokes issued credentials. After the new key is shared, run the complete oidc allow command again.
The CI pull command is the same for personal and organization projects. Its policy ID selects the ownership scope. The CI job does not need --org.
Policy Controls
| Control | CLI Option | Meaning |
|---|---|---|
| Repository | --repo=owner/repository | GitHub repository allowed to request access |
| Repository ID | --repository-id=123456789 | This option sets an explicit immutable ID. LPM CLI gets the ID from GitHub by default |
| Workflow | --workflow=.github/workflows/deploy.yml | Exact workflow file allowed to request access |
| Branch | --branch=main | This option sets an allowed branch. It accepts a comma-separated list |
| Environment | --env=production | This option selects the env that the job receives. It accepts a comma-separated list |
| Event | --events=push | This option sets allowed GitHub event names. The default is push |
| Forks | --allow-forks | This option permits eligible fork-originated runs. Fork access is disabled by default |
The workflow file is mandatory. Keep production access restricted to the smallest repository, workflow, branch, event, and environment set that needs it.
GitHub Actions
The job needs id-token: write so GitHub can issue its signed identity token:
name: Deploy
on:
push:
branches: [main]
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Install LPM CLI
run: npm install -g @lpm-registry/cli
- name: Pull production environment
run: lpm env pull --oidc --env=production --output=.env
env:
LPM_OIDC_POLICY_ID: ${{ vars.LPM_OIDC_POLICY_ID }}
- name: Run the deployment
run: node --env-file=.env ./scripts/deploy.mjs
--output accepts a file path and writes a plaintext dotenv file. Without --output, LPM CLI reports how many values were returned but does not inject them into later workflow steps. --output=- creates a file named -; it is not stdout.
Use a deployment command that explicitly loads the generated file. The file is set to owner-only permissions where the runner supports POSIX file modes.
The checked-out lpm.json must contain the vault ID used when the policy was created.
Create LPM_OIDC_POLICY_ID as a GitHub repository variable for this job. If you use an environment variable, add environment: <name> to the job. GitHub does not expose an environment variable to a job that does not target that environment.
You can pass --policy-id=<uuid> instead. The command flag takes precedence over LPM_OIDC_POLICY_ID.
GitLab.com CI
Authorize the numeric GitLab project ID from a logged-in development machine:
lpm env oidc allow \
--provider=gitlab \
--project-id=12345 \
--branch=main \
--env=production
Create LPM_OIDC_POLICY_ID as a GitLab CI/CD variable. Mark it protected only when every branch or tag allowed by the OIDC policy is also protected. GitLab does not expose protected variables to unprotected refs.
deploy:
id_tokens:
LPM_OIDC_TOKEN:
aud: https://lpm.dev
script:
- npm install -g @lpm-registry/cli
- lpm env pull --oidc --env=production --output=.env
- node --env-file=.env ./scripts/deploy.mjs
Trust Boundary
The CI job obtains an OIDC identity token at run time. LPM CLI sends that token, the policy ID, the vault ID, and the requested environment.
LPM.dev Registry then:
- Verifies the OIDC token's signature, issuer, audience, and current claims.
- Selects the exact server-issued policy ID.
- Matches the provider identity, repository or project ID, workflow, branch, event, environment, and fork status against the policy.
- Issues access scoped to that vault and environment.
- Uses the escrowed key to decrypt the project.
- Returns only the authorized environment as plaintext over TLS.
| Operation | Can LPM.dev Registry read vault values? |
|---|---|
Ordinary lpm env push or developer-machine pull | No |
lpm env oidc allow escrow upload | Receives protected key material for later server decryption |
Authorized lpm env pull --oidc | Yes |
If server-side decryption is outside the project's security requirements, do not enable OIDC escrow.
Escrow Errors
If a CI pull reports a stale escrow key, repeat setup on the machine that holds the current project key. Organization setup also requires --org=<slug> and --allow-server-decryption.
If a CI pull reports an unavailable escrow key version, the Registry configuration needs operator action. The pull fails and returns no secret values.
The Registry protects escrow material with a versioned server key. A server-key rotation does not change the policy or require a new escrow upload.
Current Limitations
- OIDC env pull requires a personal Pro project or an approved organization project.
- Initial organization decryption setup requires an owner or admin with the current shared key.
- GitLab.com policies use the stable numeric project ID. Self-managed GitLab issuers are not supported.
- The dashboard does not provide personal env OIDC policy management.
For detailed CLI behavior, see the LPM CLI environment reference.
See Also
- Cloud Sync — Understand the personal encrypted vault and escrow exception.
- Organization Sharing — Review the separate organization key model.
- CI/CD — Configure package installation and publishing in CI.