Closed Dekari closed 3 years ago
@Dekari i have been in the same process and here are some interesting links that helped figure things out.
Hello @Dekari,
We are currently working on a proper documentation regarding 3DSV2. I will keep you updated.
Have a nice day,
Hello any updates ? I'm currently looking to integrate 3DS2 in my PHP website and honestly I'm a bit lost... Isn't possible to add integration exemple in the demo workflow ? Even in the test case there is nothing about BrowserInfo and the IP adress is filled with static value Thanks in advance
Hey after few try this afternoon, I finally managed to integrate the 3DS2 on PayIn direct !
For the ipAddress I just retrive it with a function on serverside :
public function getIpAddress(){
//whether ip is from the share internet
if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
$ip = $_SERVER['HTTP_CLIENT_IP'];
}
//whether ip is from the proxy
elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
}
//whether ip is from the remote address
else {
$ip = $_SERVER['REMOTE_ADDR'];
}
return $ip;
}
For the BrowserInfo, I'm not sure if it's a good/best option but I did a JS script, on my paiement page, who send needed data to a PHP function who save these data in $_SESSION (I use getallheaders() in PHP for User-Agent and Accept Header).
Js script :
$.ajax({
type: "POST",
url: "/sendBrowserInfo",
data: {
JavaEnabled: navigator.javaEnabled(),
Language: navigator.language || navigator.userLanguage,
ColorDepth: screen.colorDepth,
ScreenHeight: screen.height,
ScreenWidth: screen.width,
TimeZoneOffset: new Date().getTimezoneOffset().toString()
},
});
Php who save in session :
public function sendBrowserInfo(){
if(!empty($_POST)){
foreach($_POST as $key => $value){
$_SESSION[$key] = $value;
}
}
}
Final function who get all BrowserInfo :
public function getBrowserInfo(){
$headers = getallheaders();
$result = new BrowserInfo();
$result->AcceptHeader = $headers['Accept'];
$result->JavaEnabled = $_SESSION['JavaEnabled'];
$result->Language = $_SESSION['Language'];
$result->ColorDepth = $_SESSION['ColorDepth'];
$result->ScreenHeight = $_SESSION['ScreenHeight'];
$result->ScreenWidth = $_SESSION['ScreenWidth'];
$result->TimeZoneOffset = $_SESSION['TimeZoneOffset'];
$result->UserAgent = getallheaders()['User-Agent'];
$result->JavascriptEnabled = true;
return $result;
}
So for PayIn Direct it's work perfectly.
But I have a problem with PreAuth... Indeed, when I make a PreAuth with 3DS2 frictionless (card 4970105191923460) flow the PreAuth response is succeed but $PreAuth->SecureModeNeeded
is true
and $PreAuth->SecureModeRedirectURL
is NULL
so my function fail because I can't redirect to 3DS page ( I don't know if it's a sandbox problem or a inplementation problem). There is no problem with the challenge flow.
Here is my code :
$CardPreAuthorization = new CardPreAuthorization();
$CardPreAuthorization->AuthorId = $authorId;
$CardPreAuthorization->DebitedFunds = new Money();
$CardPreAuthorization->DebitedFunds->Currency = "EUR";
$CardPreAuthorization->DebitedFunds->Amount = $amount * 100;
$CardPreAuthorization->CardId = $resultCardRegistration->CardId;
$CardPreAuthorization->SecureModeReturnURL = getenv('BASE_URL')."/confirm.php";
$CardPreAuthorization->Culture = "FR";
$CardPreAuthorization->Requested3DSVersion = "V2_1";
$CardPreAuthorization->SecureMode = "NO_CHOICE";
$CardPreAuthorization->IpAddress = $author->getIpAddress();
$CardPreAuthorization->BrowserInfo = $author->getBrowserInfo();
$ResultPreAuth = $this->apiMangopay->CardPreAuthorizations->Create($CardPreAuthorization);
Here the result :
object(MangoPay\CardPreAuthorization)#312 (29) {
["AuthorId"]=>
string(9) "XXXXXX"
["DebitedFunds"]=>
object(MangoPay\Money)#344 (2) {
["Currency"]=>
string(3) "EUR"
["Amount"]=>
int(1000)
}
["Status"]=>
string(9) "SUCCEEDED"
["PaymentStatus"]=>
string(7) "WAITING"
["ResultCode"]=>
string(6) "000000"
["ResultMessage"]=>
string(7) "Success"
["StatementDescriptor"]=>
NULL
["ExecutionType"]=>
string(6) "DIRECT"
["SecureMode"]=>
string(9) "NO_CHOICE"
["CardId"]=>
string(9) "XXXXXX"
["SecureModeNeeded"]=>
bool(true)
["SecureModeRedirectURL"]=>
NULL
["SecureModeReturnURL"]=>
string(76) "http://localhost:8888/confirm.php?preAuthorizationId=XXXX"
["ExpirationDate"]=>
int(1622173491)
["AuthorizationDate"]=>
int(1621611891)
["PaymentType"]=>
string(4) "CARD"
["PayInId"]=>
NULL
["SecurityInfo"]=>
object(MangoPay\SecurityInfo)#351 (1) {
["AVSResult"]=>
string(8) "NO_CHECK"
}
["MultiCapture"]=>
bool(false)
["RemainingFunds"]=>
object(MangoPay\Money)#343 (2) {
["Currency"]=>
string(3) "EUR"
["Amount"]=>
int(1000)
}
["IpAddress"]=>
string(3) "::1"
["BrowserInfo"]=>
object(stdClass)#294 (9) {
["AcceptHeader"]=>
string(135) "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
["JavaEnabled"]=>
bool(false)
["Language"]=>
string(5) "fr-FR"
["ColorDepth"]=>
int(24)
["ScreenHeight"]=>
int(900)
["ScreenWidth"]=>
int(1440)
["TimeZoneOffset"]=>
int(-120)
["UserAgent"]=>
string(121) "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36"
["JavascriptEnabled"]=>
bool(true)
}
["Requested3DSVersion"]=>
string(4) "V2_1"
["Applied3DSVersion"]=>
string(4) "V2_1"
["Id"]=>
string(9) "XXXX"
["CreationDate"]=>
int(1621611889)
}
And the last problem I face, once again I'm not sure if it's normal or not but now with the 3DS2 active all payement even under 30€ need a card with 3DS activated. If I try with the card listed for payement under 50€, it's always fail. This will be the same on production ? Because I found this very sad :(
I hope I can help someone and I also hope someone can help me 🤣
PS : sorry for the english fault, isn't my mother tongue and I try too reduce my use of Google translate to improve myself 😉
Hi @launay12u,
I'm implementing 3DS2 too and I made pretty much the same implementation as you did.
It seems the mangopay php sdk and its documentation are both really outdated.
About PayIn direct, did you added BrowserInfo in $payIn->BrowserInfo
or in $payIn->ExecutionDetails->BrowserInfo
?
Hey @Asenar !
For the Payin I added in $payIn->ExecutionDetails->BrowserInfo
😄 I did this because in PayInPaymentDetailsCard.php
in mangopay libraries there is a BrowserInfo
attribut
Hello @launay12u and @Asenar,
@Asenar We are currently working on improving our documentation. We are open to any suggestion. Don't hesitate to reach me.
@launay12u Thank you for taking the time to share your example with the community.
You can contact me anytime here
Thanks you @launay12u ! I found that field a few minutes after posting this !
@fredericdelordm I think I will don't have time before a couple of weeks but I will keep that in mind !
About the field Requested3DSVersion
, it's mentioned this is valid only in «sandbox». Does that mean this option can be safely defined in production and will have no impact ?
The first thing I think related to 3DS2 is to update workflows and code samples described on the demo page
An other thing that makes difficult the uses of the php-sdk is that some properties are missing but mandatory, and other have wrong php-doc comments (making false warnings from phpstan analysis for example). I don't remember which field is indicated as a object type, but is in fact a string.
Hello @Asenar,
About the field Requested3DSVersion, it's mentioned this is valid only in «sandbox». Does that mean this option can be safely defined in production and will have no impact ?
I confirm, no impact on production.
Hey after few try this afternoon, I finally managed to integrate the 3DS2 on PayIn direct !
For the ipAddress I just retrive it with a function on serverside :
public function getIpAddress(){ //whether ip is from the share internet if (!empty($_SERVER['HTTP_CLIENT_IP'])) { $ip = $_SERVER['HTTP_CLIENT_IP']; } //whether ip is from the proxy elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; } //whether ip is from the remote address else { $ip = $_SERVER['REMOTE_ADDR']; } return $ip; }
For the BrowserInfo, I'm not sure if it's a good/best option but I did a JS script, on my paiement page, who send needed data to a PHP function who save these data in $_SESSION (I use getallheaders() in PHP for User-Agent and Accept Header).
Js script :
$.ajax({ type: "POST", url: "/sendBrowserInfo", data: { JavaEnabled: navigator.javaEnabled(), Language: navigator.language || navigator.userLanguage, ColorDepth: screen.colorDepth, ScreenHeight: screen.height, ScreenWidth: screen.width, TimeZoneOffset: new Date().getTimezoneOffset().toString() }, });
Php who save in session :
public function sendBrowserInfo(){ if(!empty($_POST)){ foreach($_POST as $key => $value){ $_SESSION[$key] = $value; } } }
Final function who get all BrowserInfo :
public function getBrowserInfo(){ $headers = getallheaders(); $result = new BrowserInfo(); $result->AcceptHeader = $headers['Accept']; $result->JavaEnabled = $_SESSION['JavaEnabled']; $result->Language = $_SESSION['Language']; $result->ColorDepth = $_SESSION['ColorDepth']; $result->ScreenHeight = $_SESSION['ScreenHeight']; $result->ScreenWidth = $_SESSION['ScreenWidth']; $result->TimeZoneOffset = $_SESSION['TimeZoneOffset']; $result->UserAgent = getallheaders()['User-Agent']; $result->JavascriptEnabled = true; return $result; }
So for PayIn Direct it's work perfectly.
But I have a problem with PreAuth... Indeed, when I make a PreAuth with 3DS2 frictionless (card 4970105191923460) flow the PreAuth response is succeed but
$PreAuth->SecureModeNeeded
istrue
and$PreAuth->SecureModeRedirectURL
isNULL
so my function fail because I can't redirect to 3DS page ( I don't know if it's a sandbox problem or a inplementation problem). There is no problem with the challenge flow.Here is my code :
$CardPreAuthorization = new CardPreAuthorization(); $CardPreAuthorization->AuthorId = $authorId; $CardPreAuthorization->DebitedFunds = new Money(); $CardPreAuthorization->DebitedFunds->Currency = "EUR"; $CardPreAuthorization->DebitedFunds->Amount = $amount * 100; $CardPreAuthorization->CardId = $resultCardRegistration->CardId; $CardPreAuthorization->SecureModeReturnURL = getenv('BASE_URL')."/confirm.php"; $CardPreAuthorization->Culture = "FR"; $CardPreAuthorization->Requested3DSVersion = "V2_1"; $CardPreAuthorization->SecureMode = "NO_CHOICE"; $CardPreAuthorization->IpAddress = $author->getIpAddress(); $CardPreAuthorization->BrowserInfo = $author->getBrowserInfo(); $ResultPreAuth = $this->apiMangopay->CardPreAuthorizations->Create($CardPreAuthorization);
Here the result :
object(MangoPay\CardPreAuthorization)#312 (29) { ["AuthorId"]=> string(9) "XXXXXX" ["DebitedFunds"]=> object(MangoPay\Money)#344 (2) { ["Currency"]=> string(3) "EUR" ["Amount"]=> int(1000) } ["Status"]=> string(9) "SUCCEEDED" ["PaymentStatus"]=> string(7) "WAITING" ["ResultCode"]=> string(6) "000000" ["ResultMessage"]=> string(7) "Success" ["StatementDescriptor"]=> NULL ["ExecutionType"]=> string(6) "DIRECT" ["SecureMode"]=> string(9) "NO_CHOICE" ["CardId"]=> string(9) "XXXXXX" ["SecureModeNeeded"]=> bool(true) ["SecureModeRedirectURL"]=> NULL ["SecureModeReturnURL"]=> string(76) "http://localhost:8888/confirm.php?preAuthorizationId=XXXX" ["ExpirationDate"]=> int(1622173491) ["AuthorizationDate"]=> int(1621611891) ["PaymentType"]=> string(4) "CARD" ["PayInId"]=> NULL ["SecurityInfo"]=> object(MangoPay\SecurityInfo)#351 (1) { ["AVSResult"]=> string(8) "NO_CHECK" } ["MultiCapture"]=> bool(false) ["RemainingFunds"]=> object(MangoPay\Money)#343 (2) { ["Currency"]=> string(3) "EUR" ["Amount"]=> int(1000) } ["IpAddress"]=> string(3) "::1" ["BrowserInfo"]=> object(stdClass)#294 (9) { ["AcceptHeader"]=> string(135) "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" ["JavaEnabled"]=> bool(false) ["Language"]=> string(5) "fr-FR" ["ColorDepth"]=> int(24) ["ScreenHeight"]=> int(900) ["ScreenWidth"]=> int(1440) ["TimeZoneOffset"]=> int(-120) ["UserAgent"]=> string(121) "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36" ["JavascriptEnabled"]=> bool(true) } ["Requested3DSVersion"]=> string(4) "V2_1" ["Applied3DSVersion"]=> string(4) "V2_1" ["Id"]=> string(9) "XXXX" ["CreationDate"]=> int(1621611889) }
And the last problem I face, once again I'm not sure if it's normal or not but now with the 3DS2 active all payement even under 30€ need a card with 3DS activated. If I try with the card listed for payement under 50€, it's always fail. This will be the same on production ? Because I found this very sad :(
I hope I can help someone and I also hope someone can help me 🤣
PS : sorry for the english fault, isn't my mother tongue and I try too reduce my use of Google translate to improve myself 😉
Thank you so much !
Hello,
as part of 3dsv2 we need to gather up some data from browser etc in order to pass in pay in direct/ preauth.
Is there any examples on how to gather up? I guess from Client side? (javascript)
Any demo sample? or code snippets?
thanks in advance