-
Notifications
You must be signed in to change notification settings - Fork 27
Token introspection #331
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
Merged
cicnavi
merged 22 commits into
simplesamlphp:wip-version-7
from
JovanSimonoski:token-introspection
Mar 11, 2026
Merged
Token introspection #331
Changes from 16 commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
9df43c5
added token introspect controller
JovanSimonoski 4c606e7
added token introspect controller
JovanSimonoski e86482b
added token introspection controller (missing jwt check, client auth.)
JovanSimonoski 2e743c2
added client authentication and code refactor/reuse
JovanSimonoski ab9a58b
feat: increase conformance with introspection rfc
PeterBolha cf1e59c
Merge pull request #1 from JovanSimonoski/peter/rfc-conformance
JovanSimonoski 236ed3e
add generate-token script for testing
JovanSimonoski 24eab6c
remove useful-scripts.md
JovanSimonoski eb276be
Add note about cache busting after upgrade
cicnavi fdd38f9
Update upgrade doc
cicnavi 391d700
phpcbf fixes
cicnavi 8442cc8
Merge with wip-vesion-7
cicnavi 467ea97
Merge with wip-version-7
cicnavi 77dd5c5
WIP client authn refactor
cicnavi 461c0bd
Initial access token support
cicnavi 313d691
Support refresh token introspection
cicnavi 121137b
Include introspection endpoint in OAuth2 metadata
cicnavi 72d9054
Upate config-override
cicnavi a5c1e39
Add unit tests
cicnavi 5198f16
Remove additional-tools
cicnavi 7147c1f
Update docs
cicnavi 52ffe31
Update upgrade log
cicnavi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
932 changes: 932 additions & 0 deletions
932
additional-tools/SSP-OIDC-module.postman_collection.json
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| ``` | ||
| cat > /tmp/test.php << 'EOF' | ||
| <?php | ||
| require_once '/var/simplesamlphp/vendor/autoload.php'; | ||
|
|
||
| use Lcobucci\JWT\Configuration; | ||
| use Lcobucci\JWT\Signer\Key\InMemory; | ||
| use Lcobucci\JWT\Signer\Rsa\Sha256; | ||
|
|
||
| // Database setup | ||
| $db = new PDO("sqlite:/var/simplesamlphp/data/mydb.sq3"); | ||
|
|
||
| // Insert user with prepared statement | ||
| $stmt = $db->prepare("INSERT OR IGNORE INTO oidc_user (id, claims) VALUES (?, ?)"); | ||
| $stmt->execute(["test-user-123", '{"sub":"test-user-123","name":"Test User"}']); | ||
|
|
||
| // Get first client | ||
| $client = $db->query("SELECT id FROM oidc_client LIMIT 1")->fetch(PDO::FETCH_ASSOC); | ||
| if (!$client) { | ||
| die("Error: No client found in database. Please create a client first.\n"); | ||
| } | ||
| echo "Using client: " . $client["id"] . "\n"; | ||
|
|
||
| // Generate token ID | ||
| $tokenId = "test-token-" . bin2hex(random_bytes(16)); | ||
| echo "Token ID: " . $tokenId . "\n"; | ||
|
|
||
| // Calculate expiration time | ||
| $now = new DateTimeImmutable(); | ||
| $expiresAt = $now->modify('+1 hour'); | ||
|
|
||
| // Insert access token into database | ||
| $stmt = $db->prepare("INSERT INTO oidc_access_token (id, scopes, expires_at, user_id, client_id, is_revoked) VALUES (?, ?, ?, ?, ?, 0)"); | ||
| $stmt->execute([ | ||
| $tokenId, | ||
| '["openid","profile","email"]', | ||
| $expiresAt->format('Y-m-d H:i:s'), | ||
| "test-user-123", | ||
| $client["id"] | ||
| ]); | ||
|
|
||
| echo "✓ Token stored in database\n"; | ||
|
|
||
| // Read the actual key contents | ||
| $privateKeyContents = file_get_contents('/var/simplesamlphp/cert/oidc_module.key'); | ||
| $publicKeyContents = file_get_contents('/var/simplesamlphp/cert/oidc_module.crt'); | ||
|
|
||
| // Configure JWT | ||
| $config = Configuration::forAsymmetricSigner( | ||
| new Sha256(), | ||
| InMemory::plainText($privateKeyContents), | ||
| InMemory::plainText($publicKeyContents) | ||
| ); | ||
|
|
||
| // Build properly signed JWT with nbf claim | ||
| $token = $config->builder() | ||
| ->issuedBy('https://localhost') | ||
| ->permittedFor('resource-server') | ||
| ->identifiedBy($tokenId) | ||
| ->issuedAt($now) | ||
| ->canOnlyBeUsedAfter($now) // ← ADD THIS: Sets the nbf (Not Before) claim | ||
| ->expiresAt($expiresAt) | ||
| ->relatedTo('test-user-123') | ||
| ->withClaim('scopes', ['openid', 'profile', 'email']) | ||
| ->withClaim('client_id', $client["id"]) | ||
| ->getToken($config->signer(), $config->signingKey()); | ||
|
|
||
| $jwt = $token->toString(); | ||
|
|
||
| // Verify the token can be parsed and validated | ||
| try { | ||
| $parsedToken = $config->parser()->parse($jwt); | ||
| $config->validator()->assert($parsedToken, ...$config->validationConstraints()); | ||
| echo "✓ Token signature validated successfully!\n"; | ||
| } catch (\Exception $e) { | ||
| echo "✗ Validation failed: " . $e->getMessage() . "\n"; | ||
| } | ||
|
|
||
| // Output the JWT | ||
| echo "\n" . str_repeat("=", 80) . "\n"; | ||
| echo "Generated JWT:\n"; | ||
| echo str_repeat("=", 80) . "\n"; | ||
| echo $jwt . "\n"; | ||
| echo str_repeat("=", 80) . "\n"; | ||
|
|
||
| // Provide test command | ||
| echo "\nTest with curl:\n"; | ||
| echo "curl -X POST \"https://localhost/simplesaml/module.php/oidc/introspect\" \\\n"; | ||
| echo " -H \"Content-Type: application/x-www-form-urlencoded\" \\\n"; | ||
| echo " -H \"Authorization: Bearer test\" \\\n"; | ||
| echo " -d \"token=$jwt\" \\\n"; | ||
| echo " -k\n"; | ||
|
|
||
| // Also show decoded token for debugging | ||
| echo "\n" . str_repeat("=", 80) . "\n"; | ||
| echo "Decoded Token Payload:\n"; | ||
| echo str_repeat("=", 80) . "\n"; | ||
| $parts = explode('.', $jwt); | ||
| $payload = json_decode(base64_decode(strtr($parts[1], '-_', '+/')), true); | ||
| echo json_encode($payload, JSON_PRETTY_PRINT) . "\n"; | ||
| EOF | ||
|
|
||
|
|
||
| php /tmp/test.php | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -14,4 +14,5 @@ | |
| 'language.i18n.backend' => 'gettext/gettext', | ||
| 'logging.level' => 7, | ||
| 'usenewui' => false, | ||
|
|
||
| ] + $config; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| <?php | ||
|
|
||
| declare(strict_types=1); | ||
|
|
||
| namespace SimpleSAML\Module\oidc\Bridges; | ||
|
|
||
| use Defuse\Crypto\Crypto; | ||
| use Defuse\Crypto\Key; | ||
| use SimpleSAML\Module\oidc\Exceptions\OidcException; | ||
| use SimpleSAML\Module\oidc\ModuleConfig; | ||
|
|
||
| class OAuth2Bridge | ||
| { | ||
| public function __construct( | ||
| protected readonly ModuleConfig $moduleConfig, | ||
| ) { | ||
| } | ||
|
|
||
| /** | ||
| * Bridge `encrypt` function, which can be used instead of | ||
| * \League\OAuth2\Server\CryptTrait::encrypt() | ||
| * | ||
| * @param string $unencryptedData | ||
| * @param Key|string $encryptionKey | ||
| * @return string | ||
| * @throws OidcException | ||
| */ | ||
| public function encrypt( | ||
| string $unencryptedData, | ||
| null|Key|string $encryptionKey = null, | ||
| ): string { | ||
| $encryptionKey ??= $this->moduleConfig->getEncryptionKey(); | ||
|
|
||
| try { | ||
| return $encryptionKey instanceof Key ? | ||
| Crypto::encrypt($unencryptedData, $encryptionKey) : | ||
| Crypto::encryptWithPassword($unencryptedData, $encryptionKey); | ||
| } catch (\Exception $e) { | ||
| throw new OidcException('Error enrypting data: ' . $e->getMessage(), (int)$e->getCode(), $e); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Bridge `decrypt` function, which can be used instead of | ||
| * \League\OAuth2\Server\CryptTrait::decrypt() | ||
| * | ||
| * @param string $encryptedData | ||
| * @param Key|string $encryptionKey | ||
| * @return string | ||
| * @throws OidcException | ||
| */ | ||
| public function decrypt( | ||
| string $encryptedData, | ||
| null|Key|string $encryptionKey = null, | ||
| ): string { | ||
| $encryptionKey ??= $this->moduleConfig->getEncryptionKey(); | ||
|
|
||
| try { | ||
| return $encryptionKey instanceof Key ? | ||
| Crypto::decrypt($encryptedData, $encryptionKey) : | ||
| Crypto::decryptWithPassword($encryptedData, $encryptionKey); | ||
| } catch (\Exception $e) { | ||
| throw new OidcException('Error decrypting data: ' . $e->getMessage(), (int)$e->getCode(), $e); | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.