Configuration
The published config/git.php holds one block per provider plus shared blocks for caching, logging, webhooks and batching. GitHub’s block in full, with GitLab and Bitbucket abbreviated where they repeat the same shape:
return [
'providers' => [
'github' => [
'url' => env('GITHUB_API_URL', 'https://api.github.com'),
'token' => env('GITHUB_TOKEN'),
'webhook_secret' => env('GITHUB_WEBHOOK_SECRET'),
'timeout' => env('GITHUB_TIMEOUT', 10),
'retry' => [
'times' => env('GITHUB_RETRY_TIMES', 1),
'backoff' => env('GITHUB_RETRY_BACKOFF', 0),
],
'rateLimits' => [
'enabled' => env('GITHUB_RATELIMIT_ENABLED', true),
'owner' => env('GITHUB_RATELIMIT_OWNER', 'app'),
'maxAttempts' => env('GITHUB_RATELIMIT', 5000),
'timespan' => env('GITHUB_RATELIMIT_TIMESPAN', 'hour'), // second | minute | hour | day
'adaptive' => env('GITHUB_RATELIMIT_ADAPTIVE', true),
'max_wait' => env('GITHUB_RATELIMIT_MAX_WAIT'), // ms; null = wait/pace
'jitter' => env('GITHUB_RATELIMIT_JITTER'), // ms; null = none
],
'options' => [
'headers' => [
'User-Agent' => env('GIT_USER_AGENT', env('APP_NAME', 'GitHttp/1.0')),
'X-GitHub-Api-Version' => env('GITHUB_API_VERSION', '2022-11-28'),
],
],
// GitHub App authentication (self-refreshing installation tokens).
// When id, installation_id and private_key are all set, Git::github() mints
// installation tokens automatically; otherwise it uses token.
// Git::githubApp() needs only id + private_key.
'app' => [
'id' => env('GITHUB_APP_ID'),
'installation_id' => env('GITHUB_APP_INSTALLATION_ID'),
'private_key' => env('GITHUB_APP_PRIVATE_KEY'), // PEM string or file path
'slug' => env('GITHUB_APP_SLUG'), // builds the install URL
'permissions' => [ // default scope for a per-operation mint
'contents' => 'write',
'pull_requests' => 'write',
'metadata' => 'read',
],
],
// OAuth credentials (self-refreshing access tokens).
'oauth' => [
'client_id' => env('GITHUB_OAUTH_CLIENT_ID'),
'client_secret' => env('GITHUB_OAUTH_CLIENT_SECRET'),
'token_url' => env('GITHUB_OAUTH_TOKEN_URL', 'https://github.com/login/oauth/access_token'),
],
],
'gitlab' => [
'url' => env('GITLAB_API_URL', 'https://gitlab.com'),
'token' => env('GITLAB_TOKEN'),
'webhook_secret' => env('GITLAB_WEBHOOK_SECRET'),
// timeout, retry and options follow the same shape with GITLAB_* keys
'rateLimits' => [
'maxAttempts' => env('GITLAB_RATELIMIT', 10),
'timespan' => env('GITLAB_RATELIMIT_TIMESPAN', 'second'),
// enabled, owner, adaptive, max_wait, jitter as above
],
'oauth' => [
'client_id' => env('GITLAB_OAUTH_CLIENT_ID'),
'client_secret' => env('GITLAB_OAUTH_CLIENT_SECRET'),
'token_url' => env('GITLAB_OAUTH_TOKEN_URL', 'https://gitlab.com/oauth/token'),
],
],
'bitbucket' => [
'url' => env('BITBUCKET_API_URL', 'https://api.bitbucket.org'),
'token' => env('BITBUCKET_TOKEN'),
'webhook_secret' => env('BITBUCKET_WEBHOOK_SECRET'),
// timeout, retry and options follow the same shape with BITBUCKET_* keys
'rateLimits' => [
'maxAttempts' => env('BITBUCKET_RATELIMIT', 1000),
'timespan' => env('BITBUCKET_RATELIMIT_TIMESPAN', 'hour'),
],
],
],
'cache' => [
'enabled' => env('GIT_CACHE_ENABLED', false),
'store' => env('GIT_CACHE_STORE'),
'ttl' => env('GIT_CACHE_TTL', 3600),
],
'logging' => [
'enabled' => env('GIT_LOGGING_ENABLED', false),
'channel' => env('GIT_LOGGING_CHANNEL'),
],
'webhooks' => [
// Handed over raw and parsed strictly where it is read: 1/true/on/yes enable the
// route, 0/false/off/no keep it off, and anything else throws at boot.
'enabled' => env('GIT_WEBHOOKS_ENABLED', false),
'path' => env('GIT_WEBHOOKS_PATH', 'git/webhooks'),
'middleware' => ['api'],
],
'batch' => [
'concurrency' => env('GIT_BATCH_CONCURRENCY', 25),
],
];Every key
| Key | Default | Purpose |
|---|---|---|
providers.<name>.url | Forge API URL | API base URL — api.github.com, gitlab.com, api.bitbucket.org. For GitHub Enterprise Server use https://ghe.example.com/api/v3; clone and install URLs are then built on the web host https://ghe.example.com. Unset or blank (GITHUB_API_URL=) uses the public API; a non-string value throws. |
providers.<name>.token | null | Default access token — Git::github() and friends use it when you pass no credential. |
providers.<name>.webhook_secret | null | Verifies inbound webhooks; also the default secret when registering a webhook. Unset or blank means no secret, so nothing verifies. |
providers.<name>.timeout | 10 | HTTP request timeout in seconds, 0–3600 (0 = none). |
providers.<name>.retry.times | 1 | Attempts (0–100) for a read that hits a dropped connection, a 429 or a 5xx; writes are never retried. retry may also be a plain int — the attempts. |
providers.<name>.retry.backoff | 0 | Backoff between read retries, in ms (0–600000). |
providers.<name>.rateLimits.enabled | true | Client-side throttling; false sends with no limiter at all. |
providers.<name>.rateLimits.owner | app | Throttle bucket key (git:<provider>:<owner>). Blank is not set (app); non-string throws. |
providers.<name>.rateLimits.maxAttempts | 5000 / 10 / 1000 | Requests per timespan, at least 1 (GitHub / GitLab / Bitbucket). |
providers.<name>.rateLimits.timespan | hour / second / hour | second, minute, hour or day; anything else throws (an unset or blank key means minute). |
providers.<name>.rateLimits.adaptive | true | Honour the forge’s own Retry-After / X-RateLimit-* headers. |
providers.<name>.rateLimits.max_wait | null | Max defer in ms (0 or more) before failing fast; null or blank waits and paces instead. |
providers.<name>.rateLimits.jitter | null | Random jitter in ms (0 or more) added to each defer; null or blank adds none. |
providers.<name>.options.headers | User-Agent | Extra HTTP options sent with every request; GitHub also pins X-GitHub-Api-Version 2022-11-28. |
providers.github.app.id | null | GitHub App id; with installation_id and private_key set, Git::github() mints installation tokens. Unset or blank means no app is configured; a non-string value (an integer, say) throws naming the key instead of falling back to token. |
providers.github.app.installation_id | null | Installation id for the default app credential. |
providers.github.app.private_key | null | App private key — a PEM string or a file path. |
providers.github.app.slug | null | The app’s public slug; required by installUrl(). |
providers.github.app.permissions | contents, pull_requests: write; metadata: read | Permission set used by InstallationTokenScope::forRepositories(). |
providers.<github|gitlab>.oauth.client_id | null | OAuth client id, read by OauthToken::forProvider(). |
providers.<github|gitlab>.oauth.client_secret | null | OAuth client secret, read by OauthToken::forProvider(). |
providers.<github|gitlab>.oauth.token_url | Forge token URL | OAuth endpoint used to refresh access tokens. |
cache.enabled | false | Store ETags and serve 304 Not Modified responses from cache. |
cache.store | Default store | Cache store for conditional requests and for minted App/OAuth tokens. Blank is not set (default store); non-string throws. |
cache.ttl | 3600 | Cached-response TTL in seconds, at least 1. |
logging.enabled | false | Log method, URL, status and duration at debug level — never tokens or bodies. |
logging.channel | Default channel | Log channel for request logging. Blank is not set (default channel); non-string throws. |
webhooks.enabled | false | Register the POST {path}/{provider} webhook route. Unset or blank (GIT_WEBHOOKS_ENABLED=null, GIT_WEBHOOKS_ENABLED=) means off — for the route, the URL webhooks()->register() derives, and about alike. |
webhooks.path | git/webhooks | Base path of the webhook route. Blank is not set and uses git/webhooks; surrounding slashes are trimmed (/hooks/ is hooks); a slash-only path or a non-string throws — never the site root. |
webhooks.middleware | ['api'] | Middleware applied to the webhook route. |
batch.concurrency | 25 | Max concurrent requests per pool (1–1000); larger inputs are chunked. |
Environment
The common knobs are env-driven, so most apps never publish the config at all:
GITHUB_TOKEN=ghp_...
GITLAB_TOKEN=glpat-...
BITBUCKET_TOKEN=...
GITHUB_WEBHOOK_SECRET=...
GIT_WEBHOOKS_ENABLED=true
GIT_CACHE_ENABLED=true
GIT_CACHE_STORE=redis
GIT_LOGGING_ENABLED=true- Tokens and secrets: GITHUB_TOKEN, GITLAB_TOKEN, BITBUCKET_TOKEN and the matching *_WEBHOOK_SECRET.
- Per-provider transport: *_API_URL, *_TIMEOUT, *_RETRY_TIMES, *_RETRY_BACKOFF and the *_RATELIMIT* keys.
- GitHub App: GITHUB_APP_ID, GITHUB_APP_INSTALLATION_ID, GITHUB_APP_PRIVATE_KEY, GITHUB_APP_SLUG.
- OAuth: GITHUB_OAUTH_CLIENT_ID, GITHUB_OAUTH_CLIENT_SECRET, GITHUB_OAUTH_TOKEN_URL and the GitLab equivalents.
- Shared: GIT_CACHE_ENABLED, GIT_CACHE_STORE, GIT_CACHE_TTL, GIT_LOGGING_ENABLED, GIT_LOGGING_CHANNEL, GIT_WEBHOOKS_ENABLED, GIT_WEBHOOKS_PATH, GIT_BATCH_CONCURRENCY, GIT_USER_AGENT, GITHUB_API_VERSION.
.env delivers every value as a string, and the package reads them as what they spell: an integer key takes a numeric string (GITHUB_TIMEOUT=45 is 45 seconds) and throws package-toolkit’s InvalidConfigurationException naming the key when the value isn’t an integer in its range; a boolean key reads 1/true/on/yes as on and 0/false/off/no as off — so GIT_WEBHOOKS_ENABLED=off really is off — and throws the same exception for anything else (GIT_WEBHOOKS_ENABLED=disabled fails at boot rather than silently keeping the route off). The same goes for every other setting: a timespan outside second/minute/hour/day, a non-integer max_wait or jitter, and a non-string string setting all throw naming the key. Only a key that is not set — absent, null or blank (a host’s KEY=) — takes its default (or stays off, for an optional one).
App and OAuth tokens are cached so they survive across requests — point cache.store at a shared store (Redis, database, file) rather than the array driver when you use them.
Show your open-source love
This package is free and MIT-licensed. If it saves you time, a one-off donation or a Patreon membership keeps it maintained, tested and documented.
More ways to support, including cryptoBy donating, you agree to our donation terms.
Want this built into your product?
We integrate our packages into custom Laravel and AI builds. Tell us what you're working on and we'll reply within 48 hours.