Auth & Security
Thème :
Junior
1 vues ·10/12 leçons

Construire un Serveur OAuth2 avec Passport

Laravel Passport fournit une implémentation complète d’un serveur OAuth2. Utilisez-le lorsque vous avez besoin de fournir un accès API OAuth2 complet à des applications tierces (comme le fait Google ou Facebook pour votre propre application).

Quand utiliser Passport ?

  • Des développeurs externes (tiers) doivent s’intégrer à votre API.
  • Vous avez absolument besoin de Jetons de Rafraîchissement (Refresh Tokens).
  • Vous avez besoin des Codes d’Autorisation OAuth2.
  • Vous construisez une API que d’autres personnes vont consommer publiquement.

Si vous n’avez pas besoin de tout cela, utilisez plutôt Laravel Sanctum.

Installation

composer require laravel/passport

php artisan migrate

# Installe les clés de chiffrement secrètes
php artisan passport:install

Ajoutez le Trait au Modèle Utilisateur (User) :

// Attention : Remplacez Laravel\Sanctum\HasApiTokens si vous l'aviez !
use Laravel\Passport\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens, Notifiable;
}

Configurez le gardien (guard) d’authentification dans config/auth.php :

'guards' => [
    'api' => [
        'driver' => 'passport', // Passe de 'session' ou 'sanctum' à 'passport'
        'provider' => 'users',
    ],
],

Les Types d’Accords OAuth2 (Grant Types)

Passport prend en charge tous les types d’accords (Grants) de la norme OAuth2 :

1. Code d’Autorisation (Authorization Code Grant - Le plus courant)

C’est pour les applications web où les utilisateurs autorisent un accès tiers (ex: “Connexion avec Google”).

Utilisateur → Application Tierce → Votre Serveur Auth → Utilisateur Autorise →
L'Application Tierce reçoit un Code → L'échange secrètement contre un Jeton (Token)

2. Jetons d’Accès Personnels (Personal Access Tokens)

Pour que vos utilisateurs génèrent leurs propres jetons d’API (comme dans les paramètres Github).

$token = $user->createToken('Nom du Jeton')->accessToken;

3. Accord par Mot de Passe (Password Grant)

Uniquement pour vos “propres” applications (ex: votre application React Native officielle) :

# Génère un "Client" spécial pour l'accès par mot de passe
php artisan passport:client --password

Le front-end appelle ensuite cette URL avec les vrais identifiants :

// POST /oauth/token
{
    "grant_type": "password",
    "client_id": "votre-client-id-généré",
    "client_secret": "votre-client-secret",
    "username": "user@example.com",
    "password": "mot-de-passe-secret",
    "scope": ""
}

4. Authentification Inter-Serveurs (Client Credentials Grant)

Pour l’authentification machine à machine (M2M), sans aucun utilisateur humain impliqué (ex: Microservices) :

php artisan passport:client --client
// POST /oauth/token
{
    "grant_type": "client_credentials",
    "client_id": "client-id",
    "client_secret": "client-secret",
    "scope": "read-data"
}

Créer des Clients OAuth

# Création interactive d'un client (Vous demandera le nom et l'URL de retour)
php artisan passport:client

# Création de clients spécifiques (bypass les questions)
php artisan passport:client --password
php artisan passport:client --client
php artisan passport:client --personal

Le Flux du Code d’Autorisation (Authorization Code Flow)

C’est le cœur de OAuth2. Voici comment l’application B se connecte chez vous (l’application A).

Étape 1 : Rediriger vers l’Autorisation

L’application tierce redirige son utilisateur vers VOTRE site :

GET /oauth/authorize?
    client_id=VOTRE_CLIENT_ID&
    redirect_uri=https://app-tierce.com/callback&
    response_type=code&
    scope=read-posts+write-posts&
    state=CHAINE_ALEATOIRE_DE_SECURITE

Étape 2 : L’Utilisateur Autorise

L’utilisateur arrive sur une page de VOTRE site (générée par Passport) disant : “L’application X veut accéder à vos articles. Acceptez-vous ?”. S’il dit oui…

