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

feat(SDK-4732): Implement support for Back-Channel Logout #435

Merged
merged 3 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@
"source": "https://github.com/auth0/laravel-auth0"
},
"require": {
"php": "^8.0",
"php": "^8.1",
"ext-json": "*",
"auth0/auth0-php": "^8.7",
"auth0/auth0-php": "^8.10",
"illuminate/contracts": "^9 || ^10",
"illuminate/http": "^9 || ^10",
"illuminate/support": "^9 || ^10",
Expand Down
2 changes: 2 additions & 0 deletions config/auth0.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
Configuration::CONFIG_CLIENT_ASSERTION_SIGNING_KEY => Configuration::get(Configuration::CONFIG_CLIENT_ASSERTION_SIGNING_KEY),
Configuration::CONFIG_CLIENT_ASSERTION_SIGNING_ALGORITHM => Configuration::get(Configuration::CONFIG_CLIENT_ASSERTION_SIGNING_ALGORITHM),
Configuration::CONFIG_PUSHED_AUTHORIZATION_REQUEST => Configuration::get(Configuration::CONFIG_PUSHED_AUTHORIZATION_REQUEST),
Configuration::CONFIG_BACKCHANNEL_LOGOUT_CACHE => Configuration::get(Configuration::CONFIG_BACKCHANNEL_LOGOUT_CACHE),
Configuration::CONFIG_BACKCHANNEL_LOGOUT_EXPIRES => Configuration::get(Configuration::CONFIG_BACKCHANNEL_LOGOUT_EXPIRES),
],

