Nuxt+Laravel+Passport与WordPress的令牌化跨站登录共享需求
Got it, let's work through this. You've got a Nuxt + Laravel service site using Passport personal access tokens (with OTP, no password) and want to add a "Login with [Your Service Site]" button to your new WordPress product site—sharing that tokenized auth state, since miniOrange only supports Laravel's session-based auth which doesn't fit your token flow. Here's a custom solution that mimics the OAuth2 flow you're looking for:
We'll build this in two main parts: configuring your Laravel backend to act as an OAuth2 provider for WordPress, then adding custom code to WordPress to handle the login button and auth flow.
1. Laravel Backend: Set Up Passport for WordPress Integration
Since you're already using Passport, we just need to configure it to support WordPress as a trusted OAuth2 client.
Step 1: Create a Passport Client for WordPress
Run this Artisan command to generate a public client for WordPress (this uses the Authorization Code Grant flow, standard for third-party login buttons):
php artisan passport:client --public
When prompted, enter your WordPress site's callback URL (e.g., https://your-wp-site.com/wp-login.php?action=nuxt-login-callback). Save the generated client_id and client_secret—you'll need these for WordPress.
Step 2: Secure a User Info Endpoint
Make sure your Laravel API has an endpoint that returns authenticated user data. Add this to your routes/api.php:
use Illuminate\Http\Request; Route::middleware('auth:api')->get('/user', function (Request $request) { // Return only the user data you need for WordPress (email, name, etc.) return $request->user()->only(['id', 'name', 'email']); });
This endpoint will let WordPress fetch user details once it has a valid access token.
Step 3: Optional Auto-Authorize (Skip Permission Prompt)
Since both sites are yours, you can skip the default Passport authorization prompt (the "Allow this app to access your account?" page). Add this to your AuthServiceProvider's boot method:
use Laravel\Passport\Passport; public function boot() { $this->registerPolicies(); Passport::routes(); // Auto-authorize your WordPress client only Passport::ignoreAuthorizationRequestsForClientIds([YOUR_WORDPRESS_CLIENT_ID]); }
Replace YOUR_WORDPRESS_CLIENT_ID with the ID you saved earlier. Now users will automatically be redirected back to WordPress after logging in to your Laravel site.
Step 4: Update CORS Settings
Ensure your Laravel site allows cross-origin requests from WordPress. If you're using the fruitcake/laravel-cors package, add your WordPress domain to config/cors.php under allowed_origins:
'allowed_origins' => [ 'https://your-wp-site.com', ],
2. WordPress Side: Build the Login Button & Callback Handler
We'll add custom code to WordPress (either in your theme's functions.php or a simple custom plugin) to create the login button and handle the OAuth2 callback.
Step 1: Add the "Login with [Your Service Site]" Button
Add this code to insert the button on WordPress's default login page:
add_action('login_form', 'add_nuxt_service_login_button'); function add_nuxt_service_login_button() { $laravel_auth_url = 'https://your-laravel-site.com/oauth/authorize?' . http_build_query([ 'client_id' => 'YOUR_WORDPRESS_CLIENT_ID', 'redirect_uri' => 'https://your-wp-site.com/wp-login.php?action=nuxt-login-callback', 'response_type' => 'code', 'scope' => '', // Leave empty unless you need specific permissions 'state' => wp_create_nonce('nuxt_login_nonce') // CSRF protection ]); // Style the button to match WordPress's default login UI echo '<div style="margin: 16px 0;"> <a href="' . esc_url($laravel_auth_url) . '" class="button button-primary button-large">登录通过你的服务站</a> </div>'; }
Replace placeholders with your actual client ID and site URLs.
Step 2: Handle the OAuth2 Callback
Add this code to process the callback from Laravel, exchange the authorization code for an access token, and log the user into WordPress:
add_action('login_init', 'handle_nuxt_service_login_callback'); function handle_nuxt_service_login_callback() { if (isset($_GET['action']) && $_GET['action'] === 'nuxt-login-callback') { // Verify CSRF token first if (!isset($_GET['state']) || !wp_verify_nonce($_GET['state'], 'nuxt_login_nonce')) { wp_die('Invalid security token. Please go back and try again.'); } // Check for authorization code if (!isset($_GET['code'])) { wp_die('Authorization failed. No code received from your service site.'); } // Exchange authorization code for access token $token_response = wp_remote_post('https://your-laravel-site.com/oauth/token', [ 'body' => [ 'grant_type' => 'authorization_code', 'client_id' => 'YOUR_WORDPRESS_CLIENT_ID', 'client_secret' => 'YOUR_WORDPRESS_CLIENT_SECRET', 'redirect_uri' => 'https://your-wp-site.com/wp-login.php?action=nuxt-login-callback', 'code' => $_GET['code'] ] ]); if (is_wp_error($token_response)) { wp_die('Failed to retrieve access token: ' . $token_response->get_error_message()); } $token_data = json_decode(wp_remote_retrieve_body($token_response), true); if (!isset($token_data['access_token'])) { wp_die('Invalid response from your service site. Please try again.'); } // Fetch user data from Laravel API $user_response = wp_remote_get('https://your-laravel-site.com/api/user', [ 'headers' => [ 'Authorization' => 'Bearer ' . $token_data['access_token'] ] ]); if (is_wp_error($user_response)) { wp_die('Failed to fetch your account details: ' . $user_response->get_error_message()); } $user_data = json_decode(wp_remote_retrieve_body($user_response), true); if (!isset($user_data['email'])) { wp_die('Could not find your account. Please verify your login on the service site.'); } // Find or create WordPress user $wp_user = get_user_by('email', $user_data['email']); if (!$wp_user) { // Create new user with a random password (users won't need it since they use OTP) $username = sanitize_user(str_replace(['@', '.'], '_', $user_data['email'])); $user_id = wp_create_user($username, wp_generate_password(), $user_data['email']); $wp_user = get_user_by('id', $user_id); // Sync user name from Laravel (optional) if (isset($user_data['name'])) { wp_update_user([ 'ID' => $user_id, 'display_name' => $user_data['name'], 'first_name' => explode(' ', $user_data['name'])[0] ?? '', 'last_name' => explode(' ', $user_data['name'])[1] ?? '' ]); } } // Log the user into WordPress wp_set_current_user($wp_user->ID); wp_set_auth_cookie($wp_user->ID); do_action('wp_login', $wp_user->user_login, $wp_user); // Redirect to WordPress admin or homepage wp_redirect(admin_url()); exit; } }
Again, replace all placeholders with your actual client credentials and site URLs.
3. Test the Flow
- Go to your WordPress login page—you'll see the new "Login with [Your Service Site]" button.
- Click it, and you'll be redirected to your Laravel site's OTP login page.
- Enter your OTP to log in.
- You'll be automatically redirected back to WordPress and logged in with your existing (or newly created) account.
Key Security & Maintenance Notes
- Use HTTPS: Both sites must use HTTPS to avoid exposing sensitive tokens and OTP data.
- Token Expiry: Passport access tokens expire by default (usually 1 hour). If you need longer sessions, you can enable refresh tokens and add logic to WordPress to refresh tokens automatically.
- Error Handling: The code above includes basic error handling, but you can expand it to show friendlier messages or redirect users back to the login page with a notice.
- Plugin vs Theme: For long-term maintenance, consider creating a simple custom plugin instead of adding code to your theme's
functions.php—this way your code won't be lost if you switch themes.
内容的提问来源于stack exchange,提问作者Tamzid Oronno

