This document explains how to integrate Google and Apple login using Laravel Socialite, along with JWT-based API authentication.
Install required packages:
composer require laravel/socialite
composer require socialiteproviders/appleconfig/services.php
'google' => [
'client_id' => env('GOOGLE_CLIENT_ID'),
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
'redirect' => env('GOOGLE_REDIRECT_URI'),
],
'apple' => [
'client_id' => env('APPLE_CLIENT_ID'),
'client_secret' => env('APPLE_CLIENT_SECRET'),
'redirect' => env('APPLE_REDIRECT_URI'),
],
In App\Providers\AppServiceProvider.php
Import at the top:
use Laravel\Socialite\Facades\Socialite;
use SocialiteProviders\Apple\Provider as AppleProvider;
Inside the boot() method:
Socialite::extend('apple', static function ($app) {
$config = $app['config']['services.apple'];
return new AppleProvider(
$app['request'],
$config['client_id'],
$config['client_secret'],
$config['redirect']
);
});
-
Download your .p8 key from Apple Developer Account.
-
Save the file as apple_private_key.pem in storage/.
# Google
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_REDIRECT_URI=
# Apple
APPLE_CLIENT_ID=
APPLE_TEAM_ID=
APPLE_KEY_ID=
APPLE_PRIVATE_KEY_PATH=storage/apple_private_key.pem
APPLE_REDIRECT_URI=In routes/api.php:
Route::post('v1/social-login', [SocialAuthController::class, 'SocialLogin']);SocialLogin inside SocialAuthController.php
public function SocialLogin(Request $request)
{
$validated = $request->validate([
'token' => 'required',
'provider' => 'required|in: google ,apple',
]);
try {
$provider = $validated['provider'];
$token = $validated['token'];
$socialiteUser = Socialite::driver($provider)->stateless()->userFromToken($token);
if (!$socialiteUser || !$socialiteUser->getEmail()) {
return response()->json([
'success' => false,
'message' => 'Invalid social token or missing email.',
], 422);
}
$user = User::where('email', $socialiteUser->getEmail())
->where('provider', $provider)
->where('provider_id', $socialiteUser->getId())
->first();
$isNewUser = false;
if (!$user) {
$password = Str::random(16);
$user = User::create([
'first_name' => $socialiteUser->getName() ? explode(' ', $socialiteUser->getName())[0] : 'Apple',
'last_name' => $socialiteUser->getName() && count(explode(' ', $socialiteUser->getName())) > 1
? explode(' ', $socialiteUser->getName())[1] : 'User',
'email' => $socialiteUser->getEmail(),
'provider' => $provider,
'provider_id' => $socialiteUser->getId(),
'password' => Hash::make($password),
'role' => Role::USER->value,
]);
$isNewUser = true;
}
$jwt = auth('api')->login($user);
return response()->json([
'success' => true,
'message' => $isNewUser ? 'User registered successfully.' : 'User logged in successfully.',
'data' => new SocialAuthResource($user),
'token' => $jwt,
]);
} catch (\Exception $e) {
return response()->json([
'success' => false,
'message' => 'Something went wrong.',
'error' => $e->getMessage(),
], 500);
}
}Endpoint:
POST /api/v1/social-loginHeaders:
Content-Type: application/json
Accept: application/jsonRequest Body:
{
"provider": "google", // or "apple"
"token": "YOUR_SOCIAL_ACCESS_TOKEN"
}{
"success": true,
"message": "User logged in successfully.",
"data": {
"id": 1,
"first_name": "John",
"last_name": "Doe",
"email": "john@example.com"
},
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOi..."
}
Invalid Token / Missing Email:
{
"success": false,
"message": "Invalid social token or missing email."
}Server Error:
{
"success": false,
"message": "Something went wrong.",
"error": "Detailed error message"
}-
Use Postman or frontend to send access_token from Google/Apple.
-
For Apple, tokens must be generated using a real device or Apple Test Environment.
-
Ensure Apple key is valid and not expired.
π Laravel Socialite: https://laravel.com/docs/socialite
π Socialite Providers (Apple): https://socialiteproviders.com/Apple/
π JWT Auth Package: https://github.com/tymondesigns/jwt-auth
-
This setup supports both login and registration.
-
Always validate tokens on the frontend before sending to backend.
-
Make sure .p8 keys and sensitive credentials are excluded in .gitignore.