NewWe open-sourced 50+ Laravel packages
Custom AI apps, agents and automation — Roundly ConsultingRoundly
All packages
Git for Laravel

Providers & credentials

Resolve a provider through the Git facade. With a token in config you don’t pass a credential at all; an explicit credential always overrides config:

use RoundlyConsulting\Git\Dto\Credentials\Token;
use RoundlyConsulting\Git\Enums\ProviderName;
use RoundlyConsulting\Git\Facades\Git;
use RoundlyConsulting\Git\Providers\Gitlab;

$github = Git::github();                       // uses config('git.providers.github.token')
$github = Git::github(Token::from('ghp_...')); // explicit override
$gitlab = Git::gitlab();
$bitbucket = Git::bitbucket();

$gitlab = Git::provider('gitlab');             // by string,
$gitlab = Git::provider(ProviderName::Gitlab); // by ProviderName enum,
$gitlab = Git::provider(Gitlab::class);        // or by class-string

How the default credential is chosen

  • When git.providers.github.app.id, installation_id and private_key are all set, a self-refreshing GithubAppToken is built from them.
  • With any of the three missing, the provider’s token (GITHUB_TOKEN, GITLAB_TOKEN, BITBUCKET_TOKEN) becomes a static Token. An app configured only for Git::githubApp() — id and key, with installation ids arriving per customer — is a normal setup, not an error.
  • With neither, the provider is unauthenticated and reads public repositories anonymously — no Authorization header is sent at all, and you get the forge’s anonymous quota (60 requests an hour on GitHub). Writes throw InvalidCredentialsException.

Credential types

CredentialBuild withAccepted by
TokenToken::from($token)GitHub, GitLab, Bitbucket — a static personal or API token.
OauthTokenOauthToken::forProvider(…) / OauthToken::for(…)GitHub, GitLab — self-refreshing OAuth access token.
GithubAppTokenGithubAppToken::for($appId, $installationId, $privateKey)GitHub — self-refreshing installation token, optionally scoped.
GithubAppGithubApp::for($appId, $privateKey)GitHub — the app’s own RS256 JWT, for /app/** endpoints only.

You can also authenticate a resolved provider yourself and inspect what it accepts:

$provider = Git::provider('github');          // unauthenticated when nothing is configured
$provider->isAuthenticated();                   // false

$provider->authenticate(Token::from($user->github_token));
$provider->isAuthenticated();                   // true

$provider->authenticationMethods();             // [Token::class, GithubAppToken::class, GithubApp::class, OauthToken::class]
$provider->name();                              // "GitHub"
$provider->providerName();                      // ProviderName::Github

Passing a credential a provider doesn’t accept throws InvalidCredentialsException listing the supported methods. Every credential redacts its secrets (••••) in toArray() and toJson(), so it never serializes into logs.

Authentication errors

A 401 — the forge refusing the credential itself — throws InvalidCredentialsException: “requires authentication” when none was configured, “rejected the credential” when the token is invalid, revoked or expired (the forge’s response is getPrevious()). Every other refusal stays Laravel’s RequestException, so you can read its status: a repository you cannot see is a 404 (GitHub hides private repositories from callers without access), and a throttled 403 or 429 stays retryable rather than being mistaken for a broken credential. The same goes for a 401 while minting a GitHub App installation token (a revoked or wrong app key) or refreshing an OAuth token.

use Illuminate\Http\Client\RequestException;
use RoundlyConsulting\Git\Exceptions\InvalidCredentialsException;

try {
    $repository = Git::github()->repo('acme/api')->get();
} catch (InvalidCredentialsException $e) {
    // 401: "requires authentication" (none configured) or "rejected the credential"
    report($e->getPrevious());   // the forge's own response
} catch (RequestException $e) {
    $e->response->status();      // 404 = missing or not visible, 403/429 = throttled
}

Extending the manager

GitHub, GitLab and Bitbucket are the providers this package speaks — provider() resolves only those, by config key, driver class or ProviderName. There are two extension points. GitManager is macroable, so you can register your own shortcuts on top of the drivers and call them through the facade:

use RoundlyConsulting\Git\Dto\Credentials\Token;
use RoundlyConsulting\Git\Facades\Git;
use RoundlyConsulting\Git\Handles\RepositoryHandle;

Git::macro('app', fn (): RepositoryHandle => $this->github()->repo('acme/app'));
Git::macro('forUser', fn (User $user) => $this->github(Token::from($user->github_token)));

Git::app()->pullRequests();          // same as Git::github()->repo('acme/app')->pullRequests()
Git::forUser($user)->repositories();

The drivers are resolved from the container and are not final, so you can swap a built-in one for a subclass — to add an endpoint, say. Git::github(), Git::capabilities() and the fake’s feature matrix all pick the subclass up:

use RoundlyConsulting\Git\Providers\Github;

$this->app->bind(Github::class, AcmeGithub::class); // class AcmeGithub extends Github { … }

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 crypto

By 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.