{"record":{"id":"886213b93611fe47","repo":"passbolt/passbolt_api","slug":"tenant-id-should-be-a-valid-uuid","errorCode":null,"errorMessage":"Tenant ID should be a valid UUID.","messagePattern":"Tenant ID should be a valid UUID\\.","errorType":"exception","errorClass":"InternalErrorException","httpStatus":500,"severity":"error","filePath":"plugins/PassboltCe/SmtpSettings/src/Service/SmtpOauthExchangeOnlineService.php","lineNumber":95,"sourceCode":"        $this->tenantId = $config['tenant_id'];\n        $this->clientId = $config['client_id'];\n        $this->clientSecret = $config['client_secret'];\n        $this->username = $config['oauth_username'];\n        // default timeout is 30 (same) but added here for more visibility\n        $this->httpClient = $httpClient ?? new Client(['timeout' => 30]);\n    }\n\n    /**\n     * Add basic data validation check to reduce SSRF risk.\n     * We are not using form class as it can create overhead in this scenario.\n     *\n     * @param array $config Configuration to check.\n     * @return void\n     */\n    private function assertConfiguration(array $config): void\n    {\n        if (!Validation::uuid($config['tenant_id'])) {\n            throw new InternalErrorException(__('Tenant ID should be a valid UUID.'));\n        }\n        if (!Validation::uuid($config['client_id'])) {\n            throw new InternalErrorException(__('Client ID should be a valid UUID.'));\n        }\n    }\n\n    /**\n     * Fetch an OAuth2 access token from Microsoft using client credentials grant.\n     *\n     * @return string The access token.\n     * @throws \\Cake\\Http\\Exception\\InternalErrorException If the token request fails.\n     * @see https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-client-creds-grant-flow#get-a-token\n     */\n    public function getAccessToken(): string\n    {\n        $tokenUrl = str_replace('__TENANT_ID__', $this->tenantId, self::LOGIN_TOKEN_URL);\n\n        $response = $this->httpClient->post($tokenUrl, [","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/passbolt/passbolt_api/blob/31c1bbc10f32808a607fa9bd81891e898779c0bc/plugins/PassboltCe/SmtpSettings/src/Service/SmtpOauthExchangeOnlineService.php#L77-L113","documentation":"Thrown by SmtpOauthExchangeOnlineService::assertConfiguration (invoked from the constructor) when the `tenant_id` in the SMTP OAuth2 configuration for Microsoft Exchange Online is not a valid UUID. Since the service validates config at construction time, any use of the service with bad config fails immediately with a 500 InternalError.","triggerScenarios":"Constructing SmtpOauthExchangeOnlineService with smtpSettings OAuth config whose tenant_id is empty, a GUID with wrong format, a domain name (e.g. contoso.onmicrosoft.com), or arbitrary text instead of the Azure AD Directory (tenant) ID GUID.","commonSituations":"Admins copied the tenant domain instead of the Directory ID from Azure Portal; OAuth settings saved before the tenant_id field was filled; manual DB edits to smtp_settings OAuth payload.","solutions":["Copy the correct Directory (tenant) ID GUID from Azure Portal > Microsoft Entra ID > Overview into the SMTP settings.","Re-save the SMTP OAuth settings via the SMTP settings API so validation runs on write.","Verify the stored config value is a UUID: 8-4-4-4-12 hex format."],"exampleFix":"// before\n'tenant_id' => 'contoso.onmicrosoft.com'\n\n// after\n'tenant_id' => 'b4e1a1c2-9f3e-4a7d-8c5b-2f6d0e1a9b3c'","handlingStrategy":"validation","validationCode":"use Cake\\Validation\\Validation;\nif (!Validation::uuid($config['tenant_id'] ?? '')) {\n    throw new InvalidArgumentException('tenant_id must be a UUID');\n}","typeGuard":"function isTenantIdValid(mixed $tenantId): bool {\n    return is_string($tenantId) && Cake\\Validation\\Validation::uuid($tenantId);\n}","tryCatchPattern":"try {\n    $service = new SmtpOauthExchangeOnlineService($config);\n} catch (InternalErrorException $e) {\n    // surface a config error: tenant_id/client_id is not a UUID\n}","preventionTips":["Copy the Directory (tenant) ID GUID, not the tenant domain, from Azure Portal.","Validate UUID format before saving OAuth SMTP settings via the API.","Never insert OAuth config directly into the database.","Keep a checklist when setting up Exchange OAuth (tenant id, client id, secret, consent)."],"tags":["oauth","azure","smtp","uuid","configuration"],"backgroundTag":"invalid-identifier-format","analyzedSha":"31c1bbc10f32808a607fa9bd81891e898779c0bc","analyzedAt":"2026-09-17T00:04:38.960Z","contentChangedAt":"2026-09-17T00:04:38.960Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}