This commit is contained in:
2025-10-20 14:10:54 +02:00
parent 75ca8fd840
commit d2c1970ef8
732 changed files with 101915 additions and 2 deletions

View File

@@ -0,0 +1,85 @@
OAuth 2.0 Google Provider Changelog
## 4.0.1 - 2022-03-17
### Changed
- Corrected file excludes for dist archive, #120 by @cedric-anne
## 4.0.0 - 2022-03-04
### Changed
- Adding return type, #98 by @yozhef
- Add PHP 8.0 support, require PHP 7.3 or newer, #102 by @yozhef
## 3.0.4 - 2021-01-27
### Fixed
- Correct OAuth endpoint, #94 by @Slamdunk
## 3.0.3 - 2020-07-24
### Fixed
- Remove the `approval_prompt` from default parameters, #90
## 3.0.2 - 2019-11-16
### Fixed
- Allow for `family_name` to be undefined in user information, #79 by @majkel89
## 3.0.1 - 2018-12-28
### Fixed
- Correct conflict handling for prompt option, #69 by @mxdpeep
## 3.0.0 - 2018-12-23
### Changed
- Update to latest version of Google OAuth
- Use only OpenID Connect for user details
### Fixed
- Correct handling of selecting from multiple user accounts, #45
- Prevent conflict when using prompt option, #42
### Added
- Add "locale" to user details, #60
- Support additional scopes at construction
### Removed
- Dropped support for Google+ user details, #34 and #63
## 2.2.0 - 2018-03-19
### Added
- Hosted domain validation, #54 by @pradtke
## 2.1.0 - 2018-03-09
### Added
- OpenID Connect support, #48 by @pradtke
## 2.0.0 - 2017-01-24
### Added
- PHP 7.1 support
### Removed
- Dropped PHP 5.5 support
## 1.0.0 - 2015-08-12
- Initial release

View File

@@ -0,0 +1,42 @@
# Contributing
Contributions are **welcome** and will be fully **credited**.
We accept contributions via Pull Requests on [Github](https://github.com/thephpleague/oauth2-google).
## Pull Requests
- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer).
- **Add tests!** - Your patch won't be accepted if it doesn't have tests.
- **Document any change in behaviour** - Make sure the README and any other relevant documentation are kept up-to-date.
- **Consider our release cycle** - We try to follow SemVer. Randomly breaking public APIs is not an option.
- **Create topic branches** - Don't ask us to pull from your master branch.
- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests.
- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting.
- **Ensure tests pass!** - Please run the tests (see below) before submitting your pull request, and make sure they pass. We won't accept a patch until all tests pass.
- **Ensure no coding standards violations** - Please run PHP Code Sniffer using the PSR-2 standard (see below) before submitting your pull request. A violation will cause the build to fail, so please make sure there are no violations. We can't accept a patch if the build fails.
## Running Tests
```sh
composer test
```
## Running PHP Code Sniffer
```sh
composer check
```
**Happy coding**!

View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2015 Woody Gilk <woody.gilk@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

View File

