DEV Community

Cover image for Laravel API Authentication via Sanctum & Socialite and test on Postman
Philip-Droubi
Philip-Droubi

Posted on • Updated on

Laravel API Authentication via Sanctum & Socialite and test on Postman

Laravel Sanctum with Socialite API

(Updated on 23/9/2022 : Flutter app updated)

Hello everyone, this is my first post on DEV.to.
In this post, I will show you how to implement Laravel Sanctum with Socialite in a very basic way.

So let's get started.

1. Create a new Laravel project:
Step 1: Open your terminal OR command prompt and run this command:

composer create-project laravel/laravel test

Or by this command:

laravel new test

Step 2: Create a new DB, then go to your .env file and add your database details.
For example:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=db_name
DB_USERNAME=root
DB_PASSWORD=
Enter fullscreen mode Exit fullscreen mode

2. Install Laravel Sanctum Package:

Step 1: Install Laravel Sanctum via the Composer:
composer require laravel/sanctum

Step 2: You should publish the Sanctum configuration and migration files using the vendor:publish Artisan command:

php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider"
Enter fullscreen mode Exit fullscreen mode

Step 3: Uncomment the Sanctum middleware in app/Http/Kernel.php file :

'api' => [
            \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
            'throttle:api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
Enter fullscreen mode Exit fullscreen mode

Step 4: Go to the users table and set password to nullable() as Laravel Socialite does not need a password:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password')->nullable();
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
};

Enter fullscreen mode Exit fullscreen mode

Step 5: Now we need to create an AuthController to handle users sign-in and sign-up:
php artisan make:controller AuthController

This is a very simple Auth controller with two functions register and login:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Auth;

class AuthController extends Controller
{
    public function register(Request $request)
    {
        $validator = Validator::make($request->only('name', 'email', 'password', 'password_confirmation'), [
            'name' => ['required', 'min:2', 'max:50', 'string'],
            'email' => ['required', 'email', 'unique:users,email'],
            'password' => ['required', 'min:6', 'max:255', 'confirmed', 'string'],
        ]);
        if ($validator->fails())
            return response()->json($validator->errors(), 400);
        $input = $request->only('name', 'email', 'password');
        $input['password'] = Hash::make($request['password']);
        $user = User::create($input);
        $data =  [
            'token' => $user->createToken('Sanctom+Socialite')->plainTextToken,
            'user' => $user,
        ];
        return response()->json($data, 200);
    }

