PHPackages                             esanj/auth-bridge - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. esanj/auth-bridge

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

esanj/auth-bridge
=================

OAuth 2.0 Bridge package for connecting to external authorization servers.

v0.2.0(1mo ago)01095MITPHPPHP ^8.1|^8.2|^8.3|^8.4

Since Jul 9Pushed 2mo agoCompare

[ Source](https://github.com/eSanjDev/ms-package-accounting-bridge)[ Packagist](https://packagist.org/packages/esanj/auth-bridge)[ RSS](/packages/esanj-auth-bridge/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (18)Versions (10)Used By (5)

AuthBridge
==========

[](#authbridge)

**AuthBridge** is a Laravel package that connects your app to an **OAuth 2.0** authorization server. It handles the **Authorization Code** flow (redirect users to log in, then receive their token) and the **Client Credentials**flow (server‑to‑server tokens), plus **RS256 JWT verification** — with an event‑driven design so you decide what happens when a token arrives.

> Originally built for the Esanj Accounting service, but it works with any OAuth 2.0 server. Many Esanj packages (e.g. `esanj/managers`) depend on it for login.

Features
--------

[](#features)

- OAuth 2.0 **Authorization Code** and **Client Credentials** grants.
- CSRF **state** validation on callback (enforced in production).
- **Event‑driven**: `TokenReceived`, `TokenExchangeFailed`, `AuthorizationRedirecting`.
- **JWT** extraction &amp; verification (RS256) against the OAuth server's public key.
- Automatic **token caching** for the Client Credentials flow.
- A facade with handy **session token helpers**.

Requirements
------------

[](#requirements)

- **PHP:** 8.1 – 8.4
- **Laravel:** 10.x – 13.x
- **OAuth Server:** any OAuth 2.0 compliant server
- `firebase/php-jwt` (installed automatically) — used for JWT verification.

Installation
------------

[](#installation)

```
composer require esanj/auth-bridge
```

The service provider and the `AuthBridge` facade are auto‑discovered.

Configuration
-------------

[](#configuration)

### 1. Publish the config

[](#1-publish-the-config)

```
php artisan vendor:publish --tag="esanj-auth-bridge-config"
```

This creates `config/esanj/auth_bridge.php` (merged internally under the key `esanj.auth_bridge`).

### 2. Environment variables

[](#2-environment-variables)

```
# OAuth client credentials (required)
ACCOUNTING_BRIDGE_CLIENT_ID=your-client-id
ACCOUNTING_BRIDGE_CLIENT_SECRET=your-client-secret

# OAuth server base URL (required)
ACCOUNTING_BRIDGE_BASE_URL=https://oauth-server.example.com

# Authorization prompt: none | consent | login
ACCOUNTING_BRIDGE_OAUTH_PROMPT=consent

# Callback URL (optional — auto-generated from APP_URL + prefix + callback path if unset)
ACCOUNTING_BRIDGE_REDIRECT_URL=https://yourapp.com/accounting/callback

# Where to send the user after a successful login
ACCOUNTING_BRIDGE_SUCCESS_REDIRECT=/dashboard

# Routing
ACCOUNTING_BRIDGE_ROUTE_PREFIX=accounting   # prefix for the two routes
ACCOUNTING_BRIDGE_PATH_REDIRECT=login        # the "start login" path
ACCOUNTING_BRIDGE_PATH_CALLBACK=callback     # the OAuth callback path
ACCOUNTING_BRIDGE_MIDDLEWARE=web             # comma-separated middleware

# JWT public key (RS256) used to verify tokens
ACCOUNTING_BRIDGE_KEY_PATH=/path/to/oauth-public.key
```

### 3. Config options

[](#3-config-options)

OptionDescription`client_id` / `client_secret`OAuth 2.0 credentials.`base_url`Base URL of the OAuth server.`redirect_url`Callback URL (auto‑generated from `APP_URL` if not set).`auth2_prompt`OAuth `prompt`: `none`, `consent`, or `login`.`success_redirect`Where to redirect after a successful login.`routes.prefix` / `routes.middleware`Prefix and middleware for the package routes.`route_path.redirect` / `route_path.callback`Paths for the redirect and callback endpoints.`public_key_path`Path to the OAuth server's RS256 public key.`session_state_key` / `session_token_key`Session keys (`auth_bridge_state` / `auth_bridge`).Routes
------

[](#routes)

MethodPath (default)NameDescriptionGET`/{prefix}/{redirect}` → `/accounting/login``auth-bridge.redirect`Starts the OAuth flow (redirects to the server).GET`/{prefix}/{callback}` → `/accounting/callback``auth-bridge.callback`Handles the callback and stores the token.Usage
-----

[](#usage)

### Authorization Code flow (user login)

[](#authorization-code-flow-user-login)

**Step 1 — send the user to log in:**

```
return redirect()->route('auth-bridge.redirect');
```

The package builds the authorization URL, stores a random `state` in the session, fires `AuthorizationRedirecting`, and redirects to the OAuth server.

**Step 2 — the callback is handled for you.** On return the package validates `state` (in production), exchanges the `code` for a token, stores the token in the session under `auth_bridge`, fires `TokenReceived`, and redirects to `config('esanj.auth_bridge.success_redirect')`.

> ℹ️ `success_redirect` and the callback URL are taken from **config/env**. (Passing them as query parameters to the route is **not** currently supported — see [Notes](#notes--limitations).)

**Step 3 — react to the token via the `TokenReceived` event (recommended).**

```
// app/Listeners/HandleTokenReceived.php
use Esanj\AuthBridge\Events\TokenReceived;
use Esanj\AuthBridge\Contracts\ClientCredentialsServiceInterface;
use Illuminate\Support\Facades\Auth;
use App\Models\User;

class HandleTokenReceived
{
    public function handle(TokenReceived $event): void
    {
        $token = $event->tokenData;                 // TokenData DTO
        // $event->grantType === 'authorization_code'

        $jwt = app(ClientCredentialsServiceInterface::class)->extractJwt($token->accessToken);

        $user = User::firstOrCreate(
            ['oauth_id' => $jwt->sub],
            ['email' => $jwt->email ?? null, 'name' => $jwt->name ?? null],
        );

        Auth::login($user);
    }
}
```

Register it (Laravel 11+ auto‑discovers listeners; otherwise add it to your `EventServiceProvider`).

**Alternative — read the token from the session:**

```
$accessToken = session('auth_bridge.access_token');
$refreshToken = session('auth_bridge.refresh_token');
$expiresAt   = session('auth_bridge.expires_at');

// Or via the facade:
use Esanj\AuthBridge\Facades\AuthBridge;
$header = AuthBridge::getAuthorizationHeader(); // "Bearer xxx" or null
```

### Client Credentials flow (server‑to‑server)

[](#client-credentials-flow-servertoserver)

```
use Esanj\AuthBridge\Contracts\ClientCredentialsServiceInterface;

public function __construct(private ClientCredentialsServiceInterface $cc) {}

$token = $this->cc->getAccessToken(
    clientId: config('esanj.auth_bridge.client_id'),
    clientSecret: config('esanj.auth_bridge.client_secret'),
    scope: '*' // optional
);

$response = Http::withHeaders([
    'Authorization' => $token->getAuthorizationHeader(),
])->get('https://api.example.com/data');

// Force a refresh on the next call:
$this->cc->invalidateToken(config('esanj.auth_bridge.client_id'), '*');
```

Tokens are cached until ~60 seconds before expiry; failures fire `TokenExchangeFailed`.

### JWT extraction

[](#jwt-extraction)

```
use Esanj\AuthBridge\Contracts\ClientCredentialsServiceInterface;
use Esanj\AuthBridge\Exceptions\ExtractJWTException;

try {
    $jwt = app(ClientCredentialsServiceInterface::class)->extractJwt($accessToken);
    $userId = $jwt->sub;
} catch (ExtractJWTException $e) {
    report($e); // invalid token, or public key missing
}
```

Requires the RS256 public key at `config('esanj.auth_bridge.public_key_path')`.

Events
------

[](#events)

EventFired whenPayload`TokenReceived`A token is obtained (either flow).`TokenData $tokenData`, `string $grantType``TokenExchangeFailed`A token request/exchange fails.`AuthBridgeException $exception`, `string $grantType``AuthorizationRedirecting`Just before redirecting to the OAuth server.`AuthorizationRequest $request`, `string $authorizationUrl`Facade
------

[](#facade)

```
use Esanj\AuthBridge\Facades\AuthBridge;

AuthBridge::buildAuthorizationUrl();                         // build the authorize URL
AuthBridge::exchangeAuthorizationCodeForAccessToken($code);  // exchange a code → TokenData
AuthBridge::getClientId();
AuthBridge::getBaseUrl();

// Session token helpers:
AuthBridge::getToken();                 // array|null
AuthBridge::getAccessToken();           // string|null
AuthBridge::hasToken();                 // bool
AuthBridge::getAuthorizationHeader();   // "Bearer xxx"|null
AuthBridge::clearToken();               // forget the session token
```

Error handling
--------------

[](#error-handling)

ExceptionWhen`InvalidStateException`The OAuth `state` is missing or doesn't match (production).`TokenExchangeException`The authorization‑code exchange fails.`TokenRequestException`The client‑credentials token request fails.`ExtractJWTException`JWT is invalid/expired, or the public key is missing.`AuthBridgeException`Base class for all of the above (carries `getContext()`).```
use Esanj\AuthBridge\Exceptions\TokenExchangeException;

try {
    $token = AuthBridge::exchangeAuthorizationCodeForAccessToken($code);
} catch (TokenExchangeException $e) {
    logger()->error('OAuth exchange failed', ['error' => $e->getMessage(), 'context' => $e->getContext()]);
    return redirect('/login')->with('error', 'Authentication failed');
}
```

Notes &amp; limitations
-----------------------

[](#notes--limitations)

- **State (CSRF) validation runs only in production** (`app()->isProduction()`). In local/testing environments the callback skips the state check for convenience.
- **No runtime query‑parameter overrides.** `success_redirect` and the callback URL come from config/env only; passing `?success_redirect=` or `?callback_url=` to the redirect route has no effect in the current version.

Documentation
-------------

[](#documentation)

For a complete, beginner‑friendly, step‑by‑step walkthrough — wiring up login, handling the token, the client‑credentials flow, JWT verification, and troubleshooting — see **[docs/GUIDE.md](docs/GUIDE.md)**.

Credits
-------

[](#credits)

Developed and maintained by the **Esanj Tech Team**.

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance89

Actively maintained with recent releases

Popularity12

Limited adoption so far

Community16

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 75% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~45 days

Total

9

Last Release

39d ago

PHP version history (4 changes)v0.1PHP ^8.0

v0.1.6PHP ^8.1

v0.1.8PHP ^8.1|^8.2|^8.3

v0.1.9PHP ^8.1|^8.2|^8.3|^8.4

### Community

Maintainers

![](https://www.gravatar.com/avatar/c908dfdf092a072c4bc678b161b053e20d00f90e9e9ba2c18ecddef6b848f1a4?d=identicon)[esanj](/maintainers/esanj)

---

Top Contributors

[![itsalifadaei](https://avatars.githubusercontent.com/u/34383343?v=4)](https://github.com/itsalifadaei "itsalifadaei (15 commits)")[![mr-mokhtari](https://avatars.githubusercontent.com/u/34773591?v=4)](https://github.com/mr-mokhtari "mr-mokhtari (5 commits)")

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/esanj-auth-bridge/health.svg)

```
[![Health](https://phpackages.com/badges/esanj-auth-bridge/health.svg)](https://phpackages.com/packages/esanj-auth-bridge)
```

###  Alternatives

[laravel/socialite

Laravel wrapper around OAuth 1 &amp; OAuth 2 libraries.

5.7k113.1M998](/packages/laravel-socialite)[psalm/plugin-laravel

Psalm plugin for Laravel

3345.4M354](/packages/psalm-plugin-laravel)[illuminate/auth

The Illuminate Auth package.

9328.5M1.4k](/packages/illuminate-auth)[api-platform/laravel

API Platform support for Laravel

58190.1k21](/packages/api-platform-laravel)[masterix21/laravel-licensing

Laravel licensing package with polymorphic assignment to any model, activation keys, expirations/renewals, and seat control via LicenseUsage. Supports offline verification with public-key–signed tokens, a CLI to generate/rotate/revoke keys, and an extensible architecture via config and contracts.

1614.1k4](/packages/masterix21-laravel-licensing)[forjedio/inertia-table

Backend-driven dynamic tables for Laravel + Inertia.js

272.0k](/packages/forjedio-inertia-table)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
