You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Passport:无密码生成password grant令牌的方案咨询

Solution for Generating Expiring Tokens with Refresh Tokens via Social Login in Laravel Passport

Hey there! No worries at all—this is a super common pain point when building social login flows with Laravel Passport, and your English is totally fine 😊 Let’s break down the best ways to solve this, since personal tokens aren’t the right fit here (they’re meant for long-term, password-less access, not short-lived, refreshable tokens).

Option 1: Manually Generate Access & Refresh Tokens (Quick Win)

If you want a straightforward way without building custom OAuth logic, you can directly create access tokens with an expiration date and pair them with a refresh token using Passport’s underlying models. Here’s how:

First, make sure you have a password client set up (run php artisan passport:client --password if you haven’t already). Then, in your social login controller:

use Laravel\Passport\Token;
use Laravel\Passport\RefreshToken;
use Carbon\Carbon;
use App\Models\User;

// Step 1: Verify the Google token and fetch user data
// Replace this with your actual Google token validation logic
$googleUser = $this->validateGoogleToken($request->google_token);

// Step 2: Find or create the local user
$user = User::firstOrCreate(
    ['email' => $googleUser->email],
    ['name' => $googleUser->name]
);

// Step 3: Get your password client (for associating tokens)
$passwordClient = \Laravel\Passport\Client::where('password_client', true)->first();

// Step 4: Create an expiring access token
$accessTokenResult = $user->createToken(
    'Social Login Access Token', // Token name
    [], // Scopes (add if needed)
    Carbon::now()->addHours(2) // Expires in 2 hours
);
$accessToken = $accessTokenResult->accessToken;

// Step 5: Create a matching refresh token (expires in 2 weeks)
$refreshToken = RefreshToken::create([
    'access_token_id' => $accessToken->id,
    'user_id' => $user->id,
    'client_id' => $passwordClient->id,
    'revoked' => false,
    'expires_at' => Carbon::now()->addDays(14),
]);

// Step 6: Return the token response
return response()->json([
    'access_token' => $accessToken->token,
    'refresh_token' => $refreshToken->id,
    'expires_in' => Carbon::now()->diffInSeconds($accessToken->expires_at),
    'token_type' => 'Bearer',
]);

This gives you a short-lived access token and a refresh token that can be used to get new access tokens later—just like the password grant flow.

Option 2: Build a Custom OAuth2 Grant (Best Practice)

For a more robust, standards-compliant solution, you can create a custom OAuth2 grant type that mimics the password grant but skips password validation (since you’re using a social token instead). This integrates seamlessly with Passport’s existing /oauth/token endpoint.

Step 1: Create the Custom Grant Class

<?php

namespace App\Passport;

use Laravel\Passport\Bridge\User;
use League\OAuth2\Server\Grant\PasswordGrant;
use League\OAuth2\Server\RequestEvent;
use Psr\Http\Message\ServerRequestInterface;
use League\OAuth2\Server\Exception\OAuthServerException;

class SocialGoogleGrant extends PasswordGrant
{
    // Define your grant type name
    protected $grantType = 'social_google';

    protected function validateUser(ServerRequestInterface $request)
    {
        // Extract the Google token from the request
        $googleToken = $request->getParsedBody()['google_token'] ?? null;

        if (is_null($googleToken)) {
            $this->getEmitter()->emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request));
            throw OAuthServerException::invalidCredentials();
        }

        // Validate the Google token and fetch user data
        $googleUser = $this->verifyGoogleToken($googleToken);

        // Find or create the local user
        $localUser = \App\Models\User::firstOrCreate(
            ['email' => $googleUser->email],
            ['name' => $googleUser->name]
        );

        if (!$localUser) {
            $this->getEmitter()->emit(new RequestEvent(RequestEvent::USER_AUTHENTICATION_FAILED, $request));
            throw OAuthServerException::invalidCredentials();
        }

        // Return a Passport User instance
        return new User($localUser->getAuthIdentifier());
    }

    // Add your Google token validation logic here
    private function verifyGoogleToken(string $token)
    {
        $client = new \GuzzleHttp\Client();
        $response = $client->get('https://www.googleapis.com/oauth2/v3/tokeninfo', [
            'query' => ['id_token' => $token]
        ]);

        return json_decode($response->getBody());
    }
}

Step 2: Register the Grant in AuthServiceProvider

In app/Providers/AuthServiceProvider.php, update the boot method to register your custom grant:

use App\Passport\SocialGoogleGrant;
use Laravel\Passport\Passport;
use League\OAuth2\Server\AuthorizationServer;
use DateInterval;

public function boot()
{
    $this->registerPolicies();

    Passport::routes();

    // Extend the authorization server to add our custom grant
    $this->app->extend(AuthorizationServer::class, function ($server, $app) {
        $server->enableGrantType(
            $app->make(SocialGoogleGrant::class),
            new DateInterval('PT2H') // Access token expires in 2 hours
        );

        return $server;
    });
}

Step 3: Use the Grant from Your Client

Now your mobile app can send a POST request to /oauth/token with these parameters:

  • grant_type: social_google
  • client_id: Your Passport client ID
  • client_secret: Your Passport client secret
  • google_token: The user’s valid Google ID token

You’ll get a standard OAuth2 response with access_token, refresh_token, expires_in, and token_type—exactly like the password grant. You can even use the refresh token to get new access tokens later via the same endpoint (just use grant_type=refresh_token).

Why No "Refreshable Personal Tokens"?

Personal tokens are designed for long-term, password-less access (like API keys for third-party integrations), so Passport intentionally doesn’t pair them with refresh tokens. Refresh tokens are part of the OAuth2 authorization flow, which is meant for user-centric, short-lived access—hence the separation.

Will Laravel Passport Support This Natively?

As of now, there’s no official plan to add this as a built-in feature, but custom grants are fully supported and recommended by the Laravel team for extending Passport’s functionality. This approach is completely compliant with OAuth2 standards and will work with future Passport updates.


内容的提问来源于stack exchange,提问作者makz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:36:18