PHPackages                             overtrue/laravel-keycloak-guard - 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. overtrue/laravel-keycloak-guard

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

overtrue/laravel-keycloak-guard
===============================

🔑 Simple Keycloak Guard for Laravel

1.3.1(1y ago)46.8k↓76.8%2[1 PRs](https://github.com/overtrue/laravel-keycloak-guard/pulls)MITPHPPHP ^8.3CI failing

Since Jan 7Pushed 8mo agoCompare

[ Source](https://github.com/overtrue/laravel-keycloak-guard)[ Packagist](https://packagist.org/packages/overtrue/laravel-keycloak-guard)[ Docs](https://github.com/overtrue/laravel-keycloak-guard)[ RSS](/packages/overtrue-laravel-keycloak-guard/feed)WikiDiscussions master Synced yesterday

READMEChangelog (10)Dependencies (6)Versions (11)Used By (0)

 [![](bird.png)](bird.png)

 [![](https://camo.githubusercontent.com/abf09017dbcff4e73cdc99afcd8e57a34e5935b6edf2c5d80d168b56a38f8bfd/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6f766572747275652f6c61726176656c2d6b6579636c6f616b2d67756172642e737667)](https://camo.githubusercontent.com/abf09017dbcff4e73cdc99afcd8e57a34e5935b6edf2c5d80d168b56a38f8bfd/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6f766572747275652f6c61726176656c2d6b6579636c6f616b2d67756172642e737667) [![](https://camo.githubusercontent.com/5a1719c3394c5890cd427825215fc8020209c1616f7d6ee5a9d2a6a45dbe26bb/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6f766572747275652f6c61726176656c2d6b6579636c6f616b2d67756172642e737667)](https://camo.githubusercontent.com/5a1719c3394c5890cd427825215fc8020209c1616f7d6ee5a9d2a6a45dbe26bb/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6f766572747275652f6c61726176656c2d6b6579636c6f616b2d67756172642e737667) [ ![](https://camo.githubusercontent.com/9011a359f1a15cb699716968f32b261390463d4eeb1d4a5ff726a8315981836d/68747470733a2f2f636f6465636f762e696f2f6769746875622f6f766572747275652f6c61726176656c2d6b6579636c6f616b2d67756172642f67726170682f62616467652e7376673f746f6b656e3d3839514f425855345339) ](https://codecov.io/github/overtrue/laravel-keycloak-guard)

Simple Keycloak Guard for Laravel
=================================

[](#simple-keycloak-guard-for-laravel)

> A fork of [robsontenorio/laravel-keycloak-guard](https://github.com/robsontenorio/laravel-keycloak-guard) with additional features.

This package helps you authenticate users on a Laravel API based on JWT tokens generated from **Keycloak Server**.

Requirements
============

[](#requirements)

- Building an API with Laravel.
- Not using Laravel Passport for authentication, as Keycloak Server handles authentication.
- Frontend is a separate project.
- Frontend users authenticate directly on Keycloak Server to obtain a JWT token. This process is independent of the Laravel API.
- Frontend retains the JWT token from Keycloak Server.
- Frontend makes requests to the Laravel API with the JWT token.

**Note:** If your application does not meet these requirements, you might be looking for [Socialite Providers Keycloak](https://socialiteproviders.com/Keycloak) or [Vizir Laravel Keycloak Web Guard](https://github.com/Vizir/laravel-keycloak-web-guard).

The flow
========

[](#the-flow)

 [![Authentication Flow](flow.png)](flow.png)

1. The frontend user authenticates on Keycloak Server
2. The frontend user obtains a JWT token.
3. In another moment, the frontend user makes a request to some protected endpoint on a Laravel API, with that token.
4. The Laravel API (through `Keycloak Guard`) handle it.
    - Verify token signature.
    - Verify token structure.
    - Verify token expiration time.
    - Verify if my API allows `resource access` from token.
5. If everything is ok, then find the user on database and authenticate it on my API.
6. Optionally, the user can be created / updated in the API users database.
7. Return response

Installation
============

[](#installation)

Require the package via Composer:

```
composer require overtrue/laravel-keycloak-guard
```

### Example configuration (.env)

[](#example-configuration-env)

```
KEYCLOAK_TRUST_PROXY_USERINFO=false         # Trust the `x-userinfo` from the proxy server.
KEYCLOAK_PROXY_USERINFO_HEADER=x-userinfo   # The header name to look for the user info when `trust_proxy_userinfo` is enabled.
KEYCLOAK_REALM_PUBLIC_KEY=MIIBIj...         # Get it on Keycloak admin web console.
KEYCLOAK_LOAD_USER_FROM_DATABASE=false      # You can opt to not load user from database, and use that one provided from JWT token.
KEYCLOAK_ALLOWED_RESOURCES=my-api           # The JWT token must contain this resource `my-api`.
KEYCLOAK_LEEWAY=60                          # Optional, but solve some weird issues with timestamps from JWT token.
```

### Auth Guard

[](#auth-guard)

Update your `config/auth.php` to use the `keycloak` driver for API authentication.

```
'defaults' => [
    'guard' => 'api', // Set the default guard to 'api'.
    'passwords' => 'users',
],
'guards' => [
    'api' => [
        'driver' => 'keycloak', // Use 'keycloak' as the driver for the 'api' guard.
        'provider' => 'users',
    ],
],
```

### Routes

[](#routes)

Protect your API endpoints by applying the `auth:api` middleware in `routes/api.php`.

```
// public endpoints
Route::get('/hello', function () {
    return ':)';
});

// protected endpoints
Route::group(['middleware' => 'auth:api'], function () {
    Route::get('/protected-endpoint', 'SecretController@index');

    // ...
});
```

Any routes within the auth:api middleware group will require a valid JWT token issued by Keycloak Server for access.

Configuration
=============

[](#configuration)

Keycloak Guard
--------------

[](#keycloak-guard)

⚠️ When editing `.env`, ensure all strings **are trimmed** to avoid parsing issues.

```
php artisan vendor:publish  --provider="KeycloakGuard\KeycloakGuardServiceProvider"
```

Configuration Options
---------------------

[](#configuration-options)

Below are the configuration options available for Keycloak Guard:

### trust\_proxy\_userinfo

[](#trust_proxy_userinfo)

- **Type**: `boolean`
- **Default**: `false`
- **Description**: Trust the `x-userinfo` from the proxy server. This is useful when you are using a proxy server to authenticate users(for example, integrate with [APISIX](https://apisix.apache.org/zh/docs/apisix/plugins/openid-connect/)).

### proxy\_userinfo\_header

[](#proxy_userinfo_header)

- **Type**: `string`
- **Default**: `x-userinfo`
- **Description**: The header name to look for the user info when `trust_proxy_userinfo` is enabled.

### keycloak\_base\_url

[](#keycloak_base_url)

- **Type**: `string`
- **Required**: No (required without `realm_public_key`)
- **Default**: null
- **Description**: The base URL of your Keycloak server. This is the URL where your Keycloak instance is hosted.

### keycloak\_realm

[](#keycloak_realm)

- **Type**: `string`
- **Required**: No (required without `realm_public_key`)
- **Description**: The name of the Keycloak realm you are using. This is the realm where your users and clients are defined.

### realm\_public\_key

[](#realm_public_key)

- **Type**: `string`
- **Required**: No (required without `keycloak_base_url` + `keycloak_realm`)
- **Ignored when**: `trust_proxy_userinfo` is `true`
- **Description**: The public key of your Keycloak realm. Obtain it from the Keycloak admin console under “**Realm Settings**” &gt; “**Keys**” &gt; “**Public Key**”.

### token\_encryption\_algorithm

[](#token_encryption_algorithm)

- **Type**: `string`
- **Default**: `RS256`
- **Ignored when**: `trust_proxy_userinfo` is `true`
- **Description**: The JWT token encryption algorithm used by Keycloak.

### load\_user\_from\_database

[](#load_user_from_database)

- **Type**: `boolean`
- **Default**: `true`
- **Description**: Determines whether to load the user from the database. Set to false if you do not have a `users` table or prefer not to load users from the database, the user object will be created from `\Keycloak\User` class.

### user\_provider\_custom\_retrieve\_method

[](#user_provider_custom_retrieve_method)

- **Type**: `string|null`
- **Default**: `null`
- **Ignored when**: load\_user\_from\_database is `false`
- **Description**: Specifies a custom method in your user provider to retrieve users based on the decoded token. Requires `load_user_from_database` to be `true`.

### user\_provider\_credential

[](#user_provider_credential)

- **Type**: `string`
- **Default**: `username`
- **Description**: The field in the `users` table used to identify the user (e.g., `username`, `email`).

### token\_principal\_attribute

[](#token_principal_attribute)

- **Type**: `string`
- **Default**: `preferred_username`
- **Description**: The attribute in the JWT token that contains the user identifier.

### allowed\_resources

[](#allowed_resources)

- **Type**: `string`
- **Required**: No
- **Ignored when**: `trust_proxy_userinfo` is `true`
- **Description**: A comma-separated list of resources that the JWT token must contain for access.

### ignore\_resources\_validation

[](#ignore_resources_validation)

- **Type**: `boolean`
- **Default**: `true`
- **Ignored when**: `trust_proxy_userinfo` is `true`
- **Description**: Disables resource validation, ignoring the allowed\_resources configuration.

### leeway

[](#leeway)

- **Type**: `integer`
- **Default**: `0`
- **Ignored when**: `trust_proxy_userinfo` is `true`
- **Description**: Adds a leeway (in seconds) to account for clock skew between servers. Useful for resolving timestamp-related token issues.

### input\_key

[](#input_key)

- **Type**: `string|null`
- **Default**: `null`
- **Ignored when**: `trust_proxy_userinfo` is `true`
- **Description**: If set, the guard will look for a token in this custom request parameter in addition to the Bearer token.

**Example Usage**:

```
// keycloak.php
'input_key' => 'api_token'
```

With this configuration, if there is no Bearer token in the request, the guard will use the api\_token request parameter:

- **GET** request: `/foo/secret?api_token=xxxxx`
- **POST** request: `/foo/secret` with `["api_token" => "xxxxx"]` in the body.

API
===

[](#api)

Simple Keycloak Guard implements `Illuminate\Contracts\Auth\Guard`. So, all Laravel default methods will be available.

Default Laravel methods
-----------------------

[](#default-laravel-methods)

- `check()`
- `guest()`
- `user()`
- `id()`
- `validate()`
- `setUser()`

Keycloak Guard methods
----------------------

[](#keycloak-guard-methods)

#### Token

[](#token)

`token()`

*Returns full decoded JWT token from authenticated user.*

```
$token = Auth::token()  // or Auth::user()->token()
```

#### Role

[](#role)

`hasRole('some-resource', 'some-role')`

*Check if authenticated user has a role on resource\_access*

```
// Example decoded payload

'resource_access' => [
  'myapp-backend' => [
      'roles' => [
        'myapp-backend-role1',
        'myapp-backend-role2'
      ]
  ],
  'myapp-frontend' => [
    'roles' => [
      'myapp-frontend-role1',
      'myapp-frontend-role2'
    ]
  ]
]
```

```
Auth::hasRole('myapp-backend', 'myapp-backend-role1') // true
Auth::hasRole('myapp-frontend', 'myapp-frontend-role1') // true
Auth::hasRole('myapp-backend', 'myapp-frontend-role1') // false
```

`hasAnyRole('some-resource', ['some-role1', 'some-role2'])`

*Check if the authenticated user has any of the roles in resource\_access*

```
Auth::hasAnyRole('myapp-backend', ['myapp-backend-role1', 'myapp-backend-role3']) // true
Auth::hasAnyRole('myapp-frontend', ['myapp-frontend-role1', 'myapp-frontend-role3']) // true
Auth::hasAnyRole('myapp-backend', ['myapp-frontend-role1', 'myapp-frontend-role2']) // false
```

#### Scope

[](#scope)

Example decoded payload:

```
{
    "scope": "scope-a scope-b scope-c",
}
```

`scopes()`

*Get all user scopes*

```
array:3 [
  0 => "scope-a"
  1 => "scope-b"
  2 => "scope-c"
]
```

`hasScope('some-scope')`

*Check if authenticated user has a scope*

```
Auth::hasScope('scope-a') // true
Auth::hasScope('scope-d') // false
```

`hasAnyScope(['scope-a', 'scope-c'])`

*Check if the authenticated user has any of the scopes*

```
Auth::hasAnyScope(['scope-a', 'scope-c']) // true
Auth::hasAnyScope(['scope-a', 'scope-d']) // true
Auth::hasAnyScope(['scope-f', 'scope-k']) // false
```

Acting as a Keycloak user in tests
----------------------------------

[](#acting-as-a-keycloak-user-in-tests)

As an equivalent feature like `$this->actingAs($user)` in Laravel, with this package you can use `KeycloakGuard\ActingAsKeycloakUser` trait in your test class and then use `actingAsKeycloakUser()` method to act as a user and somehow skip the Keycloak auth:

```
use KeycloakGuard\ActingAsKeycloakUser;

public test_a_protected_route()
{
    $this->actingAsKeycloakUser()
        ->getJson('/api/somewhere')
        ->assertOk();
}
```

If you are not using `keycloak.load_user_from_database` option, set `keycloak.preferred_username` with a valid `preferred_username` for tests.

You can also specify exact expectations for the token payload by passing the payload array in the second argument:

```
use KeycloakGuard\ActingAsKeycloakUser;

public test_a_protected_route()
{
    $this->actingAsKeycloakUser($user, [
        'aud' => 'account',
        'exp' => 1715926026,
        'iss' => 'https://localhost:8443/realms/master'
    ])->getJson('/api/somewhere')
      ->assertOk();
}
```

`$user` argument receives a string identifier or an Eloquent model, identifier of which is expected to be the property referred in **user\_provider\_credential** config. Whatever you pass in the payload will override default claims, which includes `aud`, `iat`, `exp`, `iss`, `azp`, `resource_access` and either `sub` or `preferred_username`, depending on **token\_principal\_attribute** config.

Alternatively, payload can be provided in a class property, so it can be reused across multiple tests:

```
use KeycloakGuard\ActingAsKeycloakUser;

protected $tokenPayload = [
    'aud' => 'account',
    'exp' => 1715926026,
    'iss' => 'https://localhost:8443/realms/master'
];

public test_a_protected_route()
{
    $payload = [
        'exp' => 1715914352
    ];
    $this->actingAsKeycloakUser($user, $payload)
        ->getJson('/api/somewhere')
        ->assertOk();
}
```

Priority is given to the claims in passed as an argument, so they will override ones in the class property. `$user` argument has the highest priority over the claim referred in `token_principal_attribute` config.

Contribute
==========

[](#contribute)

Contributions are welcome! To contribute to this project, please follow these steps:

1. **Fork the Repository**
2. Click the "Fork" button at the top right of the repository page to create your own fork.
3. **Clone Your Fork**

```
git clone https://github.com/yourusername/your-forked-package.git
cd your-forked-package
```

3. Create a New Branch

```
git checkout -b feature/your-feature-name
```

4. Make Your Changes

- Implement your feature or bug fix.
- Ensure your code follows the project’s coding standards.

5. Run Tests

```
composer install
composer test
```

6. Commit Your Changes

```
git commit -m "Add feature: your feature description"
```

7. Push to Your Fork

```
git push origin feature/your-feature-name
```

8. Create a Pull Request

- Navigate to your forked repository on GitHub.
- Click the “Compare &amp; pull request” button.
- Provide a clear description of your changes and submit the Pull Request.

For more detailed guidelines, please refer to the CONTRIBUTING.md file.

Credits
=======

[](#credits)

This project is a fork of the original work by [Robson Tenório](https://github.com/robsontenorio). Special thanks to Robson for creating and maintaining the original codebase, which served as the foundation for this project. Your contributions and dedication to open-source development are greatly appreciated!

Contact
=======

[](#contact)

You can reach me on [Twitter](https://twitter.com/overtrue666) or [create an issue](https://github.com/overtrue/laravel-keycloak-guard/issues/new).

License
=======

[](#license)

MIT

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance53

Moderate activity, may be stable

Popularity28

Limited adoption so far

Community19

Small or concentrated contributor base

Maturity60

Established project with proven stability

 Bus Factor2

2 contributors hold 50%+ of commits

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 ~9 days

Recently: every ~2 days

Total

10

Last Release

458d ago

PHP version history (2 changes)1.0.0PHP ^8.0

1.0.1PHP ^8.3

### Community

Maintainers

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

---

Top Contributors

[![robsontenorio](https://avatars.githubusercontent.com/u/118955?v=4)](https://github.com/robsontenorio "robsontenorio (26 commits)")[![overtrue](https://avatars.githubusercontent.com/u/1472352?v=4)](https://github.com/overtrue "overtrue (21 commits)")[![Copilot](https://avatars.githubusercontent.com/in/1143301?v=4)](https://github.com/Copilot "Copilot (2 commits)")[![vlauciani](https://avatars.githubusercontent.com/u/16477095?v=4)](https://github.com/vlauciani "vlauciani (2 commits)")[![hamidhaghdoost](https://avatars.githubusercontent.com/u/8298095?v=4)](https://github.com/hamidhaghdoost "hamidhaghdoost (2 commits)")[![luizjr](https://avatars.githubusercontent.com/u/1474563?v=4)](https://github.com/luizjr "luizjr (1 commits)")[![marwins](https://avatars.githubusercontent.com/u/20090626?v=4)](https://github.com/marwins "marwins (1 commits)")[![matsver](https://avatars.githubusercontent.com/u/42805709?v=4)](https://github.com/matsver "matsver (1 commits)")[![OfficialBAMM](https://avatars.githubusercontent.com/u/10955512?v=4)](https://github.com/OfficialBAMM "OfficialBAMM (1 commits)")[![peter279k](https://avatars.githubusercontent.com/u/9021747?v=4)](https://github.com/peter279k "peter279k (1 commits)")[![ptrgast](https://avatars.githubusercontent.com/u/10983711?v=4)](https://github.com/ptrgast "ptrgast (1 commits)")[![roberto-proj](https://avatars.githubusercontent.com/u/121515667?v=4)](https://github.com/roberto-proj "roberto-proj (1 commits)")[![SolveSoul](https://avatars.githubusercontent.com/u/6033289?v=4)](https://github.com/SolveSoul "SolveSoul (1 commits)")[![Androbin](https://avatars.githubusercontent.com/u/16437156?v=4)](https://github.com/Androbin "Androbin (1 commits)")[![wjfz](https://avatars.githubusercontent.com/u/3372236?v=4)](https://github.com/wjfz "wjfz (1 commits)")[![antonkomarev](https://avatars.githubusercontent.com/u/1849174?v=4)](https://github.com/antonkomarev "antonkomarev (1 commits)")[![dfeneck](https://avatars.githubusercontent.com/u/78724526?v=4)](https://github.com/dfeneck "dfeneck (1 commits)")[![elnurvl](https://avatars.githubusercontent.com/u/7970970?v=4)](https://github.com/elnurvl "elnurvl (1 commits)")[![frital](https://avatars.githubusercontent.com/u/17753531?v=4)](https://github.com/frital "frital (1 commits)")

---

Tags

laravelkeycloak

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/overtrue-laravel-keycloak-guard/health.svg)

```
[![Health](https://phpackages.com/badges/overtrue-laravel-keycloak-guard/health.svg)](https://phpackages.com/packages/overtrue-laravel-keycloak-guard)
```

###  Alternatives

[robsontenorio/laravel-keycloak-guard

🔑 Simple Keycloak Guard for Laravel

5181.2M3](/packages/robsontenorio-laravel-keycloak-guard)[stevenmaguire/oauth2-keycloak

Keycloak OAuth 2.0 Client Provider for The PHP League OAuth2-Client

2306.4M45](/packages/stevenmaguire-oauth2-keycloak)[ellaisys/aws-cognito

Laravel Authentication using AWS Cognito (Web and API)

123256.9k1](/packages/ellaisys-aws-cognito)[kovah/laravel-socialite-oidc

OpenID Connect OAuth2 Provider for Laravel Socialite

24133.5k](/packages/kovah-laravel-socialite-oidc)

PHPackages © 2026

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