    public function login(Request $request)
    {
        $validator = Validator::make($request->only('email', 'password'), [
            'email' => ['required', 'email', 'exists:users,email'],
            'password' => ['required', 'min:6', 'max:255', 'string'],
        ]);
        if ($validator->fails())
            return response()->json($validator->errors(), 400);
        if (Auth::attempt(['email' => $request->email, 'password' => $request->password])) {
            $user = $request->user();
            $data =  [
                'token' => $user->createToken('Sanctom+Socialite')->plainTextToken,
                'user' => $user,
            ];
            return response()->json($data, 200);
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

3. Install Laravel Socialite Package:
Step 1: To get started with Socialite, use the Composer package manager to add the package to your project's dependencies:
composer require laravel/socialite

Step 2: Before using Socialite, you will need to add credentials for the OAuth providers your application utilizes,(In my case it's Google), So go to config/services.php and add this code:

'google' => [
        'client_id' => env('GOOGLE_CLIENT_ID'),
        'client_secret' => env('GOOGLE_CLIENT_SECRET'),
        'redirect' => 'GOOGLE_REDIRECT_URI',
    ],
Enter fullscreen mode Exit fullscreen mode

Remember that this will only work for Google tokens.
Since you are building API you don't need to set anything in your .env file to let socialite work.

Step 3: To keep things organized you need a new controller to handle login via provider, So we will create it:

php artisan make:controller SocialiteController

Now we need to make two functions handleProviderCallback to handle the login and validateProvider to check what provider used:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Laravel\Socialite\Facades\Socialite;
use Illuminate\Support\Facades\Validator;

class SocialiteController extends Controller
{
    public function handleProviderCallback(Request $request)
    {
        $validator = Validator::make($request->only('provider', 'access_provider_token'), [
            'provider' => ['required', 'string'],
            'access_provider_token' => ['required', 'string']
        ]);
        if ($validator->fails())
            return response()->json($validator->errors(), 400);
        $provider = $request->provider;
        $validated = $this->validateProvider($provider);
        if (!is_null($validated))
            return $validated;
        $providerUser = Socialite::driver($provider)->userFromToken($request->access_provider_token);
        $user = User::firstOrCreate(
            [
                'email' => $providerUser->getEmail()
            ],
            [
                'name' => $providerUser->getName(),
            ]
        );
        $data =  [
            'token' => $user->createToken('Sanctom+Socialite')->plainTextToken,
            'user' => $user,
        ];
        return response()->json($data, 200);
    }

    protected function validateProvider($provider)
    {
        if (!in_array($provider, ['google'])) {
            return response()->json(["message" => 'You can only login via google account'], 400);
        }
    }
}

Enter fullscreen mode Exit fullscreen mode

Step 4: We need now to create our API routes, So go to routes/api.php and add these routes:

use App\Http\Controllers\AuthController;
use App\Http\Controllers\SocialiteController;
Route::controller(AuthController::class)->group(function () {
    Route::post('/', 'register');
    Route::post('/login', 'login');
});

Route::post('/login/callback', [SocialiteController::class, 'handleProviderCallback']);
Enter fullscreen mode Exit fullscreen mode

Step 5: Run:
php artisan migrate
And:
php artisan serv

Now that we've finished the code, let's go to Postman and test our routes:
Test normal register and login:
register:
Normal Regist

Via Socialite:

via Laravel Socialite

You may now be wondering how to get access_provider_token, well I'm using a Flutter application created by my friend Fadi Asfour to get these tokens.

Some images from the Flutter app:

sign-in
And here is the Google token:

Google Token
You can download the app from HERE
Or get the token online from this SITE
You can see all user info given by Google token by dd the $providerUser in SocialiteController:
All user info

You can get the source code for this project from Github

In the end, I hope this article is useful and helpful to you, and remember that this is just a very simple form of the code so that the article is not too long, so try to add what you need (for example Providers Table), and link each user registered by Laravel Socialite to this table and record the user Provider and other details, and do not forget your touch.

If you have any questions, please feel free to comment on this post.

Top comments (11)

Collapse
 
rober profile image
Lorem

Great article, I really need this.
Also, thanks for sharing the Flutter app.

Collapse
 
rober profile image
Lorem • Edited

@philipdroubi , Do I need to create a Google app to get client_id and client_secret ?
And does this work with Facebook, Github and other providers??

Collapse
 
philipdroubi profile image
Philip-Droubi

@rober You're welcome.
1- As a backend you don't need to create any google app, frontend should do.
2- Yes it works, But you need to edit your config/services.php file to be like this :

'google' => [
        'client_id' => env('GOOGLE_CLIENT_ID'),
        'client_secret' => env('GOOGLE_CLIENT_SECRET'),
        'redirect' => 'GOOGLE_REDIRECT_URI',
    ],
'facebook' => [
        'client_id' => env('FACEBOOK_CLIENT_ID'),
        'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
        'redirect' => 'FACEBOOK_REDIRECT_URI',
    ],
Enter fullscreen mode Exit fullscreen mode

And the validateProvider function in SocialiteController to be like this :

protected function validateProvider($provider)
    {
        if (!in_array($provider, ['google','facebook'])) {
            return response()->json(["message" => 'You can only login via google or Facebook accounts'], 400);
        }
    }
Enter fullscreen mode Exit fullscreen mode
Collapse
 
gankcc profile image
Suphasit Thongniam

You saved my day.
Cheers mate!

Collapse
 
philipdroubi profile image
Philip-Droubi

My pleasure! 😃

Collapse
 
229okpe profile image
229okpe

where can i find the access_provider_token ?
The redirect is not obligatory?

Collapse
 
philipdroubi profile image
Philip-Droubi • Edited

@229okpe

  • You can get the access_provider_token for testing purpose through this flutter app or through this website.
    And remember that as an API the frontend application must send the access_provider_token through the request.

  • No need for any redirect.

Collapse
 
ahmedali190000 profile image
Ahmed Ali

is there no providers table to know which this user comes from google ,GitHub or Facebook ??
and how mobile developer sends me access_token_provider in callback ??

Collapse
 
philipdroubi profile image
Philip-Droubi • Edited

@ahmedali190000
1- Yes, of course, if you want to store from which provider each user came from, you must have a providers_table.

2- Mobile developers can send you the access_token_provider in the request parameters or body, but if you mean the token itself it's better to send it using the request body as it may be too long to be in the request parameters.

Collapse
 
keyvervelasquez profile image
Keyver Velásquez Guerra

Bro!, Thank you!

Collapse
 
philipdroubi profile image
Philip-Droubi

@keyvervelasquez You're welcome.