Jump to content

DataParsingError


 Share

Recommended Posts

Hi All

New here, had a quick search and I believe that my issue is related to encoding but really not sure, feels like I've tried so much now.

I have an app created and the beginnings of a Sage Class.

When calling authorizeSageAccountingApp() from a PHP page, it redirects to authorise my app, I am redirected to a page with handleCallback() and then receiving the following:
 

'{"$severity":"error","$dataCode":"DataParsingError","$message":"The data you sent could not be processed.","$source":"Proxy"}'

I am clearly doing something wrong but I may not have a good understanding of what's happening here.

Any pointers are greatly received.

Eventually, I would like to code the ability to create invoices in our Sage Accounting account rather than using Stripe.

<?php
 
class Sage
{
 
   
    public function __construct() {
 
        $this->clientId = 'XXXX';
        $this->clientSecret = 'XXXX';
    }
 
    function authorizeSageAccountingApp()
    {
        $authorizationUrl = 'https://www.sageone.com/oauth2/auth/central?filter=apiv3.1&country=gb&locale=en_GB';
        $clientId = $this->clientId;
        $redirectUri = 'http://localhost/sailadventure-new/tests/callback';
        $scopes = 'full_access'; // or 'readonly' if applicable
 
        $authorizationUrl .= '&response_type=code';
        $authorizationUrl .= '&client_id=' . urlencode($clientId);
        $authorizationUrl .= '&redirect_uri=' . urlencode($redirectUri);
        $authorizationUrl .= '&scope=' . urlencode($scopes);
 
        header('Location: ' . $authorizationUrl);
        exit();
 
    }
 
    function handleCallback()
    {
        if (isset($_GET['code'])) {
            $authorizationCode = $_GET['code'];
            $clientId = $this->clientId;
            $clientSecret = $this->clientSecret;
            $redirectUri = 'http://localhost/sailadventure-new/tests/continue';
 
            $tokenUrl = 'https://oauth.accounting.sage.com/token';
            $header = array('Accept: application/json','Content-Type: application/x-www-form-urlencoded');
            $content = "client_id=$clientId&client_secret=$clientSecret&grant_type=authorization_code";
 
            $curl = curl_init();
 
            curl_setopt_array($curl, array(
                CURLOPT_URL => $tokenUrl,
                CURLOPT_HTTPHEADER => $header,
                CURLOPT_RETURNTRANSFER => true,
                CURLOPT_POST => true,
                CURLOPT_POSTFIELDS => $content
            ));
               
            $response = curl_exec($curl);
               
            curl_close($curl);
 
            echo '<pre>' . var_export($response, true) . '</pre>';
 
        } else {
            echo "Authorization code not found.";
        }
    }    
}
Edited by Matthew Barraud
Link to comment
Share on other sites

I just tidied the code a little, and I am still getting the same response.

<?php
 
class Sage
{
    private $clientId;
    private $clientSecret;
    private $accessToken;
   
    public function __construct() {
 
        $this->clientId = '37d7XXXXXXXXXXXXXe064ec9';
        $this->clientSecret = 'eieXXXXXXXXXXXIz';
    }
 
    function authorizeSageAccountingApp()
    {
        $authorizationUrl = 'https://www.sageone.com/oauth2/auth/central?filter=apiv3.1&country=gb&locale=en_GB';
        $clientId = $this->clientId;
        $redirectUri = 'http://localhost/sailadventure-new/tests/callback';
        $scopes = 'full_access'; // or 'readonly' if applicable
 
        $authorizationUrl .= '&response_type=code';
        $authorizationUrl .= '&client_id=' . urlencode($clientId);
        $authorizationUrl .= '&redirect_uri=' . urlencode($redirectUri);
        $authorizationUrl .= '&scope=' . urlencode($scopes);
 
        header('Location: ' . $authorizationUrl);
        exit();
    }
 
