passbolt/passbolt_api · error · InternalErrorException

Client ID should be a valid UUID.

Error message

Client ID should be a valid UUID.

What it means

Thrown by SmtpOauthExchangeOnlineService::assertConfiguration (invoked from the constructor) when the `client_id` in the SMTP OAuth2 configuration for Microsoft Exchange Online is not a valid UUID. This is the Azure AD Application (client) ID and must be a GUID.

Solutions

  1. Copy the Application (client) ID GUID from Azure Portal > App registrations > your app's Overview page.
  2. Re-save the SMTP OAuth settings via the API so validation runs on write.
  3. Double-check you did not paste the client secret or tenant ID into the client_id field (both have distinct formats/uses).

Example fix

// before
'client_id' => 'my-exchange-relay-app'

// after
'client_id' => '0f8a4c9e-1d2b-4e3f-9a8b-7c6d5e4f3a2b'
Defensive patterns

Strategy: validation

Validate before calling

use Cake\Validation\Validation;
if (!Validation::uuid($config['client_id'] ?? '')) {
    throw new InvalidArgumentException('client_id must be a UUID');
}

Type guard

function isClientIdValid(mixed $clientId): bool {
    return is_string($clientId) && Cake\Validation\Validation::uuid($clientId);
}

Try / catch

try {
    $service = new SmtpOauthExchangeOnlineService($config);
} catch (InternalErrorException $e) {
    // config error: client_id is not a UUID
}

Prevention

When it happens

Trigger: Constructing SmtpOauthExchangeOnlineService with smtpSettings OAuth config whose client_id is empty, a client secret pasted by mistake, or the application name instead of the Application (client) ID GUID.

Common situations: Copy/paste mistakes in Azure Portal (app name or secret instead of client ID); settings saved with blank client_id; manual DB edits.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of passbolt/passbolt_api@31c1bbc10f (2026-09-17). Data as JSON: /api/errors/16418b3483b85421. Report an issue: GitHub.

Appendix: source

Thrown at plugins/PassboltCe/SmtpSettings/src/Service/SmtpOauthExchangeOnlineService.php:98

        $this->username = $config['oauth_username'];
        // default timeout is 30 (same) but added here for more visibility
        $this->httpClient = $httpClient ?? new Client(['timeout' => 30]);
    }

    /**
     * Add basic data validation check to reduce SSRF risk.
     * We are not using form class as it can create overhead in this scenario.
     *
     * @param array $config Configuration to check.
     * @return void
     */
    private function assertConfiguration(array $config): void
    {
        if (!Validation::uuid($config['tenant_id'])) {
            throw new InternalErrorException(__('Tenant ID should be a valid UUID.'));
        }
        if (!Validation::uuid($config['client_id'])) {
            throw new InternalErrorException(__('Client ID should be a valid UUID.'));
        }
    }

    /**
     * Fetch an OAuth2 access token from Microsoft using client credentials grant.
     *
     * @return string The access token.
     * @throws \Cake\Http\Exception\InternalErrorException If the token request fails.
     * @see https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-client-creds-grant-flow#get-a-token
     */
    public function getAccessToken(): string
    {
        $tokenUrl = str_replace('__TENANT_ID__', $this->tenantId, self::LOGIN_TOKEN_URL);

        $response = $this->httpClient->post($tokenUrl, [
            'grant_type' => 'client_credentials',
            'client_id' => $this->clientId,
            'client_secret' => $this->clientSecret,

View on GitHub (pinned to 31c1bbc10f)