@@ -0,0 +1,239 @@
# Google Provider for OAuth 2.0 Client
[![Build Status](https://img.shields.io/github/workflow/status/thephpleague/oauth2-google/test/main)](https://github.com/thephpleague/oauth2-google/actions/workflows/test.yaml)
[![Code Coverage](https://img.shields.io/codecov/c/gh/thephpleague/oauth2-google)](https://app.codecov.io/gh/thephpleague/oauth2-google)
[![License](https://img.shields.io/packagist/l/league/oauth2-google)](https://github.com/thephpleague/oauth2-google/blob/main/LICENSE)
[![Latest Stable Version](https://img.shields.io/packagist/v/league/oauth2-google)](https://packagist.org/packages/league/oauth2-google)
This package provides Google OAuth 2.0 support for the PHP League's [OAuth 2.0 Client](https://github.com/thephpleague/oauth2-client).
This package is compliant with [PSR-1][], [PSR-2][] and [PSR-4][]. If you notice compliance oversights, please send
a patch via pull request.
[PSR-1]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-1-basic-coding-standard.md
[PSR-2]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md
[PSR-4]: https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md
## Requirements
The following versions of PHP are supported.
* PHP 7.3
* PHP 7.4
* PHP 8.0
* PHP 8.1
This package uses [OpenID Connect][openid-connect] to authenticate users with
Google accounts.
To use this package, it will be necessary to have a Google client ID and client
secret. These are referred to as `{google-client-id}` and `{google-client-secret}`
in the documentation.
Please follow the [Google instructions][oauth-setup] to create the required credentials.
[openid-connect]: https://developers.google.com/identity/protocols/OpenIDConnect
[oauth-setup]: https://developers.google.com/identity/protocols/OpenIDConnect#registeringyourapp
## Installation
To install, use composer:
```sh
composer require league/oauth2-google
```
## Usage
### Authorization Code Flow
```php
require __DIR__ . '/vendor/autoload.php';
use League\OAuth2\Client\Provider\Google;
session_start(); // Remove if session.auto_start=1 in php.ini
$provider = new Google([
'clientId' => '{google-client-id}',
'clientSecret' => '{google-client-secret}',
'redirectUri' => 'https://example.com/callback-url',
'hostedDomain' => 'example.com', // optional; used to restrict access to users on your G Suite/Google Apps for Business accounts
]);
if (!empty($_GET['error'])) {
// Got an error, probably user denied access
exit('Got error: ' . htmlspecialchars($_GET['error'], ENT_QUOTES, 'UTF-8'));
} elseif (empty($_GET['code'])) {
// If we don't have an authorization code then get one
$authUrl = $provider->getAuthorizationUrl();
$_SESSION['oauth2state'] = $provider->getState();
header('Location: ' . $authUrl);
exit;
} elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) {
// State is invalid, possible CSRF attack in progress
unset($_SESSION['oauth2state']);
exit('Invalid state');
} else {
// Try to get an access token (using the authorization code grant)
$token = $provider->getAccessToken('authorization_code', [
'code' => $_GET['code']
]);
// Optional: Now you have a token you can look up a users profile data
try {
// We got an access token, let's now get the owner details
$ownerDetails = $provider->getResourceOwner($token);
// Use these details to create a new profile
printf('Hello %s!', $ownerDetails->getFirstName());
} catch (Exception $e) {
// Failed to get user details
exit('Something went wrong: ' . $e->getMessage());
}
// Use this to interact with an API on the users behalf
echo $token->getToken();
// Use this to get a new access token if the old one expires
echo $token->getRefreshToken();
// Unix timestamp at which the access token expires
echo $token->getExpires();
}
```
#### Available Options
The `Google` provider has the following [options][auth-params]:
- `accessType` to use online or offline access
- `hostedDomain` to authenticate G Suite users
- `prompt` to modify the prompt that the user will see
- `scopes` to request access to additional user information
[auth-params]: https://developers.google.com/identity/protocols/OpenIDConnect#authenticationuriparameters
#### Accessing Token JWT
Google provides a [JSON Web Token][jwt] (JWT) with all access tokens. This token
[contains basic information][openid-jwt] about the authenticated user. The JWT
can be accessed from the `id_token` value of the access token:
```php
/** @var League\OAuth2\Client\Token\AccessToken $token */
$values = $token->getValues();
/** @var string */
$jwt = $values['id_token'];
```
Parsing the JWT will require a [JWT parser][jwt-parsers]. Refer to parser
documentation for instructions.
[jwt]: https://jwt.io/
[openid-jwt]: https://developers.google.com/identity/protocols/OpenIDConnect#obtainuserinfo
[jwt-parsers]: https://packagist.org/search/?q=jwt
### Refreshing a Token
Refresh tokens are only provided to applications which request offline access. You can specify offline access by setting the `accessType` option in your provider:
```php
use League\OAuth2\Client\Provider\Google;
$provider = new Google([
'clientId' => '{google-client-id}',
'clientSecret' => '{google-client-secret}',
'redirectUri' => 'https://example.com/callback-url',
'accessType' => 'offline',
]);
```
It is important to note that the refresh token is only returned on the first request after this it will be `null`. You should securely store the refresh token when it is returned:
```php
$token = $provider->getAccessToken('authorization_code', [
'code' => $code
]);
// persist the token in a database
$refreshToken = $token->getRefreshToken();
```
If you ever need to get a new refresh token you can request one by forcing the consent prompt:
```php
$authUrl = $provider->getAuthorizationUrl(['prompt' => 'consent', 'access_type' => 'offline']);
```
Now you have everything you need to refresh an access token using a refresh token:
```php
use League\OAuth2\Client\Provider\Google;
use League\OAuth2\Client\Grant\RefreshToken;
$provider = new Google([
'clientId' => '{google-client-id}',
'clientSecret' => '{google-client-secret}',
'redirectUri' => 'https://example.com/callback-url',
]);
$grant = new RefreshToken();
$token = $provider->getAccessToken($grant, ['refresh_token' => $refreshToken]);
```
## Scopes
Additional [scopes][scopes] can be set by using the `scope` parameter when
generating the authorization URL:
```php
$authorizationUrl = $provider->getAuthorizationUrl([
'scope' => [
'scope-url-here'
],
]);
```
[scopes]: https://developers.google.com/identity/protocols/googlescopes
## Testing
Tests can be run with:
```sh
composer test
```
Style checks can be run with:
```sh
composer check
```
## Contributing
Please see [CONTRIBUTING](https://github.com/thephpleague/oauth2-google/blob/main/CONTRIBUTING.md) for details.
## Credits
- [Woody Gilk](https://github.com/shadowhand)
- [All Contributors](https://github.com/thephpleague/oauth2-google/contributors)
## License
The MIT License (MIT). Please see [License File](https://github.com/thephpleague/oauth2-google/blob/main/LICENSE) for more information.

View File

@@ -0,0 +1,43 @@
{
"name": "league\/oauth2-google",
"description": "Google OAuth 2.0 Client Provider for The PHP League OAuth2-Client",
"license": "MIT",
"authors": [
{
"name": "Woody Gilk",
"email": "hello@shadowhand.com",
"homepage": "https:\/\/shadowhand.com"
}
],
"keywords": [
"oauth",
"oauth2",
"client",
"authorization",
"authentication",
"google"
],
"minimum-stability": "stable",
"require": {
"php": "^7.3 || ^8.0",
"league\/oauth2-client": "^2.0"
},
"require-dev": {
"eloquent\/phony-phpunit": "^6.0 || ^7.1",
"phpunit\/phpunit": "^8.0 || ^9.0",
"squizlabs\/php_codesniffer": "^3.0"
},
"autoload": {
"psr-4": {
"Pshowsso\\Scope68f5e85e9608b\\League\\OAuth2\\Client\\": "src\/"
}
},
"autoload-dev": {
"psr-4": {
"Pshowsso\\Scope68f5e85e9608b\\League\\OAuth2\\Client\\Test\\": "test\/src\/"
}
},
"scripts": {
"check": "phpcs src test --standard=PSR12 -sp"
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Pshowsso\Scope68f5e85e9608b\League\OAuth2\Client\Exception;
/**
* Exception thrown if the Google Provider is configured with a hosted domain that the user doesn't belong to
*/
class HostedDomainException extends \Exception
{
/**
* @param $configuredDomain
*
* @return static
*/
public static function notMatchingDomain($configuredDomain): self
{
return new static("User is not part of domain '{$configuredDomain}'");
}
}

View File

@@ -0,0 +1,120 @@
<?php
namespace Pshowsso\Scope68f5e85e9608b\League\OAuth2\Client\Provider;
use Pshowsso\Scope68f5e85e9608b\League\OAuth2\Client\Exception\HostedDomainException;
use Pshowsso\Scope68f5e85e9608b\League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use Pshowsso\Scope68f5e85e9608b\League\OAuth2\Client\Token\AccessToken;
use Pshowsso\Scope68f5e85e9608b\League\OAuth2\Client\Tool\BearerAuthorizationTrait;
use Pshowsso\Scope68f5e85e9608b\Psr\Http\Message\ResponseInterface;
class Google extends AbstractProvider
{
use BearerAuthorizationTrait;
/**
* @var string If set, this will be sent to google as the "access_type" parameter.
* @link https://developers.google.com/identity/protocols/OpenIDConnect#authenticationuriparameters
*/
protected $accessType;
/**
* @var string If set, this will be sent to google as the "hd" parameter.
* @link https://developers.google.com/identity/protocols/OpenIDConnect#authenticationuriparameters
*/
protected $hostedDomain;
/**
* @var string If set, this will be sent to google as the "prompt" parameter.
* @link https://developers.google.com/identity/protocols/OpenIDConnect#authenticationuriparameters
*/
protected $prompt;
/**
* @var array List of scopes that will be used for authentication.
* @link https://developers.google.com/identity/protocols/googlescopes
*/
protected $scopes = [];
public function getBaseAuthorizationUrl(): string
{
return 'https://accounts.google.com/o/oauth2/v2/auth';
}
public function getBaseAccessTokenUrl(array $params): string
{
return 'https://oauth2.googleapis.com/token';
}
public function getResourceOwnerDetailsUrl(AccessToken $token): string
{
return 'https://openidconnect.googleapis.com/v1/userinfo';
}
protected function getAuthorizationParameters(array $options): array
{
if (empty($options['hd']) && $this->hostedDomain) {
$options['hd'] = $this->hostedDomain;
}
if (empty($options['access_type']) && $this->accessType) {
$options['access_type'] = $this->accessType;
}
if (empty($options['prompt']) && $this->prompt) {
$options['prompt'] = $this->prompt;
}
// Default scopes MUST be included for OpenID Connect.
// Additional scopes MAY be added by constructor or option.
$scopes = array_merge($this->getDefaultScopes(), $this->scopes);
if (!empty($options['scope'])) {
$scopes = array_merge($scopes, $options['scope']);
}
$options['scope'] = array_unique($scopes);
$options = parent::getAuthorizationParameters($options);
// The "approval_prompt" MUST be removed as it is not supported by Google, use "prompt" instead:
// https://developers.google.com/identity/protocols/oauth2/openid-connect#prompt
unset($options['approval_prompt']);
return $options;
}
protected function getDefaultScopes(): array
{
// "openid" MUST be the first scope in the list.
return ['openid', 'email', 'profile'];
}
protected function getScopeSeparator(): string
{
return ' ';
}
protected function checkResponse(ResponseInterface $response, $data): void
{
// @codeCoverageIgnoreStart
if (empty($data['error'])) {
return;
}
// @codeCoverageIgnoreEnd
$code = 0;
$error = $data['error'];
if (is_array($error)) {
$code = $error['code'];
$error = $error['message'];
}
throw new IdentityProviderException($error, $code, $data);
}
protected function createResourceOwner(array $response, AccessToken $token): GoogleUser
{
$user = new GoogleUser($response);
$this->assertMatchingDomain($user->getHostedDomain());
return $user;
}
/**
* @param string|null $hostedDomain
*
* @throws HostedDomainException If the domain does not match the configured domain.
*/
protected function assertMatchingDomain(?string $hostedDomain): void
{
if ($this->hostedDomain === null) {
// No hosted domain configured.
return;
}
if ($this->hostedDomain === '*' && $hostedDomain) {
// Any hosted domain is allowed.
return;
}
if ($this->hostedDomain === $hostedDomain) {
// Hosted domain is correct.
return;
}
throw HostedDomainException::notMatchingDomain($this->hostedDomain);
}
}

View File

@@ -0,0 +1,98 @@
<?php
namespace Pshowsso\Scope68f5e85e9608b\League\OAuth2\Client\Provider;
class GoogleUser implements ResourceOwnerInterface
{
/**
* @var array
*/
protected $response;
/**
* @param array $response
*/
public function __construct(array $response)
{
$this->response = $response;
}
public function getId()
{
return $this->response['sub'];
}
/**
* Get preferred display name.
*
* @return string
*/
public function getName(): string
{
return $this->response['name'];
}
/**
* Get preferred first name.
*
* @return string|null
*/
public function getFirstName(): ?string
{
return $this->getResponseValue('given_name');
}
/**
* Get preferred last name.
*
* @return string|null
*/
public function getLastName(): ?string
{
return $this->getResponseValue('family_name');
}
/**
* Get locale.
*
* @return string|null
*/
public function getLocale(): ?string
{
return $this->getResponseValue('locale');
}
/**
* Get email address.
*
* @return string|null
*/
public function getEmail(): ?string
{
return $this->getResponseValue('email');
}
/**
* Get hosted domain.
*
* @return string|null
*/
public function getHostedDomain(): ?string
{
return $this->getResponseValue('hd');
}
/**
* Get avatar image URL.
*
* @return string|null
*/
public function getAvatar(): ?string
{
return $this->getResponseValue('picture');
}
/**
* Get user data as an array.
*
* @return array
*/
public function toArray(): array
{
return $this->response;
}
private function getResponseValue($key)
{
return $this->response[$key] ?? null;
}
}