    function handleCallback()
    {
        if (isset($_GET['code'])) {
 
            // Initialize cURL
            $curl = curl_init();
 
            // Create the URL
            $url = 'https://oauth.accounting.sage.com/token';
 
           
            $clientSecret = $this->clientSecret;
            $authCode = urlencode($_GET['code']);
            $data = array(
                'client_id' => $this->clientId,
                'client_secret' => $this->clientSecret,
                'code' => $authCode,
                'grant_type' => 'authorization_code',
                'redirect_uri' => 'http://localhost/sailadventure-new/tests/continue'
            );
 
            $jsonData = json_encode($data);
            curl_setopt($curl,  CURLOPT_POSTFIELDS, $jsonData);
            curl_setopt($curl,  CURLOPT_URL, $url);
            curl_setopt($curl,  CURLOPT_CUSTOMREQUEST, 'POST');
            curl_setopt($curl,  CURLOPT_RETURNTRANSFER, true);
            curl_setopt($curl,  CURLOPT_HTTPHEADER,
            [
                'Content-Type: application/json'
            ]);
 
            // Execute the request
            $response = curl_exec($curl);
 
            if (curl_errno($curl)) {
                $error = curl_error($curl);
                return $error;
            }
 
            curl_close($curl);
            echo '<pre>' . var_export($response, true) . '</pre>';
           
        }
    }
}

 

Edited by Matthew Barraud
Link to comment
Share on other sites

Hi Matthew, welcome to the forum.

Could you clarify you have the following:

  • You've read the Authentication Guide.
  • Your application has been registered in the developer self service portal and the correct callback url's have been added. **Note** - callback url's are case sensitive.
  • A Sage Business Cloud Accounting instance has been created to test the oAuth flow https://developer.sage.com/accounting/quick-start/set-up-the-basics/.
  • You're able to sign into the Sage Business Cloud Accounting instance and view the welcome dashboard.
  • The parameters passed in the auth url match those registered in the developer portal and the country filter(optional) passed matches the country the business is registered for. For example if GB is passed and the business is registered for the US the auth will fail.

If you have the above it may be worthwhile completing the Auth flow in POSTMAN before moving on to you app. 

Looking at your code I can't see how you're constructing the auth url with the required params. It should look similar to the below.

request_uri = auth_url + "&response_type=" + response_type + "&client_id=" + client_id + "&redirect_uri=" + redirect_uri + "&scope=" + scope + "&state=" + state

 

Also, your code for exchanging the code once it's returned doesn't look to be using the correct header params

 

def exchange_code(code: str):
    headers = {
        "Content-Type": "application/x-www-form-urlencoded",
        "Accept": "application/json",
    }
    data = {
        "client_id": config.client_id,
        "client_secret": config.client_secret,
        "code": code,
        "grant_type": "authorization_code",
        "redirect_uri": config.redirect_uri,
    }
    response = requests.post(config.token_url, headers=headers, data=data)

Thanks

Mark

Link to comment
Share on other sites

Hi Mark

Thanks for replying 🙂

