Scopes, Rotation & Security
This page covers least-privilege scopes, credential rotation, and security best practices. For OAuth App creation, Coder integration, and test PAT setup, see the other Token Guide pages.
Token scopes and least privilege
Least privilege is not a one-time decision; it is a continuous constraint. Review the scope set every time you add a new skill, model, or integration that might require additional GitHub access. Ask the same question for every new permission: can the agent accomplish the task with a narrower scope?
Minimum viable scopes
For a standard repository that contains application code and documentation, the minimum production scope set is
repo plus read:org and user:email. Add workflow only if the agents
must modify GitHub Actions. Avoid admin:repo_hook, delete_repo, and any org-admin scopes
unless a specific, reviewed operation requires them.
Audit the OAuth App regularly
GitHub records every OAuth authorization in the organization audit log. Review the log monthly for unexpected users, unexpected scopes, or authorizations from unknown IP addresses. Revoke any authorization that does not match a known tenant or user.
Restrict the Coder API token
The orchestrator does not need to create users, modify organizations, or change deployment settings. Create a custom Coder role with only the permissions listed in the Coder Integration guide and assign that role to the orchestrator user. If Coder supports token-level scope restrictions, apply them.
Rotation
All long-lived credentials should be rotated on a schedule and immediately after any suspected exposure. Rotation is a safety mechanism, not an emergency-only procedure. The schedule below is a starting point; adjust it to your own security policy.
| Credential | Rotation trigger | Procedure |
|---|---|---|
| OAuth App client secret | On exposure, or annually as policy dictates | Generate a new secret in the GitHub OAuth App settings, update GITHUB_OAUTH_CLIENT_SECRET, restart the OpenFlows orchestrator, and revoke the old secret. |
CODER_SESSION_TOKEN | Every 90 days, or immediately after personnel changes | Create a new token in the Coder dashboard, update CODER_SESSION_TOKEN, restart the orchestrator, then revoke the old token. |
| Test GitHub PAT | Per CI run or every 30 days in long-lived test beds | Delete /tmp/github_token, create a new PAT, write it to /tmp/github_token with mode 600, and re-run the test suite. |
Rotation checklist
- Generate the replacement credential in the upstream system (GitHub OAuth App or Coder dashboard).
- Update the secret in your secret manager or orchestrator environment.
- Restart the OpenFlows orchestrator to pick up the new value.
- Verify that the next tenant command or poll cycle succeeds.
- Revoke the old credential only after the new one is confirmed working.
Rotate before you have to
Security best practices
Tokens are the keys to the kingdom. Protect them with the same rigor you would apply to a production database credential.
- Never commit
.env. The.env.examplefile contains placeholders only. Add.envto.gitignoreand scan for it in pre-commit hooks. - Use a secret manager. Store
CODER_SESSION_TOKENandGITHUB_OAUTH_CLIENT_SECRETin a secret manager, Kubernetes secret, or Docker secret. Mount them as files or environment variables at runtime, not at build time. - Restrict network access. Limit Coder and OpenFlows orchestrator traffic to trusted networks. Use TLS for every endpoint. Do not expose the Coder dashboard or the orchestrator API to the public internet without an authenticated reverse proxy.
- Enable audit logging. GitHub organization audit logs and Coder audit logs should be forwarded to a SIEM. Alert on token regeneration, scope changes, failed authorization callbacks, and unusual workspace provisioning rates.
- Run the orchestrator as a dedicated user. The Linux account that runs
openflowsshould have no shell access, no sudo rights, and no access to other production systems. The only files it needs to read are.envand the OpenFlows binary. - Keep test credentials isolated. Test PATs should be stored in a separate secret namespace and never
referenced in a production
.envfile.
Troubleshooting
Most authentication failures fall into a small number of patterns. The table below maps common errors to their causes and fixes.
| Symptom | Cause | Fix |
|---|---|---|
401 Bad credentials when OpenFlows calls GitHub | OAuth App token expired, PAT revoked, or /tmp/github_token missing. | Verify the Coder external auth session is current, re-authenticate the tenant in the Coder dashboard, or confirm the test PAT file exists and is readable. |
403 Resource not accessible by integration | OAuth App scopes are insufficient or the app is not installed on the target repository/organization. | Check the OAuth App scopes, confirm the app is authorized for the organization, and re-run the tenant authorization flow. |
401 Unauthorized from Coder API | The CODER_SESSION_TOKEN is missing, expired, or lacks the required scopes. | Verify the token in the Coder dashboard, ensure it has workspace and template permissions, and restart the orchestrator. |
| OAuth callback mismatch | The GITHUB_OAUTH_REDIRECT_URL does not match the authorization callback URL in the GitHub OAuth App. | Compare the two values exactly, including the scheme and trailing slash, and update both sides to match. |
| Tenant authorization prompts repeatedly | The Coder external auth session has a short lifetime and is not being refreshed automatically. | Check the Coder external auth provider configuration, confirm the refresh token is being stored, and review the Coder server logs. |
If the issue persists after checking the items above, inspect the Coder server logs and the OpenFlows orchestrator logs together. The most useful signals are the exact HTTP status code from the Coder API, the GitHub API response headers, and whether the failure happens during tenant provisioning or during a GitHub operation.
Still stuck?