From 3c7ad101fdfd0a3967877c9bca13fe29aa75c767 Mon Sep 17 00:00:00 2001 From: Stefan Winter Date: Tue, 2 Jun 2026 06:46:07 +0200 Subject: [PATCH 1/3] Fix typo in Backchannel Logout logging messages --- src/Server/LogoutHandlers/BackChannelLogoutHandler.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Server/LogoutHandlers/BackChannelLogoutHandler.php b/src/Server/LogoutHandlers/BackChannelLogoutHandler.php index e1fb8478..9a0460e2 100644 --- a/src/Server/LogoutHandlers/BackChannelLogoutHandler.php +++ b/src/Server/LogoutHandlers/BackChannelLogoutHandler.php @@ -39,13 +39,13 @@ public function handle(array $relyingPartyAssociations, ?HandlerStack $handlerSt 'concurrency' => 5, 'fulfilled' => function (Response $response, mixed $index) { // this is delivered each successful response - $successMessage = "Backhannel Logout (index $index) - success, status: {$response->getStatusCode()} " . + $successMessage = "Backchannel Logout (index $index) - success, status: {$response->getStatusCode()} " . "{$response->getReasonPhrase()}"; $this->loggerService->notice($successMessage); }, 'rejected' => function (GuzzleException $reason, mixed $index) { // this is delivered each failed request - $errorMessage = "Backhannel Logout (index $index) - error, reason: {$reason->getCode()} " . + $errorMessage = "Backchannel Logout (index $index) - error, reason: {$reason->getCode()} " . "{$reason->getMessage()}, exception type: " . $reason::class; $this->loggerService->error($errorMessage); }, From 1b4ac123104700e743f8de235705b1a0402f92bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Sat, 20 Jun 2026 12:10:05 +0200 Subject: [PATCH 2/3] Add doc on how to run multiples OPs --- docs/3-oidc-configuration.md | 71 ++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/docs/3-oidc-configuration.md b/docs/3-oidc-configuration.md index 12ad22c7..1222d94d 100644 --- a/docs/3-oidc-configuration.md +++ b/docs/3-oidc-configuration.md @@ -13,6 +13,7 @@ It complements the inline comments in `config/module_oidc.php`. - Attribute translation - Auth Proc filters (OIDC) - Client registration permissions +- Running multiple OPs on one server ## Caching protocol artifacts @@ -218,3 +219,73 @@ $config = [ Users can visit the following link for administration: - [https://example.com/simplesaml/module.php/oidc/clients/](https://example.com/simplesaml/module.php/oidc/clients/) + +## Running multiple OPs on one server + +A single module instance is designed to serve exactly one OpenID Provider +(OP): it has one issuer, one set of signing keys, and one configuration +file (`module_oidc.php`). If you need to run several independent OPs (each +with its own issuer, keys, clients, and scopes) on the same server, do not +try to fit them into one config. Instead, run multiple SimpleSAMLphp +instances side by side and select between them with the +`SIMPLESAMLPHP_CONFIG_DIR` environment variable. + +The idea is to give each OP its own configuration directory (each with its +own `config.php`, `authsources.php`, `module_oidc.php`, signing keys, and +metadata) and to front each one with its own virtual host. SimpleSAMLphp +reads `SIMPLESAMLPHP_CONFIG_DIR` to decide which configuration directory to +load, so each virtual host points at the configuration for its OP: + +```apache +# Virtual host for the first OP + + ServerName op1.example.org + SetEnv SIMPLESAMLPHP_CONFIG_DIR /etc/simplesamlphp/op1/config + # ... remaining SimpleSAMLphp / web root configuration ... + + +# Virtual host for the second OP + + ServerName op2.example.org + SetEnv SIMPLESAMLPHP_CONFIG_DIR /etc/simplesamlphp/op2/config + # ... remaining SimpleSAMLphp / web root configuration ... + +``` + +With nginx + PHP-FPM, set the same variable per server block via +`fastcgi_param SIMPLESAMLPHP_CONFIG_DIR /etc/simplesamlphp/op1/config;` +(or use a separate PHP-FPM pool per OP with `env[SIMPLESAMLPHP_CONFIG_DIR]`). + +In each OP's `module_oidc.php`, set a distinct `issuer` and distinct signing +key/certificate filenames so the OPs do not share identities or keys. + +### Important: isolate the database (or use a table prefix) + +The OIDC module keeps its protocol artifacts — clients, access tokens, +refresh tokens, authorization codes, allowed origins, and user records — in +the database, and these tables have no notion of which OP they belong to. +If two instances point at the same database tables, they will share all of +that state: a client registered on one OP will be visible to the other, and +the admin UIs will operate on the same data. That is almost certainly not +what you want. + +To keep the OPs properly isolated, give each instance separate storage by +configuring its `config.php` to use **either** a separate database **or** a +distinct table prefix: + +```php +// In op1/config/config.php +'database.dsn' => 'mysql:host=localhost;dbname=ssp_oidc_op1', +// ...or share a database but separate the tables with a distinct prefix: +'database.prefix' => 'op1_', +``` + +```php +// In op2/config/config.php +'database.dsn' => 'mysql:host=localhost;dbname=ssp_oidc_op2', +// ...or: +'database.prefix' => 'op2_', +``` + +Run the database schema creation (migrations) for each instance separately, +so each OP gets its own set of tables. From 7b06ea15f26114ca277fa1e9f67f63a776536b27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marko=20Ivan=C4=8Di=C4=87?= Date: Fri, 26 Jun 2026 10:41:01 +0200 Subject: [PATCH 3/3] Bump jwt-framework required version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 6bac59e6..8a91b03b 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,7 @@ "spomky-labs/base64url": "^2.0", "symfony/expression-language": "^7.4", "symfony/psr-http-message-bridge": "^7.4", - "web-token/jwt-framework": "^3", + "web-token/jwt-framework": "^3.4.10", "symfony/cache": "^7.4", "psr/simple-cache": "^3" },