Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Google Authentication using the new API #1036

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
2 changes: 1 addition & 1 deletion monorepo-builder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ parameters:
src/Gitea: '[email protected]:SocialiteProviders/Gitea.git'
src/Gitee: '[email protected]:SocialiteProviders/Gitee.git'
src/Goodreads: '[email protected]:SocialiteProviders/Goodreads.git'
src/Google: '[email protected]:SocialiteProviders/Google-Plus.git'
src/Google: '[email protected]:SocialiteProviders/Google.git'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: need to rename this repo

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do you mean remove? Google+ has become redundant, no?

src/GovBR: '[email protected]:SocialiteProviders/GovBR.git'
src/Graph: '[email protected]:SocialiteProviders/Microsoft-Graph.git'
src/Gumroad: '[email protected]:SocialiteProviders/Gumroad.git'
Expand Down
46 changes: 46 additions & 0 deletions src/Google/GoogleUser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<?php

namespace SocialiteProviders\Google;

use SocialiteProviders\Manager\OAuth2\User;

class GoogleUser extends User
{
/**
* The email verification status.
*
* @var bool
*/
public $email_verified;

/**
* The organization the user belongs to.
*
* @var string
*/
public $organization;

/**
* Checks if the user's email is verified.
*
* @return bool
*/
public function isEmailVerified()
{
return $this->email_verified;
}

/**
* Sets the organization for the current user.
*
* @param string $organization
*
* @return $this
*/
public function setOrganization($organization)
{
$this->organization = $organization;

return $this;
}
}
118 changes: 112 additions & 6 deletions src/Google/Provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,119 @@

namespace SocialiteProviders\Google;

use Laravel\Socialite\Two\GoogleProvider;
use SocialiteProviders\Manager\ConfigTrait;
use SocialiteProviders\Manager\Contracts\OAuth2\ProviderInterface;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use SocialiteProviders\Manager\OAuth2\AbstractProvider;

class Provider extends GoogleProvider implements ProviderInterface
class Provider extends AbstractProvider
{
use ConfigTrait;
/**
* The authenticated user instance.
*
* @var GoogleUser
*/
protected $user;

public const IDENTIFIER = 'GOOGLE';
/**
* The current request instance.
*
* @var \Illuminate\Http\Request
*/
protected $request;

/**
* The client ID.
*
* @var string
*/
protected $clientId;


/**
* Create a new Google provider instance.
*
* @param \Illuminate\Http\Request $request
* @param string $clientId
*/
public function __construct(Request $request, $clientId)
{
$this->request = $request;
$this->clientId = $clientId;
}

/**
* Redirect the user to the authentication page for the provider.
*
* @throws \Exception
*/
public function redirect()
{
throw new \RuntimeException('Redirect is deprecated for the new Google Auth, see https://developers.google.com/identity/gsi/web/guides/migration#html_and_javascript');
}

/**
* Get the User instance for the authenticated user.
*
* @throws InvalidJwtException
* @return GoogleUser
*/
public function user()
{
if ($this->user) {
return $this->user;
}
$jwt = $this->request->credential;
CosminBd marked this conversation as resolved.
Show resolved Hide resolved
$certificates = $this->fetchCertificates();
$decoded = (array) JWT::decode($jwt, $certificates);
return $this->user = $this->mapUserToObject($decoded)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line break above please

->setOrganization(Arr::get($decoded, 'hd'));
}

/**
* Map the raw user array to a Socialite User instance.
*
* @param array $user
* @return GoogleUser
*/
protected function mapUserToObject(array $user)
{
return (new GoogleUser())->setRaw($user)->map([
'id' => Arr::get($user, 'sub'),
'nickname' => Arr::get($user, 'nickname'),
'name' => Arr::get($user, 'name'),
'email_verified' => Arr::get($user, 'email_verified'),
'email' => Arr::get($user, 'email'),
'avatar' => $avatarUrl = Arr::get($user, 'picture'),
'avatar_original' => $avatarUrl,
]);
}

/**
* Fetches the Google signing certificates for JWTs.
*
* @return array
*/
protected function fetchCertificates(): array
{
return collect(json_decode(file_get_contents('https://www.googleapis.com/oauth2/v1/certs'), true))->map(function ($key) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if getting this endpoint fails?

return new Key($key, 'RS256');
})->toArray();
}

protected function getAuthUrl($state)
{
// TODO: Implement getAuthUrl() method.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for these comments

}

protected function getTokenUrl()
{
// TODO: Implement getTokenUrl() method.
}

protected function getUserByToken($token)
{
// TODO: Implement getUserByToken() method.
}
}
39 changes: 27 additions & 12 deletions src/Google/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ Please see the [Base Installation Guide](https://socialiteproviders.com/usage/),
### Add configuration to `config/services.php`

```php
'google' => [
'client_id' => env('GOOGLE_CLIENT_ID'),
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
'redirect' => env('GOOGLE_REDIRECT_URI')
'google' => [
'client_id' => env('GOOGLE_CLIENT_ID'),
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
'redirect' => env('GOOGLE_REDIRECT_URI')
],
```

Expand All @@ -37,14 +37,29 @@ protected $listen = [

You should now be able to use the provider like you would regularly use Socialite (assuming you have the facade installed):

```php
return Socialite::driver('google')->redirect();
The redirect method is not needed, as credential retrieval is done client-side via JavaScript.
The requirement is having the gsi/client script loaded on the page, and the g_id_onload div with the data attributes set.
In Blade, it would look something like:
```html
<script src="https://accounts.google.com/gsi/client" async defer></script>
<div id="g_id_onload"
data-client_id="{{config('services.google.client_id')}}"
data-login_uri="{{config('services.google.redirect')}}"
data-auto_prompt="false">
</div>
<div class="g_id_signin"
data-type="standard"
data-size="large"
data-theme="outline"
data-text="sign_in_with"
data-shape="rectangular"
data-logo_alignment="left">
</div>
```

### Returned User fields
For retrieving the user, you can use the following code in your redirect controller:

- ``id``
- ``nickname``
- ``name``
- ``email``
- ``avatar``
```php
$user = Socialite::driver('google')->user();
dd($user);
```
11 changes: 5 additions & 6 deletions src/Google/composer.json
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
{
"name": "socialiteproviders/google",
"description": "Google OAuth2 Provider for Laravel Socialite",
"description": "Google Authentication Provider via JWT (new API) for Laravel Socialite",
"license": "MIT",
"keywords": [
"google",
"laravel",
"oauth",
"provider",
"socialite"
],
"authors": [
{
"name": "xstoop",
"email": "[email protected]"
"name": "Cosmin Badea",
"email": "[email protected]"
}
],
"support": {
"issues": "https://github.com/socialiteproviders/providers/issues",
"source": "https://github.com/socialiteproviders/providers",
"docs": "https://socialiteproviders.com/google"
"source": "https://github.com/socialiteproviders/providers"
},
"require": {
"php": "^8.0",
"ext-json": "*",
"firebase/php-jwt": "^6.8"
"socialiteproviders/manager": "^4.4"
},
"autoload": {
Expand Down
Loading