﻿Utilisation de la bibliothèque :

Voici les 4 grandes étapes de l'intégration, qui y sont détaillées avec des exemples de code pour Laravel :

1. Installation
Dans le projet cible (ex: UsersManager), on ajoute le lien local dans composer.json et on lance composer require grimaud/login-iam-library:@dev.

2. Configuration
On crée un fichier config/keycloak.php alimenté par le .env de l'application, qui contient les URL de votre serveur de la mairie et les identifiants (comme usersmanager et son secret).

3. Le flux de connexion (Contrôleurs)
Login : On instancie AuthService, on génère des clés de sécurité (state et code_verifier PKCE) qu'on stocke en session, puis on redirige l'utilisateur vers l'URL générée par getAuthorizationUrl().
Callback : Au retour, on vérifie la sécurité, puis on appelle exchangeCodeForTokens() pour obtenir l'access_token.
4. Vérification (Middleware ou Contrôleurs)
Dans le code de votre application, il suffit de passer le token pour savoir qui est connecté et ce qu'il a le droit de faire :

php
$checker = $authService->authenticateAndAuthorize($accessToken);
// Exemples
$email = $checker->getTokenInfo()->getEmail();
if ($checker->isInGroup('/Direction')) { ... }
if ($checker->hasRole('admin')) { ... }
Tout le code complet et détaillé se trouve ci-dessous :


# Grimaud Login IAM Library

Bibliothèque PHP permettant d'encapsuler l'authentification OIDC avec Keycloak et la gestion des autorisations (rôles, groupes, permissions).

## 1. Installation

Dans l'application cible (par exemple `UsersManager`), ajoutez ce package en tant que dépôt local dans le fichier `composer.json` :

```json
    "repositories": [
        {
            "type": "path",
            "url": "c:/wamp64/www/LoginLibrary"
        }
    ],
```

Puis installez-le via la ligne de commande :
```bash
composer require grimaud/login-iam-library:@dev
```

## 2. Configuration (exemple avec Laravel)

Créez un fichier `config/keycloak.php` qui retourne les paramètres de connexion :

```php
<?php

return [
    'issuer'                 => env('KEYCLOAK_ISSUER', 'https://keycloak.mairie-grimaud.fr/realms/Users%20Authentification'),
    'client_id'              => env('KEYCLOAK_CLIENT_ID', 'usersmanager'),
    'client_secret'          => env('KEYCLOAK_CLIENT_SECRET', ''), // Optionnel si client public
    'authorization_endpoint' => env('KEYCLOAK_AUTH_ENDPOINT', 'https://keycloak.mairie-grimaud.fr/.../auth'),
    'end_session_endpoint'   => env('KEYCLOAK_LOGOUT_ENDPOINT', 'https://keycloak.mairie-grimaud.fr/.../logout'), // Optionnel (déduit auto. depuis auth)
    'scope'                  => env('KEYCLOAK_SCOPE', 'openid profile email'),
    'verify'                 => env('KEYCLOAK_VERIFY_SSL', true), // Mettre à false en dév si pas de certificat
];
```

## 3. Utilisation dans un Contrôleur (Flux OIDC)

### A. Rediriger l'utilisateur vers Keycloak (Login)

```php
use Grimaud\LoginIamLibrary\AuthService;
use Illuminate\Support\Str;

public function login()
{
    $authService = new AuthService(config('keycloak'));
    
    // PKCE et State pour la sécurité
    $state = Str::random(40);
    $codeVerifier = Str::random(128);
    
    // Sauvegarde en session pour vérifier au retour
    session(['oauth_state' => $state, 'oauth_code_verifier' => $codeVerifier]);
    
    $redirectUri = route('auth.callback');
    $url = $authService->getAuthorizationUrl($state, $codeVerifier, $redirectUri);
    
    return redirect($url);
}
```

### B. Traiter le retour de Keycloak (Callback)

```php
public function callback(\Illuminate\Http\Request $request)
{
    // Vérification du state (contre les attaques CSRF)
    if ($request->state !== session('oauth_state')) {
        abort(403, 'State invalide');
    }

    $authService = new AuthService(config('keycloak'));
    $codeVerifier = session('oauth_code_verifier');
    
    try {
        // 1. Échange du code contre les tokens
        $tokens = $authService->exchangeCodeForTokens(
            $request->code, 
            route('auth.callback'), 
            $codeVerifier
        );
        
        $accessToken = $tokens['access_token'];
        $idToken = $tokens['id_token'] ?? null;
        
        // 2. Validation du token et extraction des informations
        $checker = $authService->authenticateAndAuthorize($accessToken);
        $userInfo = $checker->getTokenInfo();
        
        // 3. Connecter l'utilisateur dans Laravel (optionnel)
        // ex: $user = User::firstOrCreate(['email' => $userInfo->getEmail()]);
        // Auth::login($user);
        
        // Stocker l'access_token et l'id_token en session (pour les APIs et la déconnexion)
        session([
            'access_token' => $accessToken,
            'id_token'     => $idToken
        ]);
        
        return redirect('/dashboard');
        
    } catch (\Exception $e) {
        return "Erreur d'authentification : " . $e->getMessage();
    }
}
```

## 4. Déconnexion (RP-Initiated Logout)

Pour déconnecter l'utilisateur proprement de votre application ET de Keycloak (Single Sign-Out) :

```php
public function logout()
{
    $authService = new AuthService(config('keycloak'));
    
    // Récupération de l'id_token stocké lors de la connexion
    $idToken = session('id_token');
    
    // On vide la session de l'application
    session()->flush();
    
    // On redirige vers Keycloak pour fermer la session globale
    // (Keycloak va ensuite rediriger l'utilisateur vers route('home'))
    $url = $authService->getLogoutUrl($idToken, route('home'));
    
    return redirect($url);
}
```

## 5. Vérifier les autorisations (Middlewares ou Contrôleurs)

Une fois que vous avez l' `access_token` (récupéré depuis la session ou via le header d'une API `Bearer Token`), vous pouvez vérifier les droits très facilement :

```php
use Grimaud\LoginIamLibrary\AuthService;
use Grimaud\LoginIamLibrary\Exceptions\TokenException;

$authService = new AuthService(config('keycloak'));
$accessToken = session('access_token'); // Ou request()->bearerToken()

try {
    $checker = $authService->authenticateAndAuthorize($accessToken);
    
    // -- Informations utilisateur --
    $email = $checker->getTokenInfo()->getEmail();
    $name = $checker->getTokenInfo()->getName();
    
    // -- Vérifications des Groupes --
    if ($checker->isInGroup('/Direction')) {
        // Action autorisée
    }
    
    // -- Vérifications des Rôles --
    if ($checker->hasRole('admin')) { // Cherche dans le realm et le client_id configuré
        // Action autorisée
    }
    
    if ($checker->hasRealmRole('super-admin')) {
        // ...
    }

} catch (TokenException $e) {
    // Token expiré ou signature invalide
    abort(401, 'Session expirée, veuillez vous reconnecter.');
}
```
