Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

elo's avatar
Level 3

Adding Social Authentication to API

Guys, I am working on an API application using Laravel 5.8. The API application has no web page and will only be returning json response. For instance when a user is successfully authenticated, a response is returned similar to this

{
    "responseMessage":"Successfully Registered.",
    "responseStatus":201,
    "token":"eyJ0eXAiOiJKV1...",
}

To add social authentication, I have added the socialite package and was able to log new users in using facebook and google with this code blocks below

Redirect and Callback routes in web.php file

Auth::routes(['verify' => true]);

Route::get('/auth/{provider}', 'SocialAuthController@redirectToProvider');

Route::get('/auth/{provider}/callback', 'SocialAuthController@handleProviderCallback');

Then the controller methods are

public function redirectToProvider($provider)
{
    return Socialite::driver($provider)->redirect();
}

public function handleProviderCallback($provider)
{
    // retrieve social user info
    $socialUser = Socialite::driver($provider)->stateless()->user();

    // check if social user provider record is stored
    $userSocialAccount = SocialAccount::where('provider_id', $socialUser->id)->where('provider_name', $provider)->first();

    if ($userSocialAccount) {

        // retrieve the user from users store
        $user = User::find($userSocialAccount->user_id);

        // assign access token to user
        $token = $user->createToken('string')->accessToken;

        // return access token & user data
        return response()->json([
            'token' => $token,
            'user'  => (new UserResource($user))
        ]);
    } else {

        // store the new user record
        $user = User::create([...]);

        // store user social provider info
        if ($user) {

            SocialAccount::create([...]);
        }

        // assign passport token to user
        $token = $user->createToken('string')->accessToken;
        $newUser = new UserResource($user);
        $responseMessage = 'Successfully Registered.';
        $responseStatus = 201;

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

Now when a user is authenticated, I see the expected message in the web browser window (not console). Can the the react web application or mobile application use the information that is returned this way? Or is there another way of doing it? I am not sure as this is my first implementation of implementing social auth to API only application.

0 likes
7 replies
elo's avatar
Level 3

Assuming I decide not to manually generate the access token which I am doing now so that it is passed in the bearer token header, please what would be the flow for social login?

audunru's avatar

Maybe I misunderstood something when I first read your post. You're consuming your own API from a React application on a different domain?

I think in that case you would have to redirect to your react app and pass it the token once the user has been created or logged in.

I've modified some code from one of my own projects to approximate what you're trying to achieve. It's not a 1:1 with your situation as in my case we only allow Google logins from existing employees, but I think you get it. :-D

GoogleLoginController.php:

<?php

namespace App\Http\Controllers\Auth;

use App\Employee;
use App\Http\Controllers\Controller;
use App\Http\Traits\FindOrCreateUser;
use Illuminate\Support\Facades\Auth;
use Socialite;

class GoogleLoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    use FindOrCreateUser;

    protected $provider;
    protected $redirectTo = '/';

    /**
     * Create a new controller instance.
     */
    public function __construct()
    {
        $this->provider = 'google';
    }

    /**
     * Redirect the user to the Google authentication page.
     *
     * @return \Illuminate\Http\Response
     */
    public function redirectToProvider()
    {
        return Socialite::driver($this->provider)->with(['hd' => env('GOOGLE_HD')])->redirect();
    }

    /**
     * Obtain the user information from Google.
     *
     * @return \Illuminate\Http\Response
     */
    public function handleProviderCallback()
    {
        $user = Socialite::driver($this->provider)->user();

        abort_unless($user->user['hd'] === env('GOOGLE_HD'), 401, 'Domain is not allowed');
        abort_unless(Employee::where('email', $user->email)->first(), 401, 'User is not in employee database');

        $authUser = $this->findOrCreateUser($user->email, $user->name, $this->provider, $user->id);
        Auth::login($authUser, true);

        $token = $authUser->createToken('Token Name')->accessToken;

        return redirect('https://my-frontend-domain.com/dashboard?access_token='.$token);
    }
}

FindOrCreateUser.php:

<?php

namespace App\Http\Traits;

use App\User;
use App\UserRole;

trait FindOrCreateUser
{
    public function findOrCreateUser($email, $name, $provider, $provider_id)
    {
        if ($user = User::where(['email' => $email, 'provider' => $provider, 'provider_id' => $provider_id])->first()) {
            return $user;
        }

        return User::create([
            'name'     => $name,
            'email'    => $email,
            'provider' => $provider,
            'provider_id' => $provider_id,
            'user_role_id' => UserRole::where('name', 'employee')->pluck('id')->first(),
        ]);
    }
}

With this example, I imagine you would do the following:

  1. In your frontend app, if you already have an access_token, make an API request to https://my-backend-domain.com/api/some-resource.
  2. If the response is 401 Unauthorized, redirect the user to https://my-backend-domain.com/login/google or whatever.
  3. That endpoint corresponds to the handleProviderCallback() function, which redirects you back to https://my-frontend-domain.com/dashboard?access_token=bla-bla-bla with a new access_token. You can store that token in a cookie if you'd like and use that to make requests to the API.
2 likes
ebuka4u's avatar

hello guys i realyyyyyyy need your help. i cant make a call to to my API route outside my local network. please help

elo's avatar
Level 3

Now we are both on the same page but which uri have you configured as the callback uri on google developer platform? I think that is where the issue lies.

audunru's avatar

In this case you would use https://my-backend-domain.com/login/google/callback as the callback URL.

I imagine the flow would be like this:

  1. User loads frontend. It tries to access the API in the backend, if unsuccesful it redirects user to https://my-backend-domain.com/login/google
  2. Backend redirects to Google for authorization.
  3. Google redirects to https://my-backend-domain.com/login/google/callback
  4. Backend creates user or finds user and signs in
  5. Backend redirects to frontend, and passes along a fresh token that can be used to make requests.

This would basically be the same flow as when you have your backend and frontend on the same domain, but in step 5 in this case you have to have some way of passing the token to the frontend. If you were on the same domain, you would use the web middleware that Passport has that automatically includes a token in a cookie, but since you're on another domain you can't access the backend's cookies from the frontend domain...

Please or to participate in this conversation.