'api' => [
Expand Down
17 changes: 17 additions & 0 deletions docs/BackchannelLogout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Backchannel Logout

The Auth0 Laravel SDK supports [Backchannel Logout](https://auth0.com/docs/authenticate/login/logout/back-channel-logout) from v7.12 onward. To use this feature, some additional configuration is necessary:

1. **Add a new route to your application.** This route must be publicly accessible. Auth0 will use it to send backchannel logout requests to your application. For example:

```php
Route::post('/backchannel', function (Request $request) {
if ($request->has('logout_token')) {
app('auth0')->handleBackchannelLogout($request->string('logout_token', '')->trim());
}
});
```

2. **Configure your Auth0 tenant to use Backchannel Logout.** See the [Auth0 documentation](https://auth0.com/docs/authenticate/login/logout/back-channel-logout/configure-back-channel-logout) for more information on how to do this. Please ensure you point the Logout URI to the backchannel route we just added to your application.

Note: If your application's configuration assigns `false` to the `backchannelLogoutCache` SDK configuration property, this feature will be disabled entirely.
2 changes: 2 additions & 0 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ The following environment variables are supported, but should not be adjusted un
| `AUTH0_CLIENT_ASSERTION_SIGNING_KEY` | `String` The key to use for signing client assertions. |
| `AUTH0_CLIENT_ASSERTION_SIGNING_ALGORITHM` | `String` The algorithm to use for signing client assertions. Defaults to `RS256`. |
| `AUTH0_PUSHED_AUTHORIZATION_REQUEST` | `Boolean` Whether the SDK should use Pushed Authorization Requests during authentication. Note that your tenant must have this feature enabled. Defaults to `false`. |
| `AUTH0_BACKCHANNEL_LOGOUT_CACHE` | `String (class name)` A PSR-6 class to use for caching backchannel logout tokens. |
| `AUTH0_BACKCHANNEL_LOGOUT_EXPIRES` | `Integer` How long (in seconds) to cache a backchannel logout token. Defaults to `2592000` (30 days). |

### Order of Priority

Expand Down
11 changes: 11 additions & 0 deletions src/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,24 @@ final class Configuration implements ConfigurationContract
self::CONFIG_TOKEN_CACHE_TTL,
self::CONFIG_HTTP_MAX_RETRIES,
self::CONFIG_COOKIE_EXPIRES,
self::CONFIG_BACKCHANNEL_LOGOUT_EXPIRES,
];

/**
* @var string
*/
public const CONFIG_AUDIENCE = 'audience';

/**
* @var string
*/
public const CONFIG_BACKCHANNEL_LOGOUT_CACHE = 'backchannelLogoutCache';

/**
* @var string
*/
public const CONFIG_BACKCHANNEL_LOGOUT_EXPIRES = 'backchannelLogoutExpires';

/**
* @var string
*/
Expand Down
33 changes: 33 additions & 0 deletions src/Entities/InstanceEntityAbstract.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public function __construct(
protected ?CacheItemPoolInterface $tokenCachePool = null,
protected ?CacheItemPoolInterface $managementTokenCachePool = null,
protected ?string $guardConfigurationKey = null,
protected ?CacheItemPoolInterface $backchannelLogoutCachePool = null,
) {
}

Expand Down Expand Up @@ -119,6 +120,29 @@ abstract public function setConfiguration(
SdkConfiguration | array | null $configuration = null,
): self;

protected function bootBackchannelLogoutCache(array $config): array
{
$backchannelLogoutCache = $config['backchannelLogoutCache'] ?? null;

if (false === $backchannelLogoutCache) {
unset($config['backchannelLogoutCache']);

return $config;
}

if (null === $backchannelLogoutCache) {
$backchannelLogoutCache = $this->getBackchannelLogoutCachePool();
}

if (is_string($backchannelLogoutCache)) {
$backchannelLogoutCache = app(trim($backchannelLogoutCache));
}

$config['backchannelLogoutCache'] = $backchannelLogoutCache instanceof CacheItemPoolInterface ? $backchannelLogoutCache : null;

return $config;
}

protected function bootManagementTokenCache(array $config): array
{
$managementTokenCache = $config['managementTokenCache'] ?? null;
Expand Down Expand Up @@ -256,6 +280,15 @@ protected function createConfiguration(
return $sdkConfiguration;
}

protected function getBackchannelLogoutCachePool(): CacheItemPoolInterface
{
if (! $this->backchannelLogoutCachePool instanceof CacheItemPoolInterface) {
$this->backchannelLogoutCachePool = app(CacheBridge::class);
}

return $this->backchannelLogoutCachePool;
}

protected function getManagementTokenCachePool(): CacheItemPoolInterface
{
if (! $this->managementTokenCachePool instanceof CacheItemPoolInterface) {
Expand Down
23 changes: 23 additions & 0 deletions tests/Unit/ServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,29 @@
->tokenCache->toBeInstanceOf(CacheItemPoolInterface::class);
});

test('bootBackchannelLogoutCache() behaves as expected', function (): void {
$method = new ReflectionMethod(Service::class, 'bootBackchannelLogoutCache');
$method->setAccessible(true);

expect($method->invoke($this->laravel, []))
->backchannelLogoutCache->toBeInstanceOf(CacheBridgeContract::class);

expect($method->invoke($this->laravel, ['backchannelLogoutCache' => null]))
->backchannelLogoutCache->toBeInstanceOf(CacheBridgeContract::class);

expect($method->invoke($this->laravel, ['backchannelLogoutCache' => CacheBridge::class]))
->backchannelLogoutCache->toBeInstanceOf(CacheBridgeContract::class);

expect($method->invoke($this->laravel, ['backchannelLogoutCache' => false]))
->backchannelLogoutCache->toBeNull();

expect($method->invoke($this->laravel, ['backchannelLogoutCache' => MemoryStore::class]))
->backchannelLogoutCache->toBeNull();

expect($method->invoke($this->laravel, ['backchannelLogoutCache' => 'cache.psr6']))
->backchannelLogoutCache->toBeInstanceOf(CacheItemPoolInterface::class);
});

// test('bootManagementTokenCache() behaves as expected', function (): void {
// $method = new ReflectionMethod(Service::class, 'bootManagementTokenCache');
// $method->setAccessible(true);
Expand Down