Connect source-control applications¶
Open Connections → Source control to register an application owned by your GitHub organization, GitLab account or Bitbucket workspace. The provider controls its permissions and grants. forge discovers the repositories it can access and checks the current grant again before cloning or publishing.
Application registration and owner approval happen on the provider's website. Saving a client ID or private key in forge does not create an application or prove access. Test connection makes a real provider request. Connect repository accepts a discovered repository ID; forge obtains its URL and default branch from a fresh provider response.
GitHub App¶
Register a GitHub App under the account that should own it. Request repository Contents: read and write and Pull requests: read and write. Install it on the selected repositories. Save its app ID, installation ID and unencrypted RSA private key in forge. The optional app slug provides a direct installation link.
forge signs a short-lived app JWT. Repository discovery uses an installation token with metadata permission. Git execution and pull requests use a token restricted to the selected repository ID, with the two write permissions above. Tokens are refreshed before expiry. Organization approval, branch protections and workflow-file permissions can still prevent an operation. See GitHub's installation-token contract.
For GitHub Enterprise Server, set Host to its HTTPS origin. forge derives
/api/v3 from that origin and rejects clone URLs or pagination links from another
host. App installation and permissions must exist on that same server.
GitLab OAuth application¶
Register an OAuth application with the redirect URI displayed in forge:
https://your-forge.example/api/v1/scm/connections/gitlab/callback
Use api, read_repository and write_repository scopes for merge requests and
Git access. Save the application ID and redirect URI; save its client secret
when the application is confidential. Select Authorize to complete the
provider's consent screen.
forge uses authorization code with PKCE, a browser-bound state that expires after ten minutes, and server-side rotating refresh tokens. State can be used once. Discovery requests non-archived projects where the authorized user is a member with developer access or higher. GitLab OAuth follows the user's grants; it does not provide GitHub's per-repository installation-token restriction. Self-managed GitLab uses its configured HTTPS origin. See the GitLab OAuth API.
Bitbucket OAuth consumer¶
Create an OAuth consumer in the workspace
and enable repository, repository:write, pullrequest and pullrequest:write.
Save its client key, client secret and workspace slug. The default grant is
client credentials: forge obtains a short-lived token representing the
consumer's owner and lists repositories in the configured workspace.
For user consent, choose authorization code, register the forge callback URI and select Authorize. This uses browser-bound, single-use state and rotating refresh tokens. Client-credentials tokens are obtained again on expiry; that grant does not require a refresh token.
API calls use bearer authentication at api.bitbucket.org. App passwords are
deprecated and are not used by this connection. See the current
Bitbucket authentication contract
and OAuth changes effective May 2026.
Protect and revoke access¶
Private keys, client secrets and OAuth grants stay in configuration/ under the
server's private data directory. Files have 0600 permissions and the directory
has 0700 permissions. API summaries return configured flags for secrets;
secret values cannot be read back. Blank secret fields preserve saved values.
Use the explicit clear action to remove them. Changing application settings
invalidates saved grants, cached tokens and pending authorization state.
Changing an OAuth host or client ID also requires an explicitly supplied client
secret or an explicit clear action. forge refuses to carry a confidential
client's saved secret to that new destination. A public GitLab client can clear
the old secret before starting a new authorization.
Before refreshing a rotating token, forge persists a dispatch marker in its current private SCM grant storage. A timeout, invalid response or interrupted process leaves that marker unresolved; subsequent requests cannot send the old refresh token again, including after restart. The connection reports Needs authorization. Complete a new provider consent flow to establish a fresh grant. This recovery does not claim whether the previous provider request succeeded. SCM storage remains owner-private configuration; the general encrypted PostgreSQL provider-connection lifecycle is separate work.
Token issuance and repository discovery also check that the application revision did not change while a provider request was in flight. An obsolete response cannot cache credentials or register a repository. Repeat the operation after saving the current application configuration. Malformed credential or repository responses fail closed; they do not mark an application as connected.
Git credentials are passed only to the clone or push process. They are not
written into repository URLs, .git/config, global Git configuration or generated
products. Coding and verification workers do not receive those credentials.
Provider errors omit response bodies that might contain sensitive data.
Revoke an installation or OAuth grant at the provider to remove its authority. forge's next grant check fails if access is revoked. Clearing the local secret removes forge's copy; it does not uninstall the provider's application. Existing remote branches and pull requests remain.
Connection API¶
All routes below use /api/v1 and require current factory-administrator authority, except the two OAuth callback routes. Hosted clients authenticate through the configured OIDC identity; explicit local bootstrap uses its loopback operator credential. Callbacks require the saved one-use state and browser cookie. Factory credentials never appear in a redirect URL. See identity and project access.
| Method | Path | Result |
|---|---|---|
| GET | /scm/connections |
Application summaries and setup fields |
| PUT | /scm/connections/{provider} |
Write-only settings and explicit secret clearing |
| POST | /scm/connections/{provider}/test |
Live grant-test summary |
| GET | /scm/connections/{provider}/repositories |
Repositories in current grants |
| POST | /scm/connections/{provider}/repositories/connect |
Register a freshly discovered repository ID |
| POST | /scm/connections/{provider}/authorize |
Browser authorization URL and private cookie |
| GET | /scm/connections/{provider}/callback |
Complete GitLab or Bitbucket consent |
{
"values": {"app_id": "123", "installation_id": "456"},
"clear_secrets": []
}
The connection request is {"repository_id":"42"}. It does not accept a URL
or credentials supplied by the caller.
Publish a verified change¶
Studio runs begin with publish: false. After verification succeeds, Publish
pull request creates a branch and invokes the provider's pull-request API.
Operators can also use forge publish RUN_ID or explicitly request publish:
true when creating a run. forge does not merge a pull request or deploy a
product through this action. Project reviews and branch protections still apply.
Generic Git, Azure DevOps and Gitea retain the manual repository path. HTTPS URLs must not contain credentials. Configure an appropriate Git credential helper or SSH agent for those sources. Their existing provider-specific publication settings remain available; GitHub, GitLab and Bitbucket application connections provide the managed grant flow described above.
Contract tests check request construction, state handling and failure boundaries.
Loopback HTTP acceptance runs a real forge API server and a provider fixture
server for GitHub Enterprise /api/v3, self-managed GitLab /api/v4, and
Bitbucket Cloud. It verifies operator authentication, GitHub JWT signatures,
GitLab PKCE and refresh rotation, bearer-authorized repository discovery, signed
or secret-token ingress, outbound conversation feedback, revocation, and receipt
reconciliation without duplicate comments. Test-only routing sends the configured
provider paths and Host headers to the local fixture; it does not test provider
DNS, TLS, organizational installation, or consent on a real provider account.
Live acceptance requires the real application registration, provider consent,
repository grant and successful remote operation for each account.