php-twinfield / twinfield

PHP 7.3+ Library for using the Twinfield API.
https://accounting.twinfield.com/webservices/documentation/#/
Other
33 stars 78 forks source link

User server side connection without browser #203

Closed japaveh closed 2 years ago

japaveh commented 3 years ago

Hi all

I use this module to do server side requests to Twinfield to check payment status and to send invoices via the API to Twinfield. This works without any issue using the old username password but this method will be invalidated tomorrow.

I am trying to implement the oAuth2 method but I cannot get this working without without any user interaction via the browser. This is obviously a requirement for only server-side interaction

I tried to use the password grant via

 $accessToken = $provider->getAccessToken('password',
                [
                    'username' => $this->getOptions()->getUsername(),
                    'password' => $this->getOptions()->getPassword()
                ]);

But then I get unauthorized_client as response

Any tips to get this working?

luukskeur commented 2 years ago

@japaveh managed to get this working?

japaveh commented 2 years ago

@luukskeur Yes, and I already planned to share the solution here so your head-up triggered this :)

The solution I implemented is by storing the refresh token you get from Twinfield, as this token is valid for a very long time (20 years or so) but I also included code to fetch a new refresh token. I store this refresh token in an include file together with the Twinfield ClientId and secret

I created a class: TwinfieldAdapter (gist) which handles all the communcation to Twinfield using PHPTwinfield and standard Guzzle calls

The process is as follows:

  1. You first register an application in Twinfield so you get a clientId and secret.
  2. Then I created a simple controller (gist) which can be used to check if the saved refresh token is valid and if not you can push a button to start a oAuth request to twinfield.
  3. In the callback the refresh token is shown on the screen so you can save it back in the secrets file, or you can save it in a database if you prefer.
  4. So, if a service needs an access token you can call TwinfieldAdapter->getTwinfieldAuthentication() which uses the refresh token to request a new access token etc.

Of course this solution is open for improvements

luukskeur commented 2 years ago

Nice, thanks for the reply! I hope it helps others.

In the meantime I got it working as well following this example: https://github.com/iranl/twinfield/blob/extend-all/examples/Authorization.php

Storing and using the refreshtoken server-side is the solution, the docs weren't that clear 😅

luukskeur commented 2 years ago

And, could you close the issue? @japaveh