I'm a little bit out of my comfort zone. I'm trying to create a SOAP request with PHP, and I'm using the famous API of KBO, here's the documentation:
So essentially everything went well, but I'm still struggling with something about the authentication, which makes me fail my entire small framework:
<?php
$endpoint = 'https://kbopub-acc.economie.fgov.be/kbopubws110000/services/wsKBOPub';
$wsdl = 'https://kbopub-acc.economie.fgov.be/kbopubws110000/services/wsKBOPub?wsdl';
$username = 'myusername';
$password = 'mypassword';
$timestamp = gmdate('Y-m-d\TH:i:s\Z');
$nonce = base64_encode(random_bytes(16));
$passwordDigest = base64_encode(sha1($nonce . $timestamp . $password, true));
$header = '
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
<wsse:Username>' . $username . '</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">' . $passwordDigest . '</wsse:Password>
<wsse:Nonce>' . $nonce . '</wsse:Nonce>
<wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">' . $timestamp . '</wsu:Created>
</wsse:UsernameToken>
</wsse:Security>';
$options = array(
'soap_version' => SOAP_1_1,
'trace' => true,
'exceptions' => true,
'encoding' => 'UTF-8',
'cache_wsdl' => WSDL_CACHE_NONE,
'stream_context' => stream_context_create(array(
'http' => array(
'header' => 'Authorization: WSSE profile=' . $header,
'user_agent' => 'PHPSoapClient'
),
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false
)
))
);
$context = stream_context_create(array(
'ssl' => array(
'verify_peer' => false,
'verify_peer_name' => false,
),
));
$options['stream_context'] = $context;
// $options = array(
// 'soap_version' => SOAP_1_1
// );
$client = new SoapClient($wsdl, $options);
// Set up the request parameters
$enterpriseNumber = '0810.002.854';
$request = array('EnterpriseNumber' => $enterpriseNumber);
// Call the SOAP operation with the request parameters
$response = $client->__soapCall('ReadEnterprise', array($request));
// Get the request and response XML
$requestXML = $client->__getLastRequest();
$responseXML = $client->__getLastResponse();
var_dump($response);
I also followed some suggestions from my PHP log file, where it was written to use a different version of the soap version: SOAP_1_1 instead of the SOAP_1_2.
What I find really challenging is the fact that I can't debug it in any way; I have no idea on how I can check the error message, or I can't have any hint in my error log file, it simply mentions the security check, but nothing much.
Has anyone had the same issue?
By the way, the error that I have encountered is the following:
[14-Feb-2023 17:09:24 UTC] PHP Fatal error: Uncaught SoapFault exception: [ns1:SecurityError] A security error was encountered when verifying the message in Stack trace: #0 /Users/mymac/Sites/cboxform/api-call/index.php(55): SoapClient->__soapCall('ReadEnterprise', Array) #1 {main} thrown in /Users/mymac/Sites/cboxform/api-call/index.php on line 55
TLTR:
To summarize, I would need a request that looks like:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:mes="http://economie.fgov.be/kbopub/webservices/v1/messages" xmlns:dat="http://economie.fgov.be/kbopub/webservices/v1/datamodel">
<soapenv:Header>
<mes:RequestContext>
<mes:Id>myid</mes:Id>
<mes:Language>fr</mes:Language>
</mes:RequestContext>
</soapenv:Header>
<soapenv:Body>
<mes:ReadEnterpriseRequest>
<dat:EnterpriseNumber>0206231995</dat:EnterpriseNumber>
</mes:ReadEnterpriseRequest>
</soapenv:Body>
</soapenv:Envelope>
with a header with a digest password, with timestamp and nonce that will expire in 300 seconds to this endpoint:
https://kbopub-acc.economie.fgov.be/kbopubws110000/services/wsKBOPub?wsdl
with also a username.

It looks like an issue with the security token that you're using to authenticate your SOAP request. Please check
timezoneformat as UTC(YYYY-MM-DDTHH:MM:SSZ),Nonceshould be a random value that is generated for each request, andPasswordDigestvalue is calculated correctly,PasswordDigest(SHA-1 hash) and concatenated values forNonce, Createdtimestamp,passwordin binary format.Also you can try to print out the values of the
timestamp,nonce, andpasswordDigestfor easy to debuggingCan you try replace at line 20 within below code:
WSSE header to use the correct profile value within space after it