PHPackages                             whilesmart/eloquent-client-credentials - 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. whilesmart/eloquent-client-credentials

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

whilesmart/eloquent-client-credentials
======================================

Add client credentials authentication to any Eloquent model

00PHP

Since Dec 9Pushed 3mo agoCompare

[ Source](https://github.com/whilesmartphp/eloquent-client-credentials)[ Packagist](https://packagist.org/packages/whilesmart/eloquent-client-credentials)[ RSS](/packages/whilesmart-eloquent-client-credentials/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependenciesVersions (3)Used By (0)

Eloquent Client Credentials
===========================

[](#eloquent-client-credentials)

Add OAuth2 client credentials authentication to any Eloquent model.

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

[](#installation)

```
composer require whilesmart/eloquent-client-credentials
```

Publish the config file:

```
php artisan vendor:publish --tag=client-credentials-config
```

Run migrations:

```
php artisan migrate
```

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

[](#configuration)

```
// config/client-credentials.php
return [
    'default_model' => \Whilesmart\EloquentClientCredentials\Models\Client::class,

    'owner_resolver' => \Whilesmart\EloquentClientCredentials\Resolvers\DefaultOwnerResolver::class,

    'middleware_hooks' => [],

    'routes' => [
        'enabled' => false,
        'prefix' => 'api',
        'middleware' => [],
        'client_routes' => false,
    ],

    'oauth' => [
        'enabled' => true,
        'token_lifetime' => 3600,
        'refresh_token_lifetime' => 86400 * 30,
        'refresh_tokens_enabled' => false,
    ],
];
```

Usage
-----

[](#usage)

### Using the Default Client Model

[](#using-the-default-client-model)

Enable routes in your config:

```
'routes' => [
    'enabled' => true,
    'prefix' => 'api',
    'middleware' => ['auth:sanctum'],
    'client_routes' => true,
],
```

This registers the following routes:

MethodURIDescriptionPOST`/api/oauth/token`Issue access tokenPOST`/api/oauth/revoke`Revoke access tokenGET`/api/clients`List clientsPOST`/api/clients`Create clientGET`/api/clients/{slug}`Get clientPUT`/api/clients/{slug}`Update clientDELETE`/api/clients/{slug}`Delete clientPOST`/api/clients/{slug}/regenerate-secret`Regenerate secret### Adding Client Credentials to Your Own Model

[](#adding-client-credentials-to-your-own-model)

Use the `HasClientCredentials` trait:

```
use Whilesmart\EloquentClientCredentials\Traits\HasClientCredentials;

class ApiApp extends Model
{
    use HasClientCredentials;

    protected $fillable = ['name', 'secret', /* ... */];
}
```

The trait provides:

- `setSecret(string $plainSecret)` - Hash and store a secret
- `verifySecret(string $secret)` - Verify a plain secret against stored hash
- `regenerateSecret()` - Generate and store a new random secret
- `plainSecret` - Access the plain secret (only available immediately after creation/regeneration)

### Owner Resolver

[](#owner-resolver)

Configure how the owner is resolved for client operations. Create a custom resolver:

```
use Whilesmart\EloquentClientCredentials\Contracts\OwnerResolverInterface;

class CustomOwnerResolver implements OwnerResolverInterface
{
    public function resolve(Request $request): ?Model
    {
        return $request->user()->currentTeam;
    }
}
```

Register in config:

```
'owner_resolver' => \App\Resolvers\CustomOwnerResolver::class,
```

You can also pass an owner directly when using the controller programmatically:

```
$controller = app(ClientController::class);
$controller->store($request, $customOwner);
```

OAuth2 Token Flow
-----------------

[](#oauth2-token-flow)

### Issuing Tokens

[](#issuing-tokens)

**Client Credentials Grant:**

```
POST /api/oauth/token
Content-Type: application/json

{
    "grant_type": "client_credentials",
    "client_id": "your-client-id",
    "client_secret": "your-client-secret",
    "scope": "read write"
}
```

Response:

```
{
    "access_token": "...",
    "token_type": "Bearer",
    "expires_in": 3600,
    "scope": "read write",
    "refresh_token": "..."
}
```

**Refresh Token Grant** (when enabled):

```
POST /api/oauth/token
Content-Type: application/json

{
    "grant_type": "refresh_token",
    "refresh_token": "your-refresh-token"
}
```

### Revoking Tokens

[](#revoking-tokens)

```
POST /api/oauth/revoke
Authorization: Bearer your-access-token
```

Middleware
----------

[](#middleware)

### Bearer Token Authentication

[](#bearer-token-authentication)

Authenticate requests using OAuth2 bearer tokens:

```
Route::middleware('client.bearer')->group(function () {
    Route::get('/resource', fn () => 'Protected');
});

// With scope requirement
Route::middleware('client.bearer:admin')->get('/admin', fn () => 'Admin only');
```

### Basic Auth

[](#basic-auth)

Authenticate using HTTP Basic Authentication:

```
Route::middleware('client.basic')->group(function () {
    Route::get('/resource', fn () => 'Protected');
});
```

Credentials: `client_id:client_secret` base64 encoded.

### Header-Based Authentication

[](#header-based-authentication)

Authenticate using custom headers:

```
Route::middleware('client.auth')->group(function () {
    Route::get('/resource', fn () => 'Protected');
});
```

Headers required:

- `X-Client-ID: your-client-id`
- `X-Client-Secret: your-client-secret`

### Registering Middleware

[](#registering-middleware)

In your `bootstrap/app.php` or service provider:

```
use Whilesmart\EloquentClientCredentials\Http\Middleware\AuthenticateBearerToken;
use Whilesmart\EloquentClientCredentials\Http\Middleware\AuthenticateBasicAuth;
use Whilesmart\EloquentClientCredentials\Http\Middleware\AuthenticateClient;

->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'client.bearer' => AuthenticateBearerToken::class,
        'client.basic' => AuthenticateBasicAuth::class,
        'client.auth' => AuthenticateClient::class,
    ]);
})
```

Hook System
-----------

[](#hook-system)

Add custom logic before/after controller actions:

```
// config/client-credentials.php
'middleware_hooks' => [
    \App\Hooks\MyClientHook::class,
],
```

Create a hook class:

```
use Whilesmart\EloquentClientCredentials\Interfaces\MiddlewareHookInterface;

class MyClientHook implements MiddlewareHookInterface
{
    public function before(Request $request, string $action): ?Request
    {
        // Modify request or return null to continue
        return $request;
    }

    public function after(Request $request, JsonResponse $response, string $action): JsonResponse
    {
        // Modify response
        return $response;
    }
}
```

Available hook actions (from `HookAction` enum):

- `CLIENT_STORE`
- `CLIENT_UPDATE`
- `CLIENT_DELETE`
- `CLIENT_REGENERATE_SECRET`
- `TOKEN_ISSUE`
- `TOKEN_REVOKE`

Models
------

[](#models)

### Client

[](#client)

Default client model with:

- UUID primary key
- Sluggable name
- Polymorphic owner relationship
- Revocation support

### AccessToken

[](#accesstoken)

OAuth2 access tokens with:

- UUID primary key
- Polymorphic client relationship
- Scopes support
- Expiration and revocation

### RefreshToken

[](#refreshtoken)

Refresh tokens with:

- UUID primary key
- Linked to access token (cascades on delete)
- Expiration and revocation

Publishing Assets
-----------------

[](#publishing-assets)

```
# Config
php artisan vendor:publish --tag=client-credentials-config

# Migrations
php artisan vendor:publish --tag=client-credentials-migrations

# Language files
php artisan vendor:publish --tag=client-credentials-lang

# Routes
php artisan vendor:publish --tag=client-credentials-routes
```

Testing
-------

[](#testing)

```
composer test
```

License
-------

[](#license)

MIT

###  Health Score

19

—

LowBetter than 10% of packages

Maintenance53

Moderate activity, may be stable

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity16

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% 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.

### Community

Maintainers

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

---

Top Contributors

[![nfebe](https://avatars.githubusercontent.com/u/14317775?v=4)](https://github.com/nfebe "nfebe (18 commits)")

---

Tags

api-keysappsm2moauthoauth2

### Embed Badge

![Health badge](/badges/whilesmart-eloquent-client-credentials/health.svg)

```
[![Health](https://phpackages.com/badges/whilesmart-eloquent-client-credentials/health.svg)](https://phpackages.com/packages/whilesmart-eloquent-client-credentials)
```

###  Alternatives

[kartik-v/yii2-password

Useful password strength validation utilities for Yii Framework 2.0

761.2M17](/packages/kartik-v-yii2-password)

PHPackages © 2026

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