Google Grant Type in Laravel with Socialite, log in with Google API
Tags: login, google, laravel, php
Published: 2024-02-14 15:54:41

Hi Everyone
To authenticate your app from the front end, follow these steps to build an API for Google login. The API will produce a bearer token, which you can check in the Laravel backend. and verify a user accordingly.
Step 1. Install [Laravel Socialite] (https://laravel.com/docs/10.x/socialite) package. and [Laravel Passport](https://laravel.com/docs/10.x/passport)
Step 2. Add this code to service.php
```
  'google' => [
    'api_key' => env('GOOGLE_API_KEY'),
    'client_id' => env('GOOGLE_CLIENT_ID'),
    'client_secret' => env('GOOGLE_CLIENT_SECRET'),
    'redirect' => env('GOOGLE_REDIRECT')
    ]
```
setup the key form your google in your.env file
Step 3. Create a file in `app/Grant/GoogleGrant.php` or anywhere in your app.
Step 4. Copy paste or modify this code according to you.
```php
<?php

namespace App\Grants;

use App\User;
use DateInterval;
use Google\Exception;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\ValidationException;
use Laravel\Socialite\Facades\Socialite;
use League\OAuth2\Server\Grant\AbstractGrant;
use League\OAuth2\Server\Repositories\RefreshTokenRepositoryInterface;
use League\OAuth2\Server\ResponseTypes\ResponseTypeInterface;
use Psr\Http\Message\ServerRequestInterface;

class GoogleGrant extends AbstractGrant
{
    public function __construct(
        RefreshTokenRepositoryInterface $refreshTokenRepository
    ) {
        $this->refreshTokenRepository = $refreshTokenRepository;
    }

    /**
     * @inheritDoc
     * @return string
     */
    public function getIdentifier(): string
    {
        return 'google';
    }

    /**
     * @inheritDoc
     *
     * @param ServerRequestInterface $request
     * @param ResponseTypeInterface $responseType
     * @param DateInterval $accessTokenTTL
     * @return ResponseTypeInterface
     * @throws
     */
    public function respondToAccessTokenRequest(
        ServerRequestInterface $request,
        ResponseTypeInterface  $responseType,
        DateInterval $accessTokenTTL
    ): ResponseTypeInterface {
        $client = $this->validateClient($request);
        $scopes = $this->validateScopes($this->getRequestParameter('scope', $request));

        $user = $this->validateUser($request);

        // Finalize the requested scopes
        $scopes = $this->scopeRepository
            ->finalizeScopes($scopes, $this->getIdentifier(), $client, $user->getAuthIdentifier());

        // Issue and persist new tokens
        $accessToken = $this->issueAccessToken($accessTokenTTL, $client, $user->getAuthIdentifier(), $scopes);
        $refreshToken = $this->issueRefreshToken($accessToken);

        // Inject tokens into response
        $responseType->setAccessToken($accessToken);
        $responseType->setRefreshToken($refreshToken);

        return $responseType;
    }

    /**
     * Validate the request content and generate mapped user
     *
     * @param ServerRequestInterface $request
     * @return User
     * @throws GoogleLoginFailure
     * @throws ValidationException
     * @throws Exception
     */
    public function validateUser(ServerRequestInterface $request): User
    {
        $validator = Validator::make($request->getParsedBody(), [
            'access_token' => 'required'
        ]);

        $validator->validate();

        try {
            $user = Socialite::driver('google')->userFromToken($request->getParsedBody()['access_token']);
        } catch (ClientException $clientException) {
            throw new ClientException($clientException);
        }

        /**
         * @var $authUser User
         */
        try {
            return User::where('email', $user->email)->firstOrFail();
        } catch (ModelNotFoundException $ex) {
             abort(401, 'Custom message');
            throw new ModelNotFoundException('custom message');
        }
    }
}

```
step 5. Register this grant you AuthServiceProvide.php file. inside `boot()` method
```php
  try {
            $this->app->make(AuthorizationServer::class)
                ->enableGrantType(
                    $this->googleGrant(),
                    Passport::tokensExpireIn()
                );
        } catch (LogicException $exception) {
            return;
        }
```
Step 6. Make a method AuthServiceProvide.php
```php
   /**
     * Returns GoogleGrant instance
     *
     * @return GoogleGrant
     * @throw
     * @throws Exception
     * @throws ContainerExceptionInterface
     */
    protected function googleGrant(): GoogleGrant
    {
        $this->app->singleton(GoogleGrant::class, function () {
            $googleGrant = new GoogleGrant($this->app->make(RefreshTokenRepository::class));
            $googleGrant->setRefreshTokenTTL(Passport::refreshTokensExpireIn());
            return $googleGrant;
        });

        try {
            return $this->app->get(GoogleGrant::class);
        } catch (NotFoundExceptionInterface $e) {
            throw new Exception($e);
        }
    }
```