diff --git a/docs/token_exchange.md b/docs/token_exchange.md index 4248a3c4..843105f3 100644 --- a/docs/token_exchange.md +++ b/docs/token_exchange.md @@ -31,6 +31,11 @@ if (class_exists('OCA\UserOIDC\Event\ExchangedTokenRequestedEvent')) { $this->eventDispatcher->dispatchTyped($event); } catch (OCA\UserOIDC\Exception\TokenExchangeFailedException $e) { $this->logger->debug('Failed to exchange token: ' . $e->getMessage()); + $error = $e->getError(); + $errorDescription = $e->getErrorDescription(); + if ($error && $errorDescription) { + $this->logger->debug('Token exchange error response from the IdP: ' . $error . ' (' . $errorDescription . ')'); + } } $token = $event->getToken(); if ($token === null) { diff --git a/lib/Exception/TokenExchangeFailedException.php b/lib/Exception/TokenExchangeFailedException.php index 4d08bba4..e1d0b034 100644 --- a/lib/Exception/TokenExchangeFailedException.php +++ b/lib/Exception/TokenExchangeFailedException.php @@ -11,4 +11,22 @@ use Exception; class TokenExchangeFailedException extends Exception { + + public function __construct( + $message = '', + $code = 0, + $previous = null, + private ?string $error = null, + private ?string $errorDescription = null, + ) { + parent::__construct($message, $code, $previous); + } + + public function getError(): ?string { + return $this->error; + } + + public function getErrorDescription(): ?string { + return $this->errorDescription; + } } diff --git a/lib/Service/TokenService.php b/lib/Service/TokenService.php index 803056d8..de886531 100644 --- a/lib/Service/TokenService.php +++ b/lib/Service/TokenService.php @@ -8,6 +8,8 @@ namespace OCA\UserOIDC\Service; +use GuzzleHttp\Exception\ClientException; +use GuzzleHttp\Exception\ServerException; use OCA\UserOIDC\AppInfo\Application; use OCA\UserOIDC\Db\ProviderMapper; use OCA\UserOIDC\Exception\TokenExchangeFailedException; @@ -268,6 +270,27 @@ public function getExchangedToken(string $targetAudience): Token { ['provider_id' => $loginToken->getProviderId()], ); return new Token($tokenData); + } catch (ClientException|ServerException $e) { + $response = $e->getResponse(); + $body = (string)$response->getBody(); + $this->logger->error('[TokenService] Failed to exchange token, client/server error in the exchange request', ['response_body' => $body, 'exception' => $e]); + + $parsedBody = json_decode(trim($body), true); + if (is_array($parsedBody) && isset($parsedBody['error'], $parsedBody['error_description'])) { + throw new TokenExchangeFailedException( + 'Failed to exchange token, client/server error in the exchange request: ' . $body, + 0, + $e, + $parsedBody['error'], + $parsedBody['error_description'], + ); + } else { + throw new TokenExchangeFailedException( + 'Failed to exchange token, client/server error in the exchange request: ' . $body, + 0, + $e, + ); + } } catch (\Exception|\Throwable $e) { $this->logger->error('[TokenService] Failed to exchange token ', ['exception' => $e]); throw new TokenExchangeFailedException('Failed to exchange token, error in the exchange request', 0, $e);