Skip to content

Commit

Permalink
added Minecraft Provider (#793)
Browse files Browse the repository at this point in the history
Co-authored-by: Lucas Michot <[email protected]>
Co-authored-by: atymic <[email protected]>
  • Loading branch information
3 people authored Mar 14, 2022
0 parents commit 7c0b752
Show file tree
Hide file tree
Showing 4 changed files with 338 additions and 0 deletions.
18 changes: 18 additions & 0 deletions OktaExtendSocialite.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace SocialiteProviders\Okta;

use SocialiteProviders\Manager\SocialiteWasCalled;

class OktaExtendSocialite
{
/**
* Register the provider.
*
* @param \SocialiteProviders\Manager\SocialiteWasCalled $socialiteWasCalled
*/
public function handle(SocialiteWasCalled $socialiteWasCalled)
{
$socialiteWasCalled->extendSocialite('okta', Provider::class);
}
}
179 changes: 179 additions & 0 deletions Provider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
<?php

namespace SocialiteProviders\Okta;

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

class Provider extends AbstractProvider
{
/**
* Unique Provider Identifier.
*/
public const IDENTIFIER = 'OKTA';

/**
* Scopes defintions.
*
* @see https://developer.okta.com/docs/reference/api/oidc/#scopes
*/
public const SCOPE_OPENID = 'openid';
public const SCOPE_PROFILE = 'profile';
public const SCOPE_EMAIL = 'email';
public const SCOPE_ADDRESS = 'address';
public const SCOPE_PHONE = 'phone';
public const SCOPE_OFFLINE_ACCESS = 'offline_access';

/**
* {@inheritdoc}
*/
protected $scopes = [
self::SCOPE_OPENID,
self::SCOPE_PROFILE,
self::SCOPE_EMAIL,
];

/**
* {@inheritdoc}
*/
protected $scopeSeparator = ' ';

protected function getOktaUrl()
{
return $this->getConfig('base_url');
}

/**
* Returns the Auth Server ID based on config option 'auth_server_id'.
*
* @return string
*/
protected function getAuthServerId()
{
$authServerId = (string) $this->getConfig('auth_server_id');

return $authServerId === '' ? $authServerId : $authServerId.'/';
}

/**
* Get the Okta sever URL.
*
* @return string
*/
protected function getOktaServerUrl(): string
{
return $this->getOktaUrl().'/oauth2/'.$this->getAuthServerId();
}

/**
* {@inheritdoc}
*/
public static function additionalConfigKeys()
{
return ['base_url', 'auth_server_id'];
}

/**
* {@inheritdoc}
*/
protected function getAuthUrl($state)
{
return $this->buildAuthUrlFromBase($this->getOktaServerUrl().'v1/authorize', $state);
}

/**
* {@inheritdoc}
*/
protected function getTokenUrl()
{
return $this->getOktaServerUrl().'v1/token';
}

/**
* {@inheritdoc}
*/
protected function getUserByToken($token)
{
$response = $this->getHttpClient()->get($this->getOktaServerUrl().'v1/userinfo', [
RequestOptions::HEADERS => [
'Authorization' => 'Bearer '.$token,
],
]);

return json_decode((string) $response->getBody(), true);
}

/**
* Get the client access token response.
*
* @param array|string $scopes
*
* @return array
*/
public function getClientAccessTokenResponse($scopes = null)
{
$scopes = $scopes ?? $this->getScopes();
$response = $this->getHttpClient()->post($this->getTokenUrl(), [
RequestOptions::AUTH => [$this->clientId, $this->clientSecret],
RequestOptions::HEADERS => ['Cache-Control' => 'no-cache'],
RequestOptions::FORM_PARAMS => [
'grant_type' => 'client_credentials',
'scope' => $this->formatScopes((array) $scopes, $this->scopeSeparator),
],
]);

return json_decode((string) $response->getBody(), true);
}

/**
* {@inheritdoc}
*/
protected function mapUserToObject(array $user)
{
return (new User())->setRaw($user)->map([
'id' => Arr::get($user, 'sub'),
'email' => Arr::get($user, 'email'),
'email_verified' => Arr::get($user, 'email_verified', false),
'nickname' => Arr::get($user, 'nickname'),
'name' => Arr::get($user, 'name'),
'first_name' => Arr::get($user, 'given_name'),
'last_name' => Arr::get($user, 'family_name'),
'profileUrl' => Arr::get($user, 'profile'),
'address' => Arr::get($user, 'address'),
'phone' => Arr::get($user, 'phone'),
'id_token' => $this->credentialsResponseBody['id_token'] ?? null,
]);
}

/**
* {@inheritdoc}
*/
protected function getTokenFields($code)
{
return array_merge(parent::getTokenFields($code), [
'grant_type' => 'authorization_code',
]);
}

/**
* @param string $idToken
* @param string|null $redirectUri
* @param string|null $state
*
* @return string
*/
public function getLogoutUrl(string $idToken, string $redirectUri = null, string $state = null)
{
$url = $this->getOktaServerUrl().'v1/logout';

$params = http_build_query(array_filter([
'id_token_hint' => $idToken,
'post_logout_redirect_uri' => $redirectUri,
'state' => $state,
]));

return "$url?$params";
}
}
108 changes: 108 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# Okta

```bash
composer require socialiteproviders/okta
```

## 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
'okta' => [
'base_url' => env('OKTA_BASE_URL'),
'client_id' => env('OKTA_CLIENT_ID'),
'client_secret' => env('OKTA_CLIENT_SECRET'),
'redirect' => env('OKTA_REDIRECT_URI')
],
```

#### Custom Auth Server

If you're using Okta Developer you should set `auth_server_id` config option appropriately. It should be set to "default", or to the server id of your Custom Authorization Server.

For more information, see the [okta docs](https://developer.okta.com/docs/concepts/auth-servers/).

### Add provider event listener

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\Okta\OktaExtendSocialite::class.'@handle',
],
];
```

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

Store a local copy in your callback:

```php
public function handleProviderCallback(\Illuminate\Http\Request $request)
{
$user = Socialite::driver('okta')->user();
$localUser = User::updateOrCreate(['email' => $user->email], [
'email' => $user->email,
'name' => $user->name,
'token' => $user->token,
'id_token' => $user->id_token
]);

try {
Auth::login($localUser);
}
catch (\Throwable $e) {
return redirect('/login-okta');
}

return redirect('/home');
}
```

Generate the logout url from your controller:

```php
public function logout(\Illuminate\Http\Request $request)
{
$idToken = $request->user()->id_token;
$logoutUrl = Socialite::driver('okta')->getLogoutUrl($idToken, URL::to('/'));
Auth::logout();

return redirect($logoutUrl);
}
```

#### Client Token
To obtain a client access token for authenticating to other apps without a user:

```php
$response = (object) Socialite::driver('okta')->getClientAccessTokenResponse();
$token = $response->access_token;
```
NOTE: no caching of this token is performed. It's strongly suggested caching the token locally for its ttl

### Returned User fields

- ``id``
- ``email``
- ``email_verified``
- ``nickname``
- ``name``
- ``first_name``
- ``last_name``
- ``profileUrl``
- ``address``
- ``phone``
33 changes: 33 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"name": "socialiteproviders/okta",
"description": "Okta OAuth2 Provider for Laravel Socialite",
"keywords": [
"laravel",
"oauth",
"okta",
"provider",
"socialite"
],
"license": "MIT",
"authors": [
{
"name": "Chase Coney",
"email": "[email protected]"
}
],
"require": {
"php": "^7.2 || ^8.0",
"ext-json": "*",
"socialiteproviders/manager": "~4.0"
},
"autoload": {
"psr-4": {
"SocialiteProviders\\Okta\\": ""
}
},
"support": {
"issues": "https://github.com/socialiteproviders/providers/issues",
"source": "https://github.com/socialiteproviders/providers",
"docs": "https://socialiteproviders.com/okta"
}
}

0 comments on commit 7c0b752

Please sign in to comment.