Stateless Socialite Authentication

A couple years ago I was working on a Laravel API that had social authentication features. I was using the laravel/socialite package to handle these authentication features, but ran into issues because our app was stateless. We were using JWT for handling authentication between our frontend client and our backend Laravel API, and therefore didn't have need of sessions so we had stripped it all out. At the time there was no workaround for our issue, and it resulted in this pull request: https://github.com/laravel/socialite/pull/68.

That PR introduced the stateless() method, which is now part of Socialite and documented here: https://laravel.com/docs/socialite#stateless-authentication.

Ever since then I’ve received plenty of questions about how to drop Socialite into session‑free APIs. Let's work through a simple example of how it works. In my samples, I'm going to use the jwt-auth package, but I'll also add some comments for how it might look with sanctum.

Two common scenarios

  • APIs that don’t use sessions at all, and you still want to handle social authentication on the backend. Classic setup: the API redirects to the provider, handles the callback, and then issues its own JWT. This used to be more common when Lumen was popular (it didn't use sessions).

  • The client app handles the redirect and authorization, but you still want the API to finish the login. Your SPA/mobile app uses the provider’s SDK to get an access token and posts that token to the API, which calls userFromToken().

In both cases you’ll call ->stateless() because there’s no session to keep track of things.

Quick setup


composer require laravel/socialite        # Social login helper
composer require tymon/jwt-auth           # JWTs (self‑contained)
# or install sanctum
    

For jwt‑auth:


php artisan vendor:publish -provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
php artisan jwt:secret
    

Add provider credentials to config/services.php (GitHub example):


'github' => [
    'client_id'     => env('GITHUB_CLIENT_ID'),
    'client_secret' => env('GITHUB_CLIENT_SECRET'),
    'redirect'      => env('GITHUB_REDIRECT_URI'),
],
    

How it looks – backend handles redirect & callback


use Illuminate\Support\Facades\Route;
use Laravel\Socialite\Facades\Socialite;
use App\Models\User;
use Tymon\JWTAuth\Facades\JWTAuth;           

/**
 * Redirect the user to the GitHub authentication page.
 */
Route::get('/auth/github/redirect', function () {
    return Socialite::driver('github') 
        ->stateless()
        ->redirect();
});
    

As you can see the redirect method is VERY simple. In many scenarios this method is optional. For example as I mentioned previously it might be the responsibility of the client side application (Vue/React etc) to redirect for authentication. However I like to have my frontend client apps call this backend endpoint to start the authorization process. just don't forget to include the "stateless()" function.


/**
 * Obtain the user information from GitHub.
 * This is the callback URL that GitHub will redirect to after authentication.
 */
Route::get('/auth/github/callback', function () {
    $providerUser = Socialite::driver('github')->stateless()->user();
    // this user we get back is not our user model,
	// but a special user object that has all the information we need

	// find the user or create a new one
    $user = User::updateOrCreate(
        ['email' => $providerUser->getEmail()],
        ['name'  => $providerUser->getName() ?? $providerUser->getNickname()]
    );

	/**
	* At this point we done.  You can use whatever you are using for authentication here...
	* for our example we'll use JWT
	*/

	$token = JWTAuth::fromUser($user);
	// example if you were using sanctum:
    // $token = $user->createToken('api')->plainTextToken; 

    return response()->json([
        'token' => $token,
        'user'  => $user,
    ]);
});
    

NOTE: Socialite only covers the social login piece—you still need JWT, Sanctum, Passport, or another auth system for the rest of your API.

This is a very basic example and I have included some comments in my code sample to explain a few things. However the basic idea is this: When you configure your github integration, or integration with any other platform... you will have to setup a "callback url". Which is basically just the endpoint it hits after you successfully authorize the app. In this method we can take the provider user that socialite gives us and we can build our real user and save the information down to our database. You can then use whatever authentication you like to create a token etc and send it back to the user.

We need the stateless functionality here because our app isn't going to remember the state, and it is an optional parameter for oauth. It doesn't matter what we used to authorize as long as the callback url hits this endpoint and we use the stateless method.

Conclusion

That wraps up this example, feel free to reach out with questions or thoughts. Below are some resources links to help you get your stateless API working with social authentication!

Resources

Isaac Earl Avatar

Isaac Earl

// Lead Developer

Related Posts

  • Diagram showing multi-tenant SaaS architecture with user connecting to multiple organization subdomains and Laravel logo
    Development Building Multi-Tenant SaaS with Laravel and Spatie

    A practical guide to building multi-tenant SaaS applications where users belong to multiple organizations, using Laravel and Spatie multitenancy package with subdomain-based routing.

    Read More

Get started

contact us