Skip to content

Commit

Permalink
Add Zitadel provider (#1245)
Browse files Browse the repository at this point in the history
Co-authored-by: atymic <atymicq@gmail.com>
  • Loading branch information
tbhaxor and atymic authored Aug 24, 2024
0 parents commit 188e0f7
Show file tree
Hide file tree
Showing 4 changed files with 226 additions and 0 deletions.
110 changes: 110 additions & 0 deletions Provider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?php

namespace SocialiteProviders\Zitadel;

use GuzzleHttp\RequestOptions;
use Illuminate\Support\Arr;
use SocialiteProviders\Manager\OAuth2\AbstractProvider;
use SocialiteProviders\Manager\OAuth2\User;
use InvalidArgumentException;

class Provider extends AbstractProvider
{
public const INDENTIFIER = 'ZITADEL';

/** @inheritDoc */
protected $scopeSeparator = ' ';

/** @inheritDoc */
protected $scopes = ['openid', 'profile', 'email'];

/** @inheritDoc */
public function getScopes()
{
$additionalScopes = [];
if ($this->getConfig('organization_id')) {
array_push($additionalScopes, 'urn:zitadel:iam:org:id:' . $this->getConfig('organization_id'));
}
if ($this->getConfig('project_id')) {
array_push($additionalScopes, 'urn:zitadel:iam:org:project:id:' . $this->getConfig('project_id') . ':aud');
}
return array_merge($this->scopes, $additionalScopes);
}

/** @inheritDoc */
public static function additionalConfigKeys()
{
return [
'base_url',
'organization_id',
'project_id',
'post_logout_redirect_uri'
];
}

/** @inheritDoc */
protected function getAuthUrl($state)
{
return $this->buildAuthUrlFromBase($this->getConfig('base_url') . '/oauth/v2/authorize', $state);
}

/** @inheritDoc */
protected function getTokenUrl()
{
return $this->getConfig('base_url') . '/oauth/v2/token';
}

/** @inheritDoc */
protected function getUserByToken($token)
{
return json_decode($this->getHttpClient()->get($this->getConfig('base_url') . '/oidc/v1/userinfo', [
RequestOptions::HEADERS => [
'Authorization' => 'Bearer ' . $token
]
])->getBody(), true);
}

/** @inheritDoc */
protected function parseApprovedScopes($body)
{
$scopes = parent::parseApprovedScopes($body);
return array_unique(array_merge($scopes, $this->getScopes()));
}

/** @inheritDoc */
public function mapUserToObject(array $user): User
{
return (new User())->setRaw($user)->map([
'id' => Arr::get($user, 'sub'),
'email' => Arr::get($user, 'email'),
'name' => Arr::get($user, 'name'),
'nickname' => Arr::get($user, 'preferred_username'),
'avatar' => Arr::get($user, 'picture')
]);
}

/**
* Return logout endpoint.
*
* @link https://zitadel.com/docs/apis/openidoauth/endpoints#end_session_endpoint
*
* @param string|null $idToken ID token from the access token response
* @return string
*
* @throws Invalid
*/
public function getLogoutUrl($idToken)
{
if (is_null($redirect = $this->getConfig('post_logout_redirect_uri'))) {
throw new InvalidArgumentException('services.zitadel.post_logout_redirect_uri configuration is missing');
}
$query = [
'id_token_hint' => $idToken,
'client_id' => $this->clientId,
'post_logout_redirect_uri' => $redirect,
'state' => $this->getState()
];

return $this->getConfig('base_url') . '/oidc/v1/end_session?' . http_build_query($query);
}
}
74 changes: 74 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# Zitadel

```bash
composer require socialiteproviders/zitadel
```

## Installation & Basic Usage

Please see the [Base Installation Guide](https://socialiteproviders.com/usage/), then follow the provider specific instructions below.

### Add configuration to `config/services.php`

```php
'zitadel' => [
'client_id' => env('ZITADEL_CLIENT_ID'),
'client_secret' => env('ZITADEL_CLIENT_SECRET'),
'redirect' => env('ZITADEL_REDIRECT_URI'),
'base_url' => env('ZITADEL_BASE_URL'),
'organization_id' => env('ZITADEL_ORGANIZATION_ID'), // Optional
'project_id' => env('ZITADEL_PROJECT_ID'), // Optional
'post_logout_redirect_uri' => env('ZITADEL_POST_LOGOUT_REDIRECT_URI') // Optional
],
```

### Add provider event listener

#### Laravel 11+

In Laravel 11, the default `EventServiceProvider` provider was removed. Instead, add the listener using the `listen` method on the `Event` facade, in your `AppServiceProvider` `boot` method.

- Note: You do not need to add anything for the built-in socialite providers unless you override them with your own providers.

```php
Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) {
$event->extendSocialite('zitadel', \SocialiteProviders\Zitadel\Provider::class);
});
```

<details>
<summary>
Laravel 10 or below
</summary>
Configure the package's listener to listen for `SocialiteWasCalled` events.

Add the event to your `listen[]` array in `app/Providers/EventServiceProvider`. See the [Base Installation Guide](https://socialiteproviders.com/usage/) for detailed instructions.

```php
protected $listen = [
\SocialiteProviders\Manager\SocialiteWasCalled::class => [
// ... other providers
\SocialiteProviders\Zitadel\ZitadelExtendSocialite::class.'@handle',
],
];
```

</details>

### Usage

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('zitadel')->redirect();
```

### Get Logout Url

```php
$idToken = ...; // Retrieve ID token here
return redirect()->away(Socialite::driver('zitadel')->getLogoutUrl($idToken));
```

> [!NOTE]
> Passing the ID token is optional, but it is recommended to logout specific user session.
14 changes: 14 additions & 0 deletions ZitadelExtendSocialite.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace SocialiteProviders\Zitadel;

use SocialiteProviders\Manager\SocialiteWasCalled;

class ZitadelExtendSocialite
{

public function handle(SocialiteWasCalled $socialiteWasCalled)
{
$socialiteWasCalled->extendSocialite('zitadel', Provider::class);
}
}
28 changes: 28 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"$schema": "https://getcomposer.org/schema.json",
"name": "socialiteproviders/zitadel",
"description": "Zitadel OAuth2 Provider for Laravel Socialite",
"license": "MIT",
"version": "1.0.0",
"autoload": {
"psr-4": {
"Socialiteproviders\\Zitadel\\": ""
}
},
"authors": [
{
"name": "Gurkirat Singh",
"email": "tbhaxor@gmail.com"
}
],
"require": {
"php": "^8.1",
"ext-json": "*",
"socialiteproviders/manager": "^4.4"
},
"support": {
"issues": "https://github.com/socialiteproviders/providers/issues",
"source": "https://github.com/socialiteproviders/providers",
"docs": "https://socialiteproviders.com/zoho"
}
}

0 comments on commit 188e0f7

Please sign in to comment.