walle89 / SwedbankJson

Unofficial API client for the Swedbank's and Sparbankerna's mobile apps in Sweden.
MIT License
75 stars 14 forks source link

Problems getting started #45

Closed wilhelmssonjens closed 2 years ago

wilhelmssonjens commented 2 years ago

Hi, I'm trying to use your package for a python project. I have not used PHP before so it might be something obvious that I'm missing.

I wan't to be able to access the "Quick Balance" so I'm trying to get a subscription ID using the example code provided but I am struggling.

I installed the package using composer according the instructions and I am currently running a index.php file using the command: php -S 127.0.0.1:8000 to run it in my browser.

First, I tried the following code (replaced personal identity number):

<?php 
require 'vendor/autoload.php';

session_start();

// Settings
$bankApp   = 'swedbank';
$username  = YYMMDDXXXX; // Personal identity number (personnummer).
$cachePath = __DIR__.'/AppData.json';

// Sign in
if (!isset($_SESSION['swedbankjson_auth']))
{
    $appData = new SwedbankJson\AppData($bankApp, $cachePath);
    $auth = new SwedbankJson\Auth\MobileBankID($appData);
    $auth->initAuth();
    exit('Please open the BankID app and confirm the login. Then reload this page.');
}

// Verify sign in
$auth = unserialize($_SESSION['swedbankjson_auth']);
if (!$auth->verify())
    exit("You reloaded the page, but the authentication has not been approved in the BankID app. Please try again.");

// You are in
$bankConn = new SwedbankJson\SwedbankJson($auth);

if (empty($_POST['quickbalanceSubscriptionID']))
{
    $quickBalanceAccounts = $bankConn->quickBalanceAccounts();

    echo '<form action="" method="post"><p>Select account for SubscriptionId</p><select name="quickbalanceSubscriptionID">';

    foreach ($quickBalanceAccounts->accounts as $account)
        echo '<option value="'.$account->quickbalanceSubscription->id.'">'.$account->name.'</option>';

    echo '</select><button>Create subscription</button></form>';
    exit;
}

$subInfo = $bankConn->quickBalanceSubscription($_POST['quickbalanceSubscriptionID']);
echo "<p>Your SubscriptionId: {$subInfo->subscriptionId}</p>
<p>Test it right away:</p>var_dump(\$bankConn->quickBalance('{$subInfo->subscriptionId}'));";

$auth->terminate(); // Sign out

It seems to work and it displays the text "Please open the BankID app and confirm the login. Then reload this page" in the browser. But nothing happens in the "Mobilt BankID" app on my phone? I reload the page and get "You reloaded the page, but the authentication has not been approved in the BankID app. Please try again.".

Not sure what the problem is. However, I tried replacing the authentication method with the QR-approach as follows:

<?php 
require 'vendor/autoload.php';

session_start();

// Settings
$bankApp   = 'swedbank';
$username  = YYMMDDXXXX; // Personal identity number (personnummer).
$cachePath = __DIR__.'/AppData.json';

// Step 1 - Start the authentication process
if (!isset($_SESSION['swedbankjson_auth']))
{
    $appData = new SwedbankJson\AppData($bankApp, __DIR__.'/AppData.json');
    $auth    = new SwedbankJson\Auth\MobileBankID($appData);
    $auth->initAuth();

    // Need to reload page
    exit('<meta http-equiv="refresh" content="0">');
}

// Step 2 - Verify authentication
$auth = unserialize($_SESSION['swedbankjson_auth']);
if (!$auth->verify()) {

    // Reload page once per 2 seconds.
    echo '<meta http-equiv="refresh" content="2">';

    echo '<strong>Instructions</strong>
          <ol>
              <li>Open the BankID app</li>
              <li>Press "Scan QR code" and scan the QR code below.</li>
              <li>Done, this page will update automatically.</li>
          </ol>';
    printf(
        '<img src="data:image/png;base64,%s" style="max-width:100%%">',
        base64_encode($auth->getChallengeImage())
    );
}

// You are in
$bankConn = new SwedbankJson\SwedbankJson($auth);

if (empty($_POST['quickbalanceSubscriptionID']))
{
    $quickBalanceAccounts = $bankConn->quickBalanceAccounts();

    echo '<form action="" method="post"><p>Select account for SubscriptionId</p><select name="quickbalanceSubscriptionID">';

    foreach ($quickBalanceAccounts->accounts as $account)
        echo '<option value="'.$account->quickbalanceSubscription->id.'">'.$account->name.'</option>';

    echo '</select><button>Create subscription</button></form>';
    exit;
}

$subInfo = $bankConn->quickBalanceSubscription($_POST['quickbalanceSubscriptionID']);
echo "<p>Your SubscriptionId: {$subInfo->subscriptionId}</p>
<p>Test it right away:</p>var_dump(\$bankConn->quickBalance('{$subInfo->subscriptionId}'));";

$auth->terminate(); // Sign out

This seem to work and I am able to scan the QR code in the browser and identify myself in the "Mobilt BankID" app. But in the terminal from where I'm running the code, I get that this action require a stronger authentication:

