1. Go to this page and download the library: Download bspdx/keystone library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
'features' => [
// Two-factor authentication (TOTP via Fortify)
'two_factor' => true,
// Passkey authentication (WebAuthn/FIDO2)
'passkeys' => true,
// Passkey as a second factor (reserved — not yet implemented)
'passkey_2fa' => false,
// Account deletion endpoint (reserved — not yet implemented)
'account_deletion' => false,
// Allow users to configure passwordless login options
'passwordless_login' => true,
// Show roles and permissions on the profile page
'show_permissions' => true,
// Enable multi-tenant mode (adds tenant_id column to users, roles, and permissions tables)
'multi_tenant' => env('KEYSTONE_MULTI_TENANT', false),
],
use BSPDX\Keystone\Models\KeystoneRole;
// Create global role (accessible to all tenants)
$superAdmin = KeystoneRole::withoutTenant()->create([
'name' => 'super_administrator',
'tenant_id' => null,
]);
// Create tenant-specific role (auto-scoped)
Auth::login($userInTenantA);
$manager = KeystoneRole::create(['name' => 'manager']);
// tenant_id automatically populated from auth()->user()->tenant_id
'rbac' => [
// Cache expiration time for roles and permissions (in seconds)
'cache_expiration' => 60 * 60 * 24, // 24 hours
// Default role assigned to new users (null = no default role)
'default_role' => 'user',
// Super admin role that bypasses all permission checks
'super_admin_role' => 'super-admin',
],
'passkey' => [
// Relying Party name (your application name)
'rp_name' => env('APP_NAME', 'Laravel'),
// Relying Party ID — derived from APP_URL host, falls back to 'localhost'
'rp_id' => env('APP_URL') ? parse_url(env('APP_URL'), PHP_URL_HOST) : 'localhost',
// Timeout for passkey operations (in milliseconds)
'timeout' => 60000,
// User verification: '
'two_factor' => [
'qr_code_size' => 200,
'recovery_codes_count' => 8,
// Window of time to accept TOTP codes (in periods, 1 period = 30 seconds)
'window' => 1,
'
'rate_limiting' => [
// Maximum login attempts before lockout
'max_login_attempts' => 5,
// Lockout duration in minutes
'lockout_duration' => 1,
// Maximum 2FA attempts
'max_2fa_attempts' => 3,
// Maximum passkey attempts
'max_passkey_attempts' => 3,
],
'profile' => [
// URI path where the profile page is accessible
'path' => '/profile',
// Middleware applied to profile routes
'middleware' => ['web', 'auth'],
// Require password confirmation before sensitive operations
'
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use BSPDX\Keystone\Traits\HasKeystone;
class User extends Authenticatable
{
use Notifiable, HasKeystone;
// ... rest of your model
}
use App\Models\User;
$admins = User::role('admin')->get();
$staff = User::role(['admin', 'manager'])->get();
namespace App\Http\Controllers;
use BSPDX\Keystone\Services\Contracts\RoleServiceInterface;
use BSPDX\Keystone\Services\Contracts\PermissionServiceInterface;
use BSPDX\Keystone\Services\Contracts\AuthorizationServiceInterface;
use BSPDX\Keystone\Services\Contracts\PasskeyServiceInterface;
class AdminController extends Controller
{
public function __construct(
private RoleServiceInterface $roleService,
private PermissionServiceInterface $permissionService,
private AuthorizationServiceInterface $authService
) {}
public function assignRole(User $user)
{
// Get all roles
$roles = $this->roleService->getAllWithPermissions();
// Assign roles to user
$this->authService->assignRolesToUser($user, ['admin', 'editor']);
// Check if user has role
if ($this->authService->userHasRole($user, 'admin')) {
// User is admin
}
}
}
// Include in your routes/web.php
// Include in your routes/api.php
Route::middleware(['auth', 'role:admin'])->group(function () {
// Only users with 'admin' role can access
});
// Multiple roles (OR logic)
Route::middleware(['auth', 'role:admin,editor'])->group(function () {
// Users with 'admin' OR 'editor' role can access
});
Route::middleware(['auth', 'permission:edit-posts'])->group(function () {
// Only users with 'edit-posts' permission
});
// Multiple permissions
Route::middleware(['auth', 'permission:edit-posts,publish-posts'])->group(function () {
// Users with either permission can access
});
Route::middleware(['auth', '2fa'])->group(function () {
// Ensures users with
Route::middleware(['auth', 'keystone.feature:account_deletion'])->group(function () {
// Only reachable when 'account_deletion' is enabled in config
});
Route::middleware(['auth', 'password-confirm'])->group(function () {
// Requires the user to have confirmed their password recently
});
Route::middleware(['auth', 'passkey-2fa'])->group(function () {
// Requires passkey verification when passkey_2fa is enabled
});
// Check role
if (auth()->user()->hasRole('admin')) {
// User is an admin
}
// Check permission
if (auth()->user()->can('edit-posts')) {
// User can edit posts
}
// Check multiple roles
if (auth()->user()->hasAnyRole(['admin', 'editor'])) {
// User has at least one of these roles
}
// Super admin check
if (auth()->user()->isSuperAdmin()) {
// User is super admin (bypasses all permission checks)
}
use BSPDX\Keystone\Services\Contracts\AuthorizationServiceInterface;
class PostController extends Controller
{
public function __construct(
private AuthorizationServiceInterface $authService
) {}
public function edit(Post $post)
{
if ($this->authService->userHasPermission(auth()->user(), 'edit-posts')) {
// User can edit posts
}
}
}
use BSPDX\Keystone\Models\KeystoneRole;
// Create a global role accessible to all tenants
$superAdmin = KeystoneRole::withoutTenant()->create([
'name' => 'super_administrator',
'title' => 'Super Administrator',
'tenant_id' => null, // Global role
]);
// tenant_id is auto-populated from authenticated user
Auth::login($userInTenantA);
$manager = KeystoneRole::create([
'name' => 'department_manager',
'title' => 'Department Manager',
// tenant_id automatically set from auth()->user()->tenant_id
]);
// View all roles across all tenants
$allRoles = KeystoneRole::withoutTenant()->get();
// Check if user can bypass tenant filtering
if ($user->canBypassPermissions()) {
// User is super-admin
}
namespace App\Models;
use Illuminate\Foundation\Auth\User as Authenticatable;
use BSPDX\Keystone\Traits\HasKeystone;
class User extends Authenticatable
{
use HasKeystone;
protected $fillable = ['name', 'email', 'password'];
}
// routes/web.php
Route::get('/login', function () {
return view('auth.login');
})->name('login');
// Include Keystone routes