Étape 3 : Retour (Callback) avec le Code

Vous le redirigez vers l’application tierce avec un code temporaire :

https://app-tierce.com/callback?code=CODE_D_AUTORISATION&state=CHAINE_ALEATOIRE_DE_SECURITE

Étape 4 : Échanger le Code contre un Jeton

Le serveur de l’application tierce contacte secrètement (en arrière-plan) VOTRE serveur pour échanger le code vulnérable contre un vrai Jeton sécurisé :

// POST /oauth/token
{
    "grant_type": "authorization_code",
    "client_id": "VOTRE_CLIENT_ID",
    "client_secret": "LE_SECRET_QUE_L_APP_TIERCE_POSSEDE",
    "redirect_uri": "https://app-tierce.com/callback",
    "code": "CODE_D_AUTORISATION_RECUPERE_A_L_ETAPE_3"
}

Votre Réponse (Succès) :

{
    "token_type": "Bearer",
    "expires_in": 31536000,
    "access_token": "eyJ0eXAiOiJKV1Q...", // Le fameux "Access Token"
    "refresh_token": "def50200..." // Le jeton pour recommencer dans un an sans redemander le code !
}

Définir des Portées (Scopes)

Les scopes informent l’utilisateur des permissions exactes que l’application tierce demande.

// Dans AppServiceProvider ou AuthServiceProvider
use Laravel\Passport\Passport;

public function boot(): void
{
    // Déclare toutes les permissions possibles sur votre API
    Passport::tokensCan([
        'read-posts' => 'Lire vos articles',
        'write-posts' => 'Créer et modifier vos articles',
        'delete-posts' => 'Supprimer vos articles',
        'read-profile' => 'Lire votre profil public',
        'update-profile' => 'Mettre à jour vos informations de profil',
    ]);

    // Scopes attribués par défaut si l'application tierce n'en demande aucun
    Passport::defaultScopes([
        'read-posts',
        'read-profile',
    ]);
}

Protéger les Routes

// Protégé par le Token OAuth classique
Route::middleware('auth:api')->group(function () {
    Route::get('/user', function (Request $request) {
        return $request->user();
    });
});

// Exige un Scope (Portée) spécifique : `scope` (Singulier = OU, `scopes` = Pluriel = ET)
Route::get('/posts', [PostController::class, 'index'])
    ->middleware(['auth:api', 'scope:read-posts']);

Route::post('/posts', [PostController::class, 'store'])
    ->middleware(['auth:api', 'scopes:read-posts,write-posts']); // Doit avoir les DEUX

Expiration des Jetons

Vous pouvez (et devez) définir la durée de vie de ces jetons de sécurité.

// Dans AppServiceProvider
use Laravel\Passport\Passport;

public function boot(): void
{
    // Durée de vie du Jeton principal (Access Token)
    Passport::tokensExpireIn(now()->addDays(15));

    // Le Jeton de Rafraîchissement dure plus longtemps
    Passport::refreshTokensExpireIn(now()->addDays(30));

    // Les Jetons créés manuellement par les développeurs meurent au bout de 6 mois
    Passport::personalAccessTokensExpireIn(now()->addMonths(6));
}

Rafraîchir un Jeton (Refresh Token)

Quand le jeton a expiré au bout de 15 jours (cf plus haut), l’application tierce n’a pas besoin de redemander à l’utilisateur de se reconnecter. Elle utilise le refresh_token :

// POST /oauth/token
{
    "grant_type": "refresh_token",
    "refresh_token": "LE_REFRESH_TOKEN_OBTENU_LORS_DE_LA_CONNEXION",
    "client_id": "CLIENT_ID",
    "client_secret": "CLIENT_SECRET",
    "scope": ""
}

Ressources


📘 Cette leçon fait partie du cours Authentification et Autorisation Laravel sur la plateforme d’apprentissage RostoDev.

Prêt à passer à la suite ?

Vous avez terminé cette leçon sur Construire un Serveur OAuth2 avec Passport. Continuez votre apprentissage avec la prochaine leçon ou explorez d'autres formations.