### Install Package and Publish Config Source: https://context7.com/365werk/jwtauthroles/llms.txt Install the package via Composer and publish its configuration and migration files. Migrations are only needed if database caching or user persistence is enabled. ```bash composer require werk365/jwtauthroles php artisan vendor:publish --provider="Werk365\JwtAuthRoles\JwtAuthRolesServiceProvider" php artisan migrate ``` -------------------------------- ### Environment Variables for FusionAuth PEM Setup Source: https://context7.com/365werk/jwtauthroles/llms.txt Example `.env` file settings for a typical FusionAuth setup using the PEM endpoint for JWT validation. ```ini # .env — typical FusionAuth setup using the PEM endpoint FA_ALG=RS256 FA_VALIDATE=true FA_USE_DB=true FA_CREATE_USR=true FA_STORE_ROLES=true FA_USER_MODEL=App\Models\User FA_USR_ID=uuid FA_CACHE_ENABLED=true FA_CACHE_TYPE=database PEM_URL=https://auth.example.com/api/jwt/public-key USE_JWK=false ``` -------------------------------- ### Install Package with Composer Source: https://github.com/365werk/jwtauthroles/blob/master/readme.md Use Composer to add the jwtauthroles package to your project. ```bash $ composer require werk365/jwtauthroles ``` -------------------------------- ### Customize JWT Error Responses Source: https://context7.com/365werk/jwtauthroles/llms.txt Example of how to customize the exception handler to format `AuthException` responses. This allows for consistent JSON error reporting. ```php use Werk365\JwtAuthRoles\Exceptions\AuthException; public function render($request, Throwable $exception) { if ($exception instanceof AuthException) { return response()->json([ 'error' => $exception->getMessage(), 'status' => $exception->getStatusCode(), ], $exception->getStatusCode()); } return parent::render($request, $exception); } ``` -------------------------------- ### Run Database Migrations Source: https://github.com/365werk/jwtauthroles/blob/master/readme.md Execute database migrations to set up necessary tables, if configured. ```bash $ php artisan migrate ``` -------------------------------- ### Publish and Run Migrations Source: https://context7.com/365werk/jwtauthroles/llms.txt Commands to publish the package's service provider and run database migrations. This is necessary when database features are enabled. ```bash php artisan vendor:publish --provider="Werk365\JwtAuthRoles\JwtAuthRolesServiceProvider" php artisan migrate php artisan db:show --counts ``` -------------------------------- ### Publish Configuration and Migrations Source: https://github.com/365werk/jwtauthroles/blob/master/readme.md Publish the package's configuration file and database migrations using the Artisan command. ```bash $ php artisan vendor:publish --provider="Werk365\JwtAuthRoles\JwtAuthRolesServiceProvider" ``` -------------------------------- ### Default Configuration File Source: https://github.com/365werk/jwtauthroles/blob/master/readme.md Review and configure package settings, including database usage, JWT validation, and JWK/PEM endpoints. ```php env('FA_USE_DB', false), // Only if useDB = true // Column name in the users table where uuid should be stored.' 'userId' => env('FA_USR_ID', 'uuid'), // Only if useDB = true 'autoCreateUser' => env('FA_CREATE_USR', false), 'alg' => env('FA_ALG', 'RS256'), // Allows you to skip validation, this is potentially dangerous, // only use for testing or if the jwt has been validated by something like an api gateway 'validateJwt' => env('FA_VALIDATE', true), // Only if validateJwt = true 'cache' => [ 'enabled' => env('FA_CACHE_ENABLED', false), 'type' => env('FA_CACHE_TYPE', 'database'), ], // Only if validateJwt = true 'jwkUri' => env('JWKS_URL', 'http://localhost:9011/.well-known/jwks.json'), // Only if validateJwt = true 'pemUri' => env('PEM_URL', 'http://localhost:9011/api/jwt/public-key'), // Only if validateJwt = true // Configure to use PEM endpoint (default) or JWK 'useJwk' => env('USE_JWK', false), ]; ``` -------------------------------- ### Configuration File (`config/jwtauthroles.php`) Source: https://context7.com/365werk/jwtauthroles/llms.txt Configure the package's behavior, including user model, database persistence, JWT validation, caching, and JWKS/PEM endpoints. Values can be overridden by environment variables. ```php // config/jwtauthroles.php return [ // The base User model JwtUser should extend (default: App\Models\User) 'userModel' => env('FA_USER_MODEL', 'App\\Models\\User'), // Persist authenticated users to the jwt_users table 'useDB' => env('FA_USE_DB', false), // Persist the user's roles array to the database on every request 'storeRoles' => env('FA_STORE_ROLES', true), // Column in the users table that stores the identity-provider UUID 'userId' => env('FA_USR_ID', 'uuid'), // Auto-create a DB row for first-time users (requires useDB = true) 'autoCreateUser' => env('FA_CREATE_USR', false), // JWT signing algorithm expected by the identity provider 'alg' => env('FA_ALG', 'RS256'), // Set false only in testing or behind a trusted API gateway 'validateJwt' => env('FA_VALIDATE', true), // Cache fetched public keys in the jwt_keys table 'cache' => [ 'enabled' => env('FA_CACHE_ENABLED', false), 'type' => env('FA_CACHE_TYPE', 'database'), ], // JWKS endpoint (used when useJwk = true) 'jwkUri' => env('JWKS_URL', 'http://localhost:9011/.well-known/jwks.json'), // PEM public-key endpoint (used when useJwk = false — the default) 'pemUri' => env('PEM_URL', 'http://localhost:9011/api/jwt/public-key'), // Switch from PEM (default) to JWK-based validation 'useJwk' => env('USE_JWK', false), ]; ``` -------------------------------- ### Configure Auth Guards and Providers Source: https://github.com/365werk/jwtauthroles/blob/master/readme.md Update config/auth.php to include a 'jwt' guard and a 'jwt_users' provider. ```php 'guards' => [ // ... 'jwt' => [ 'driver' => 'jwt', 'provider' => 'jwt_users', 'hash' => false, ], ], // ... 'providers' => [ // ... 'jwt_users' => [ 'driver' => 'eloquent', 'model' => JwtUser::class, ], ], ``` -------------------------------- ### Apply Role Middleware to Routes Source: https://github.com/365werk/jwtauthroles/blob/master/readme.md Use the 'role' middleware for single or multiple role-based access control on routes. ```php // single role Route::get('/exammple', function(){ return "example"; })->middleware('role:example'); // multiple roles Route::get('/exammples', function(){ return "examples"; })->middleware('role:example|second|third|etc'); ``` -------------------------------- ### Create JWT Auth Tables Migration Source: https://context7.com/365werk/jwtauthroles/llms.txt This migration stub creates the `jwt_keys` and `jwt_users` tables. The `jwt_keys` table caches public keys, and `jwt_users` persists authenticated user data. ```php Schema::create('jwt_keys', function (Blueprint $table) { $table->id(); $table->string('kid'); // Key ID from JWT header, used to look up the correct key $table->json('key'); // PEM-encoded public key string $table->timestamps(); }); Schema::create('jwt_users', function (Blueprint $table) { $table->id(); $table->uuid('uuid'); // Subject claim (sub) from the JWT — identity-provider user ID $table->json('roles'); // Roles array from the JWT payload $table->json('claims'); // Full decoded JWT claims object $table->timestamps(); }); ``` -------------------------------- ### Authenticate User with JWT Source: https://context7.com/365werk/jwtauthroles/llms.txt Extracts a bearer token, validates it, decodes claims, and returns a JwtUser. If useDB is enabled, it persists or retrieves the user from the database. This is the primary entry point for authentication. ```php use Illuminate\Http\Request; use Werk365\JwtAuthRoles\JwtAuthRoles; // In a controller or middleware (guard calls this internally): $user = JwtAuthRoles::authUser($request); // $user->uuid — the `sub` claim from the token // $user->roles — array/json of roles from the token // $user->claims — full decoded token payload // Direct usage example (e.g., in a custom middleware): Route::middleware('auth:jwt')->get('/profile', function () { $user = Auth::user(); // JwtUser instance return [ 'uuid' => $user->uuid, 'roles' => $user->roles, 'claims' => $user->claims, ]; // {"uuid":"a1b2c3d4-...","roles":["admin","editor"],"claims":{...}} }); ``` -------------------------------- ### Apply JWT Guard to Routes Source: https://github.com/365werk/jwtauthroles/blob/master/readme.md Protect a group of routes using the 'auth:jwt' middleware. ```php Route::group(['middleware' => ['auth:jwt']], function () { // Routes can go here }); ``` -------------------------------- ### Access User Relationships Source: https://github.com/365werk/jwtauthroles/blob/master/readme.md Retrieve related data, like documents, for the authenticated user. ```php return Auth::user()->documents; ``` -------------------------------- ### Define User Model Relationship Source: https://github.com/365werk/jwtauthroles/blob/master/readme.md Extend the default User model to include relationships, such as 'documents', using the 'uuid' from the JWT. ```php public function documents() { return $this->hasMany('App\Models\Document', 'user', 'uuid'); } ``` -------------------------------- ### Possible AuthException Errors and Status Codes Source: https://context7.com/365werk/jwtauthroles/llms.txt A list of potential `AuthException` errors and their corresponding HTTP status codes, useful for debugging and understanding validation failures. ```text 422 — "Malformed JWT" (token is not header.payload.signature) 422 — "Invalid algorithm" (token alg header doesn't match config) 422 — "Malformed JWT" (no kid in header) 404 — "jwks endpoint not found" 404 — "No JWKs found" 404 — "pem not found" 500 — "Malformed jwk" (JWK missing e or n fields) 500 — "Unable to validate JWT" 401 — "Unauthorized" (kid not found in JWKS) 401 — "User does not have right roles" ``` -------------------------------- ### Register JWT Auth Driver Source: https://github.com/365werk/jwtauthroles/blob/master/readme.md Modify your AuthServiceProvider to register a custom JWT authentication driver. ```php use Illuminate\Support\Facades\Auth; use Werk365\JwtAuthRoles\JwtAuthRoles; public function boot() { $this->registerPolicies(); Auth::viaRequest('jwt', function ($request) { return JwtAuthRoles::authUser($request); }); } ``` -------------------------------- ### Register JWT Guard in `AuthServiceProvider` Source: https://context7.com/365werk/jwtauthroles/llms.txt Integrate the JWT guard into Laravel's authentication system by registering a custom driver. This allows `Auth::user()` to resolve JWT-authenticated users. ```php // app/Providers/AuthServiceProvider.php namespace App\Providers; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; use Illuminate\Support\Facades\Auth; use Werk365\JwtAuthRoles\JwtAuthRoles; class AuthServiceProvider extends ServiceProvider { protected $policies = []; public function boot() { $this->registerPolicies(); // Register the JWT driver: on every guarded request, authUser() is called Auth::viaRequest('jwt', function ($request) { return JwtAuthRoles::authUser($request); }); } } ``` -------------------------------- ### Role-Based Access Control Middleware Source: https://context7.com/365werk/jwtauthroles/llms.txt A route middleware ('role') that checks if the authenticated JWT user has at least one of the required roles. Roles are read from the JwtUser instance. Multiple roles can be specified using pipe-delimited format. ```php // routes/api.php use Illuminate\Support\Facades\Route; // Protect a route group with the JWT guard Route::middleware('auth:jwt')->group(function () { // Single role required Route::get('/admin/dashboard', function () { return response()->json(['message' => 'Welcome, admin']); })->middleware('role:admin'); // Any one of multiple roles grants access Route::get('/content', function () { return response()->json(['message' => 'Welcome, editor or viewer']); })->middleware('role:editor|viewer|admin'); // No role restriction — only valid JWT required Route::get('/me', function () { return response()->json(Auth::user()); }); }); // Role check failure throws AuthException (HTTP 401): // {"message": "User does not have right roles"} ``` -------------------------------- ### Extend JwtUser with Custom Relationships Source: https://context7.com/365werk/jwtauthroles/llms.txt JwtUser extends the application's configured User model, inheriting its relationships. Define relationships in your base User model (e.g., App\Models\User) to make them available on the authenticated JwtUser instance. ```php // app/Models/User.php — add relationships that JwtUser will inherit namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable { // JwtUser inherits this relationship automatically public function documents() { // 'user' column in documents table stores the identity-provider UUID return $this->hasMany(\App\Models\Document::class, 'user', 'uuid'); } public function permissions() { return $this->hasMany(\App\Models\Permission::class, 'user_uuid', 'uuid'); } } // In a controller protected by auth:jwt Route::middleware('auth:jwt')->get('/my-documents', function () { $user = Auth::user(); // JwtUser instance return [ 'uuid' => $user->uuid, 'roles' => $user->roles, 'documents' => $user->documents, // uses inherited relationship ]; }); ``` -------------------------------- ### JwtUser Model Source: https://context7.com/365werk/jwtauthroles/llms.txt The `JwtUser` model extends the application's configured User model, inheriting its relationships. It uses the `jwt` guard and provides `uuid`, `roles`, and `claims` as fillable attributes. ```APIDOC ## `JwtUser` Model `JwtUser` extends the application's configured User model (`App\Models\User` by default), meaning all relationships defined on the base User model are available on the authenticated JWT user. The model uses the `jwt` guard and exposes `uuid`, `roles`, and `claims` as fillable attributes. ```php // app/Models/User.php — add relationships that JwtUser will inherit namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable { // JwtUser inherits this relationship automatically public function documents() { // 'user' column in documents table stores the identity-provider UUID return $this->hasMany(\App\Models\Document::class, 'user', 'uuid'); } public function permissions() { return $this->hasMany(\App\Models\Permission::class, 'user_uuid', 'uuid'); } } // In a controller protected by auth:jwt Route::middleware('auth:jwt')->get('/my-documents', function () { $user = Auth::user(); // JwtUser instance return [ 'uuid' => $user->uuid, 'roles' => $user->roles, 'documents' => $user->documents, // uses inherited relationship ]; }); ``` ``` -------------------------------- ### Role Middleware Source: https://context7.com/365werk/jwtauthroles/llms.txt A route middleware aliased as `role` that checks if the authenticated JWT user possesses at least one of the specified roles. Roles are validated against the `JwtUser` instance. ```APIDOC ## `RoleMiddleware` — `role` Middleware A route middleware (aliased as `role`) that enforces that the currently authenticated JWT user holds at least one of the required roles. Roles are read directly from the `JwtUser` instance set by the JWT guard. Multiple roles are pipe-delimited. ```php // routes/api.php use Illuminate\Support\Facades\Route; // Protect a route group with the JWT guard Route::middleware('auth:jwt')->group(function () { // Single role required Route::get('/admin/dashboard', function () { return response()->json(['message' => 'Welcome, admin']); })->middleware('role:admin'); // Any one of multiple roles grants access Route::get('/content', function () { return response()->json(['message' => 'Welcome, editor or viewer']); })->middleware('role:editor|viewer|admin'); // No role restriction — only valid JWT required Route::get('/me', function () { return response()->json(Auth::user()); }); }); // Role check failure throws AuthException (HTTP 401): // {"message": "User does not have right roles"} ``` ``` -------------------------------- ### JwtAuthRoles::authUser(Request $request): JwtUser Source: https://context7.com/365werk/jwtauthroles/llms.txt The main method to authenticate a user from an incoming request. It extracts the bearer token, validates it, decodes claims, and returns a JwtUser instance. If `useDB` is enabled, it interacts with the database. ```APIDOC ## `JwtAuthRoles::authUser(Request $request): JwtUser` The primary entry point of the package. Extracts the bearer token from the incoming request, optionally validates its signature using the configured public-key endpoint, decodes the claims, and returns a hydrated `JwtUser` instance. When `useDB` is enabled, the user is persisted or retrieved from the database. ```php // Called automatically by the JWT guard — shown here for illustration use Illuminate\Http\Request; use Werk365\JwtAuthRoles\JwtAuthRoles; // In a controller or middleware (guard calls this internally): $user = JwtAuthRoles::authUser($request); // $user->uuid — the `sub` claim from the token // $user->roles — array/json of roles from the token // $user->claims — full decoded token payload // Direct usage example (e.g., in a custom middleware): Route::middleware('auth:jwt')->get('/profile', function () { $user = Auth::user(); // JwtUser instance return [ 'uuid' => $user->uuid, 'roles' => $user->roles, 'claims' => $user->claims, ]; // {"uuid":"a1b2c3d4-...","roles":["admin","editor"],"claims":{...}} }); ``` ``` -------------------------------- ### JwtAuthRoles::getClaims(string $jwt): object Source: https://context7.com/365werk/jwtauthroles/llms.txt Decodes the JWT payload without verifying the signature. This is useful for inspecting token contents when validation is handled externally, such as by an API gateway. ```APIDOC ## `JwtAuthRoles::getClaims(string $jwt): object` Decodes the JWT payload without verifying the signature and returns the claims as a plain object. Useful for inspecting token contents in situations where validation has already been handled upstream (e.g., by an API gateway). ```php use Werk365\JwtAuthRoles\JwtAuthRoles; use Werk365\JwtAuthRoles\Exceptions\AuthException; $jwt = $request->bearerToken(); try { $claims = JwtAuthRoles::getClaims($jwt); echo $claims->sub; // "a1b2c3d4-5678-90ab-cdef-1234567890ab" echo $claims->email; // "user@example.com" print_r($claims->roles); // ["admin", "editor"] echo $claims->exp; // 1700000000 (Unix timestamp) } catch (AuthException $e) { // Thrown with HTTP 422 if the JWT is not in header.payload.signature format return response()->json(['error' => $e->getMessage()], $e->getStatusCode()); } ``` ``` -------------------------------- ### Decode JWT Claims Without Verification Source: https://context7.com/365werk/jwtauthroles/llms.txt Decodes JWT payload without signature verification, returning claims as a plain object. Useful when validation is handled upstream, like by an API gateway. Throws AuthException if JWT format is invalid. ```php use Werk365\JwtAuthRoles\JwtAuthRoles; use Werk365\JwtAuthRoles\Exceptions\AuthException; $jwt = $request->bearerToken(); try { $claims = JwtAuthRoles::getClaims($jwt); echo $claims->sub; // "a1b2c3d4-5678-90ab-cdef-1234567890ab" echo $claims->email; // "user@example.com" print_r($claims->roles); // ["admin", "editor"] echo $claims->exp; // 1700000000 (Unix timestamp) } catch (AuthException $e) { // Thrown with HTTP 422 if the JWT is not in header.payload.signature format return response()->json(['error' => $e->getMessage()], $e->getStatusCode()); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.