LinkedIn OAuth Authentication in Laravel Without Socialite

LinkedIn OAuth Authentication in Laravel Without Socialite

In this guide, we’ll learn the process of integrating LinkedIn authentication into a Laravel 10 without using any third-party package like Laravel Socialite. We'll rely solely on LinkedIn API’s endpoints to create authentication from scratch. By the end of this tutorial, you’ll have a Laravel app where users can log in using their LinkedIn credentials. This setup is ideal for scenarios where you need more control over the authentication process or want to avoid extra dependencies.

Setting Up a Laravel Project

To get started, create a fresh Laravel project. Open your terminal and run the following command:
composer create-project laravel/laravel linkedin-integration
After creating the project, we’ll need to install Laravel UI for authentication scaffolding. Laravel UI provides simple authentication scaffolding to get started quickly.
composer require laravel/ui php artisan ui bootstrap –auth npm install
Finally, don’t forget to configure your database connection in the .env file. For this tutorial, name your database social-integration.
DB_DATABASE=socialIntegration

Integrate LinkedIn Login

To integrate LinkedIn login, you'll need a LinkedIn Developer Account. Follow these steps:

  1. Visit LinkedIn Developer Portal.
  2. Click on "Create App".
  3. Fill out the required fields and set up your app.
  4. Once created, navigate to "Auth" settings, and you'll find your Client ID and Client Secret.
  5. Set your redirect URI to match the one in your Laravel app, for example: http://127.0.0.1:8000/auth/linkedin/callback.
  6. Now, update your .env file with the LinkedIn API credentials:
    • LINKEDIN_CLIENT_ID=your_client_id
    • LINKEDIN_CLIENT_SECRET=your_client_secret
    • LINKEDIN_REDIRECT_URI=http://127.0.0.1:8000/auth/linkedin/callback
DB_DATABASELINKEDIN_CLIENT_ID=77zxxxxxxxxxi7k LINKEDIN_CLIENT_SECRET=NzqxxxxxxxxdQGJ LINKEDIN_REDIRECT_URI="http://127.0.0.1:8000/auth/linkedin/callback"

Updating the Migration for LinkedIn Data

Next, we need to update the users table to store the linkedin_id and picture_url fields. This allows us to track which users logged in through LinkedIn and store their profile pictures Update your users migration like this:
Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('name'); $table->string('linkedin_id')->nullable(); $table->string('picture_url')->nullable(); $table->string('email')->unique(); $table->timestamp('email_verified_at')->nullable(); $table->rememberToken(); $table->timestamps(); });

Updating the User Model

protected $fillable = [ 'name', 'email', 'linkedin_id', 'picture_url'];
After updating the migration, run the following command to apply the changes to your database:
php artisan migrate

Creating the LinkedIn Controller

We now need to create a controller to handle the LinkedIn authentication logic. Run this Artisan command to create a new controller:
php artisan make:controller LinkedinController
namespace App\Http\Controllers; use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Http; class LinkedinController extends Controller { public function redirectToLinkedin() { $clientId = config('services.linkedin.client_id'); $redirectUri = config('services.linkedin.redirect_uri'); $scope = 'openid%20profile%20email'; $response_type = 'code'; // $state = bin2hex(random_bytes(16)); // session(['linkedin_state' => $state]); //optional // if you are creating state then you also need to pass in url return redirect("https://www.linkedin.com/oauth/v2/authorization?response_type=$response_type&client_id=$clientId&redirect_uri=$redirectUri&scope=$scope"); } public function handlelinkedinCallback(Request $request) { // $state = $request->query('state'); // Verify the state parameter to prevent CSRF attacks // if (!$state || $state !== $request->session()->pull('linkedin_state')) { // return response()->json(['error' => 'Invalid state'], 400); // } $code = $request->query('code'); if (empty($code)) { return response()->json(['error' => 'Authorization code not provided'], 400); } $clientId = config('services.linkedin.client_id'); $clientSecret = config('services.linkedin.client_secret'); $redirectUri = config('services.linkedin.redirect_uri'); $response = Http::asForm()->post('https://www.linkedin.com/oauth/v2/accessToken', [ 'code' => $code, 'client_id' => $clientId, 'client_secret' => $clientSecret, 'redirect_uri' => $redirectUri, 'grant_type' => 'authorization_code', ]); $accessToken = $response->json('access_token'); $userData = $this->getUserData($accessToken); $user = $this->findOrCreateUser($userData); $userRecord = User::where('email', $user['email'])->where('linkedin_id', $user['linkedin_id'])->first(); if ($userRecord) { Auth::login($userRecord); return redirect('/'); //Redirect the user where you want } else { return redirect()->route('login'); } } private function getUserData($accessToken) { $response = Http::withHeaders([ 'Authorization' => 'Bearer ' . $accessToken, ])->get('https://api.linkedin.com/v2/userinfo'); return $response->json(); } private function findOrCreateUser($userData) { $user = User::where('email', $userData['email'])->first(); if (!$user) { // Create a new user if not exists in database $user = User::create([ 'name' => $userData['name'], 'email' => $userData['email'], 'linkedin_id' => $userData['sub'], 'picture_url' => $userData['picture'], ]); } return $user; } }

LinkedIn Login Functionality

Below are the key functionalities involved in LinkedIn Login integration:

  • redirectToLinkedin: Redirects the user to LinkedIn's OAuth authorization page.
  • handleLinkedinCallback: Handles the callback after LinkedIn’s authorization. It exchanges the authorization code for an access token and uses this token to fetch user data from LinkedIn.
  • getUserData: Fetches user data from LinkedIn using the access token.
  • findOrCreateUser: Finds an existing user or creates a new one based on the LinkedIn profile information.
Now goto your routes/web.php
Auth::routes(); Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home'); Route::get('auth/linkedin', [LinkedinController::class, 'redirectToLinkedin']); Route::get('auth/linkedin/callback', [LinkedinController::class, 'handlelinkedinCallback']);
Lets step up our views.Now go to resources/views/auth/login.blade.php
<div class="row mb-0"> <div class="col-md-8 offset-md-4"> <a href="{{ url('auth/linkedin') }}" class="btn btn-primary">Login with Linkedin</a> <button type="submit" class="btn btn-primary"> {{ __('Login') }} </button> @if (Route::has('password.request')) <a class="btn btn-link" href="{{ route('password.request') }}"> {{ __('Forgot Your Password?') }} </a> @endif </div> </div>

Running the Application

You’re almost done! Open two terminals and run the following commands:
//In the first terminal, start the Laravel development server: php artisan serve //In the second terminal, compile your frontend assets: npm run dev
Once the server is running, navigate to http://127.0.0.1:8000 and try logging in with LinkedIn. ![alt!]() ![alt!]() ![alt!]()
Tags
Login With Linkedin Linkedin Login Laravel Social Login Linkedin Login In Laravel 10 Linkedin Login In Laravel Linkedin Login Without Pakage Laravel Logins Using Linkedin Api For Authentication Auth Authentication Login In Laravel Laravel Login Without Pakage