[Sun Nov 28 13:22:24 2021] 127.0.0.1:60818 [200]: / - Uncaught SwedbankJson\Exception\ApiException: general (1): STRONGER_AUTHENTICATION_NEEDED - Den här tjänsten kräver en annan ID-metod. Klicka på Fortsätt för att logga in med ny ID-metod. in /Users/proj/vendor/walle89/swedbank-json/src/Auth/AbstractAuth.php:301
Stack trace:
#0 /Users/proj/vendor/walle89/swedbank-json/src/Auth/AbstractAuth.php(140): SwedbankJson\Auth\AbstractAuth->sendRequest(Object(GuzzleHttp\Psr7\Request), Array)
#1 /Users/proj/vendor/walle89/swedbank-json/src/SwedbankJson.php(44): SwedbankJson\Auth\AbstractAuth->getRequest('profile/')
#2 /Users/proj/vendor/walle89/swedbank-json/src/SwedbankJson.php(87): SwedbankJson\SwedbankJson->profileList()
#3 /Users/proj/vendor/walle89/swedbank-json/src/SwedbankJson.php(350): SwedbankJson\SwedbankJson->selectProfile('')
#4 /Users/proj/index.php(46): SwedbankJson\SwedbankJson-> in /Users/proj/vendor/walle89/swedbank-json/src/Auth/AbstractAuth.php on line 301

So it says that I need another identification method and to click continue. But I don't understand where this button should be? In the mobile app? Or browser?

Thanks for helping out a complete beginner!

NisseDILLIGAF commented 2 years ago

You have this line in the wrong place

// Need to reload page
exit('<meta http-equiv="refresh" content="0">');

that should be after you print the qr code... like this

printf(
    '<img src="data:image/png;base64,%s" style="max-width:100%%">',
    base64_encode($auth->getChallengeImage())
);
// Need to reload page
exit('<meta http-equiv="refresh" content="0">');

Hope this helps :smiley:

edit: @walle89 Maybe I'm wrong but shouldn't the exit code be after the QR image? https://github.com/walle89/SwedbankJson/blob/c753010dc7e0b588361032b26d34bab4f053c15f/docs/authentication.md?plain=1#L113

wilhelmssonjens commented 2 years ago

You have this line in the wrong place

// Need to reload page
exit('<meta http-equiv="refresh" content="0">');

that should be after you print the qr code... like this

printf(
    '<img src="data:image/png;base64,%s" style="max-width:100%%">',
    base64_encode($auth->getChallengeImage())
);
// Need to reload page
exit('<meta http-equiv="refresh" content="0">');

Hope this helps 😃

Thanks! Yes it did! Now I have my subscription ID and I managed to get my balance using it. Great stuff!

walle89 commented 2 years ago

@NisseDILLIGAF Well, I don't think your code dosen't do anything to be honest. What exit('<meta http-equiv="refresh" content="0">'); does is to reload the page so that you get to step 2 where it will display the QR-code with instructions. Try print anything before a page reload dosen't do anything.

Edit: I saw now the documentaiton did have a missing exit;, thanks @NisseDILLIGAF to pointing that out. I have updated the documentation.

@wilhelmssonjens When you get STRONGER_AUTHENTICATION_NEEDED is sually means that you try to access an endproint without proper auehntication. In other words, you try to run $bankConn->quickBalanceAccounts() before beeing authenticated. The easiest way to fix that is to add an exit after your QR-code display. By doing that, the $auth->verify() needs to be true before it can run quickBalanceAccounts():

    printf(
        '<img src="data:image/png;base64,%s" style="max-width:100%%">',
        base64_encode($auth->getChallengeImage())
    );
    exit;
}

Full working example code (I did remove the username sense it isn't needed for BankID):

<?php
require '../vendor/autoload.php';

session_start();

// Settings
$bankApp   = 'swedbank';
$cachePath = __DIR__.'/AppData.json';

// Step 1 - Start the authentication process
if (!isset($_SESSION['swedbankjson_auth']))
{
    $appData = new SwedbankJson\AppData($bankApp, __DIR__.'/AppData.json');
    $auth    = new SwedbankJson\Auth\MobileBankID($appData);
    $auth->initAuth();

    // Need to reload page
    exit('<meta http-equiv="refresh" content="0">');
}

// Step 2 - Verify authentication
$auth = unserialize($_SESSION['swedbankjson_auth']);
if (!$auth->verify())
{
    // Reload page once per 2 seconds.
    echo '<meta http-equiv="refresh" content="2">';

    echo '<strong>Instructions</strong>
          <ol>
              <li>Open the BankID app</li>
              <li>Press "Scan QR code" and scan the QR code below.</li>
              <li>Done, this page will update automatically.</li>
          </ol>';
    printf(
        '<img src="data:image/png;base64,%s" style="max-width:100%%">',
        base64_encode($auth->getChallengeImage())
    );
    exit;
}

// You are in
$bankConn = new SwedbankJson\SwedbankJson($auth);

if (empty($_POST['quickbalanceSubscriptionID']))
{
    $quickBalanceAccounts = $bankConn->quickBalanceAccounts();

    echo '<form action="" method="post"><p>Select account for SubscriptionId</p><select name="quickbalanceSubscriptionID">';

    foreach ($quickBalanceAccounts->accounts as $account)
        echo '<option value="'.$account->quickbalanceSubscription->id.'">'.$account->name.'</option>';

    echo '</select><button>Create subscription</button></form>';
    exit;
}

$subInfo = $bankConn->quickBalanceSubscription($_POST['quickbalanceSubscriptionID']);
echo "<p>Your SubscriptionId: {$subInfo->subscriptionId}</p>
<p>Test it right away:</p>var_dump(\$bankConn->quickBalance('{$subInfo->subscriptionId}'));";

$auth->terminate(); // Sign out