In response ...

  • You've read the Authentication Guide
    Yep, loads, he he
  • Your application has been registered in the developer self service portal and the correct callback url's have been added. **Note** - callback url's are case sensitive.
    I believe so., see pic below.
    image.thumb.png.0467aa70b3a43b9ec9850719849a0d6e.png
  • A Sage Business Cloud Accounting instance has been created to test the oAuth flow https://developer.sage.com/accounting/quick-start/set-up-the-basics/.
    This one, I'm not sure, I already have a Sage Accounting account for my business. Do I need to setup a trial account as well?
  • You're able to sign into the Sage Business Cloud Accounting instance and view the welcome dashboard.
    Yep, on my business account, see above ref, developer.
  • The parameters passed in the auth url match those registered in the developer portal and the country filter(optional) passed matches the country the business is registered for. For example if GB is passed and the business is registered for the US the auth will fail.
    Understood all GB used.

    -----

    When I visit http://localhost/sailadventure-new/tests/ it opens a new instance of my class and runs the authorizeSageAccountingApp() function. This redirects the page to 

    https://www.sageone.com/oauth2/auth/central?filter=apiv3.1&country=gb&locale=en_GB&response_type=code&client_id=XXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXX&redirect_uri=http%3A%2F%2Flocalhost%2Fsailadventure-new%2Ftests%2Fcallback&scope=full_access&state=159786325

    it then prompts me with the following

    image.thumb.png.1b4b3fe589d135b1cc23771433744c5c.png

    clicking allow then returns '{"$severity":"error","$dataCode":"DataParsingError","$message":"The data you sent could not be processed.","$source":"Proxy"}'

    I've been updating the code and working through issues as I learn/understand them.

    This is the class currently in PHP
     
    <?php
     
    class Sage
    {
        private $clientId;
        private $clientSecret;
        private $accessToken;
       
        public function __construct() {
     
            $this->clientId = 'XXXX';
            $this->clientSecret = 'XXXX';
        }
     
        function authorizeSageAccountingApp()
        {
            $authorizationUrl = 'https://www.sageone.com/oauth2/auth/central?filter=apiv3.1&country=gb&locale=en_GB';
            $clientId = $this->clientId;
            $redirectUri = 'http://localhost/sailadventure-new/tests/callback';
            $scopes = 'full_access'; // or 'readonly' if applicable
     
            $authorizationUrl .= '&response_type=code';
            $authorizationUrl .= '&client_id=' . urlencode($clientId);
            $authorizationUrl .= '&redirect_uri=' . urlencode($redirectUri);
            $authorizationUrl .= '&scope=' . urlencode($scopes);
            $authorizationUrl .= '&state=159786325';
     
            header('Location: ' . $authorizationUrl);
            exit();
        }
     
        function handleCallback()
        {
            if (isset($_GET['code'])) {
     
                // Initialize cURL
                $curl = curl_init();
     
                // Create the URL
                $url = 'https://oauth.accounting.sage.com/token';
     
               
                $clientSecret = $this->clientSecret;
                $authCode = $_GET['code'];
                $data = array(
                    'grant_type' => 'authorization_code',
                    'client_id' => $this->clientId,
                    'client_secret' => $this->clientSecret,
                    'code' => $authCode,
                    'redirect_uri' => 'http://localhost/sailadventure-new/tests/callback'
                );
                http_build_query($data);
                curl_setopt($curl,  CURLOPT_POSTFIELDS, $data);
                curl_setopt($curl,  CURLOPT_URL, $url);
                curl_setopt($curl,  CURLOPT_CUSTOMREQUEST, 'POST');
                curl_setopt($curl,  CURLOPT_RETURNTRANSFER, true);
                curl_setopt($curl,  CURLOPT_HTTPHEADER,
                [
                    'Content-Type: application/x-www-form-urlencoded',
                    'Accept: application/json',
                ]);
     
                // Execute the request
                $response = curl_exec($curl);
     
                if (curl_errno($curl)) {
                    $error = curl_error($curl);
                    return $error;
                }
     
                curl_close($curl);
                echo '<pre>' . var_export($response, true) . '</pre>';
               
            }
        }
    }
Link to comment
Share on other sites

I think I have it!

This was an encoding / decoding issue in the URL. With the edition of the following to the $authCode variable I was able to get a token returned.
 

function handleCallback()
    {
        if (isset($_GET['code'])) {
 
            // Initialize cURL
            $curl = curl_init();
 
            // Create the URL
            $url = 'https://oauth.accounting.sage.com/token';
 
            $clientSecret = $this->clientSecret;
 
            $authCode = $_GET['code'];
            $authCode = preg_replace("/%u([0-9a-f]{3,4})/i","&#x\\1;",urldecode($authCode));
            $authCode = html_entity_decode($authCode,null,'UTF-8');
 
            $data = array(
                'client_id' => $this->clientId,
                'client_secret' => $this->clientSecret,
                'code' => $authCode,
                'grant_type' => 'authorization_code',              
                'redirect_uri' => 'http://localhost/sailadventure-new/tests/callback'
            );
 
            curl_setopt($curl,  CURLOPT_POSTFIELDS, http_build_query($data));
            curl_setopt($curl,  CURLOPT_URL, $url);
            curl_setopt($curl,  CURLOPT_CUSTOMREQUEST, 'POST');
            curl_setopt($curl,  CURLOPT_RETURNTRANSFER, true);
            curl_setopt($curl,  CURLOPT_HTTPHEADER,
            [
                'Content-Type: application/x-www-form-urlencoded',
                'Accept: application/json',
            ]);
 
            // Execute the request
            $response = curl_exec($curl);
 
            if (curl_errno($curl)) {
                $error = curl_error($curl);
                return $error;
            }
 
            curl_close($curl);
            echo '<pre>' . var_export($response, true) . '</pre>';
           
        }
    }
Edited by Matthew Barraud
Link to comment
Share on other sites

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...