Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Keycloak Security Bundle Laravel Package

dmstr/keycloak-security-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

To begin using this package, ensure your project meets the minimum PHP 8.4 requirement (⚠️ BREAKING in v0.2.0). Install via Composer:

composer require vendor/package-name

Keycloak integration now includes a KeycloakUser model and KeycloakUserProvider, designed for seamless OAuth2/Keycloak authentication. Start by:

  1. Publishing the config:
    php artisan vendor:publish --provider="Vendor\Package\ServiceProvider"
    
  2. Configure .env and config/keycloak.php with your Keycloak realm, client ID, and credentials.
  3. Bind the provider in AuthServiceProvider:
    public function boot()
    {
        $this->app['auth']->provider('keycloak', function ($app) {
            return new \Vendor\Package\KeycloakUserProvider($app['config']['keycloak']);
        });
    }
    
  4. Use the KeycloakUser model in your User trait or extend it directly.

For testing, the package now includes unit tests for KeycloakUser/KeycloakUserProvider, which can serve as a reference for your own implementations.


Implementation Patterns

Core Workflow

  1. Authentication Flow:

    • Redirect users to Keycloak for login:
      use Vendor\Package\Facades\KeycloakAuth;
      
      return KeycloakAuth::redirectToKeycloak();
      
    • Handle callbacks via a route (e.g., /auth/keycloak/callback) with middleware:
      Route::get('/auth/keycloak/callback', [AuthController::class, 'handleKeycloakCallback']);
      
    • Validate tokens and fetch user data via the provider:
      $user = $this->auth->guard('web')->user(); // If using default guard
      // Or manually:
      $provider = app('auth')->createUserProvider('keycloak');
      $user = $provider->retrieveByCredentials(['id_token' => $request->id_token]);
      
  2. User Model Integration:

    • Extend KeycloakUser or use it as a trait:
      use Vendor\Package\Models\KeycloakUser;
      
      class User extends Authenticatable implements KeycloakUser
      {
          // ...
      }
      
    • Sync Keycloak attributes (e.g., email, name) to your DB:
      $user->syncFromKeycloak($keycloakUserData);
      
  3. Role/Group Mapping:

    • Use the KeycloakUserProvider to resolve roles/groups from the token:
      $roles = $provider->getUserRoles($user);
      

Advanced Patterns

  • Token Refresh: Leverage the provider’s refreshToken() method if your Keycloak client supports silent refresh:

    $provider->refreshToken($user->refresh_token);
    
  • Custom Claims: Extend KeycloakUserProvider to handle custom claims:

    class CustomKeycloakUserProvider extends KeycloakUserProvider
    {
        public function getCustomClaim($user, $claimName)
        {
            return $this->getKeycloakClient()->getCustomClaim($user->id_token, $claimName);
        }
    }
    
  • CI/CD: The package now includes a CI workflow (GitHub Actions) as a template. Adapt it for your pipeline to run tests against your Keycloak instance.


Gotchas and Tips

Breaking Changes (v0.2.0)

  • PHP 8.4 Requirement: Ensure your project upgrades to PHP 8.4. Key features like readonly properties, first-class callable syntax, and new attributes are used internally. Test thoroughly for compatibility.

Common Pitfalls

  1. Token Validation:

    • Keycloak tokens expire. Handle TokenExpiredException gracefully:
      try {
          $user = $provider->retrieveByCredentials(['id_token' => $token]);
      } catch (\Vendor\Package\Exceptions\TokenExpiredException $e) {
          return redirect()->route('keycloak.login')->with('error', 'Session expired');
      }
      
    • Use the validateToken() method to check token validity before processing.
  2. Role/Group Sync:

    • Keycloak roles/groups may not map 1:1 to your DB. Normalize them in KeycloakUserProvider:
      protected function mapKeycloakRoleToLocal($role)
      {
          return strtolower(str_replace(' ', '_', $role));
      }
      
  3. CI/CD Quirks:

    • The CI workflow assumes a Keycloak instance is available. Use environment variables (e.g., KEYCLOAK_URL, KEYCLOAK_ADMIN_CREDENTIALS) to configure it dynamically.

Debugging Tips

  • Enable Debugging: Set KEYCLOAK_DEBUG=true in .env to log raw token responses and errors.

  • Token Inspection: Decode Keycloak tokens manually to verify claims:

    php -r 'echo base64_decode(explode(".", "YOUR_TOKEN_HERE")[1]);'
    
  • Middleware Order: Ensure KeycloakAuthMiddleware runs after VerifyCsrfToken but before Authenticate in your middleware stack to avoid token validation issues.

Extension Points

  1. Custom User Provider: Override KeycloakUserProvider to add logic (e.g., custom user resolution):

    class CustomUserProvider extends KeycloakUserProvider
    {
        public function retrieveById($identifier)
        {
            // Custom logic to fetch user from DB + Keycloak
        }
    }
    
  2. Event Listeners: Listen for KeycloakUserLoggedIn or KeycloakTokenRefreshed events to trigger post-auth actions:

    Event::listen(KeycloakUserLoggedIn::class, function ($user) {
        // Log user activity or update last_login_at
    });
    
  3. Testing: Use the provided unit tests as a scaffold for your own tests. Mock the Keycloak HTTP client:

    $mockClient = Mockery::mock(\Vendor\Package\KeycloakClient::class);
    $provider = new KeycloakUserProvider($config, $mockClient);
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator
equipc/laravel-email-database-log
adedsec/nova-translated-labels
wazza/laravel-db-encryption
hokny/laravel-generator
vonsogt/backup
jengo/queues
jeremykenedy/laravel-observability
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums