|
| 1 | +<p align="center"> |
| 2 | + <img src="bird.png"> |
| 3 | +</p> |
| 4 | +<p align="center"> |
| 5 | + |
| 6 | + <img src="https://img.shields.io/packagist/v/robsontenorio/laravel-keycloak-guard.svg" /> |
| 7 | + <img src="https://img.shields.io/packagist/dt/robsontenorio/laravel-keycloak-guard.svg" /> |
| 8 | + |
| 9 | +</p> |
| 10 | + |
| 11 | +# Simple Keycloak Guard for Laravel |
| 12 | + |
| 13 | +This package helps you authenticate users on a Laravel API based on JWT tokens generated from **Keycloak Server**. |
| 14 | + |
| 15 | + |
| 16 | +# Requirements |
| 17 | + |
| 18 | +✔️ I`m building an API with Laravel. |
| 19 | + |
| 20 | +✔️ I will not use Laravel Passport for authentication, because Keycloak Server will do the job. |
| 21 | + |
| 22 | +✔️ I already have an "users table", with unique identifiers, on my database. |
| 23 | + |
| 24 | +✔️ The frontend is a separated project. |
| 25 | + |
| 26 | +✔️ The frontend users authenticate **directly on Keycloak Server** to obtain a JWT token. This process have nothing to do with the Laravel API. |
| 27 | + |
| 28 | +✔️ The frontend keep the JWT token from Keycloak Server. |
| 29 | + |
| 30 | +✔️ The frontend make requests to the Laravel API, with that token. |
| 31 | + |
| 32 | + |
| 33 | + |
| 34 | +# The flow |
| 35 | + |
| 36 | +<p align="center"> |
| 37 | + <img src="flow.png"> |
| 38 | +</p> |
| 39 | + |
| 40 | + |
| 41 | +1. The frontend user authenticates on Keycloak Server |
| 42 | + |
| 43 | +1. The frontend user obtains a JWT token. |
| 44 | + |
| 45 | +1. In another moment, the frontend user makes a request to some protected endpoint on a Laravel API, with that token. |
| 46 | + |
| 47 | +1. The Laravel API (through `Keycloak Guard`) handle it. |
| 48 | + - Verify token signature. |
| 49 | + - Verify token structure. |
| 50 | + - Verify token expiration time. |
| 51 | + - Verify if my API allows `resource access` from token. |
| 52 | + |
| 53 | +1. If everything is ok, find the user on database and authenticate it on my API. |
| 54 | + |
| 55 | +1. Return response |
| 56 | + |
| 57 | +# Install |
| 58 | + |
| 59 | +Require the package |
| 60 | + |
| 61 | +``` |
| 62 | +composer require robsontenorio/laravel-keycloak-guard |
| 63 | +``` |
| 64 | + |
| 65 | +Publish the config file |
| 66 | + |
| 67 | +``` |
| 68 | +php artisan vendor:publish --provider="KeycloakGuard\KeycloakGuardServiceProvider" |
| 69 | +
|
| 70 | +``` |
| 71 | + |
| 72 | +# Configuration |
| 73 | + |
| 74 | +## Keycloack Guard |
| 75 | + |
| 76 | +The Keycloak Guard configuration can be handled from Laravel `.env` file. ⚠️ Be sure all strings **are trimmed.** |
| 77 | + |
| 78 | +```php |
| 79 | +<?php |
| 80 | + |
| 81 | +return [ |
| 82 | + 'realm_public_key' => env('KEYCLOAK_REALM_PUBLIC_KEY', null), |
| 83 | + |
| 84 | + 'user_provider_credential' => env('KEYCLOAK_USER_PROVIDER_CREDENTIAL', 'username'), |
| 85 | + |
| 86 | + 'token_principal_attribute' => env('KEYCLOAK_TOKEN_PRINCIPAL_ATTRIBUTE', 'preferred_username'), |
| 87 | + |
| 88 | + 'append_decoded_token' => env('KEYCLOAK_APPEND_DECODED_TOKEN', false), |
| 89 | + |
| 90 | + 'allowed_resources' => env('KEYCLOAK_ALLOWED_RESOURCES', null) |
| 91 | +]; |
| 92 | + |
| 93 | +``` |
| 94 | + |
| 95 | +✔️ **realm_public_key** |
| 96 | + |
| 97 | +*Required.* |
| 98 | + |
| 99 | +The Keycloack Server realm public key (string). |
| 100 | + |
| 101 | +✔️ **user_provider_credential** |
| 102 | + |
| 103 | +*Required. Default is `username`.* |
| 104 | + |
| 105 | + |
| 106 | +Any field from "users" table that contains the user unique identifier (eg. username, email, nickname). This will be confronted against `token_principal_attribute` attribute, while authenticating. |
| 107 | + |
| 108 | +✔️ **token_principal_attribute** |
| 109 | + |
| 110 | +*Required. Default is `preferred_username`.* |
| 111 | + |
| 112 | +The property from JWT token that contains the user identifier. |
| 113 | +This will be confronted against `user_provider_credential` attribute, while authenticating. |
| 114 | + |
| 115 | +✔️ **append_decoded_token** |
| 116 | + |
| 117 | +*Default is `false`.* |
| 118 | + |
| 119 | +Appends to the authenticated user the full decoded JWT token. Useful if you need to know roles, groups and another user info holded by JWT token. Even choosing `false`, you can also get it using `Auth::token()`, see API section. |
| 120 | + |
| 121 | +✔️ **allowed_resources** |
| 122 | + |
| 123 | +*Required* |
| 124 | + |
| 125 | +Usually you API should handle one *resource_access*. But, if you handle multiples, just use a comma separated list of allowed resources accepted by API. This attribute will be confronted against `resource_access` attribute from JWT token, while authenticating. |
| 126 | + |
| 127 | +## Laravel auth config |
| 128 | + |
| 129 | +Changes on `config/auth.php` |
| 130 | +```php |
| 131 | +'defaults' => [ |
| 132 | + 'guard' => 'api', # <-- For sure, i`m building an API |
| 133 | + 'passwords' => 'users', |
| 134 | + ], |
| 135 | + |
| 136 | + 'guards' => [ |
| 137 | + 'api' => [ |
| 138 | + 'driver' => 'keycloak', # <-- Set the API guard to "keycloack" |
| 139 | + 'provider' => 'users', |
| 140 | + ], |
| 141 | + ], |
| 142 | +``` |
| 143 | + |
| 144 | +# API |
| 145 | + |
| 146 | +Simple Keycloak Guard implements `Illuminate\Contracts\Auth\Guard`. So, all Laravel default methods will be available. Ex: `Auth::user()` returns the authenticated user. |
| 147 | + |
| 148 | +### Default methods: |
| 149 | + |
| 150 | +- check() |
| 151 | +- guest() |
| 152 | +- user() |
| 153 | +- id() |
| 154 | +- validate() |
| 155 | +- setUser() |
| 156 | + |
| 157 | + |
| 158 | +### Keycloak Guard methods: |
| 159 | + |
| 160 | +- token() |
| 161 | + |
| 162 | +Ex: `Auth::token()` returns full decoded JWT token from authenticated user |
| 163 | + |
| 164 | +# Contact |
| 165 | + |
| 166 | +Twitter [@robsontenorio](https://twitter.com/robsontenorio) |
0 commit comments