Issue
I have an application in which I use the DocuSign API to read data from envelopes.
Up until recently I was using this package: https://github.com/Tucker-Eric/Laravel-Docusign and the only reason I've stopped is because DocuSign is now enforcing the use of OAuth2, whereas before it was just email, password and an integration key.
I did a lot of reading and also found a starting point on the issues within the above package on GitHub.
Note that I'm using the PHP SDK. Here is my attempt.
<?php
namespace App\DocuSign;
use DocuSign\eSign\Client\ApiClient;
use DocuSign\eSign\Client\Auth\OAuth;
use DocuSign\eSign\Configuration;
use Throwable;
/**
* Helper class to generate a DocuSign Client instance using JWT OAuth2.
*
* @see
*
*/
class OAuthClient
{
/**
* Create a new DocuSign API Client instance using JWT based OAuth2.
*/
public static function createApiClient()
{
$config = (new Configuration())->setHost(config('docusign.host'));
$oAuth = (new OAuth())->setOAuthBasePath(config('docusign.oauth_base_path'));
$apiClient = new ApiClient($config, $oAuth);
try {
$response = $apiClient->requestJWTUserToken(
config('docusign.integrator_key'),
config('docusign.user_id'),
config('docusign.private_key'),
'signature impersonation',
60
);
if ($response) {
$accessToken = $response[0]['access_token'];
$config->addDefaultHeader('Authorization', 'Bearer ' . $accessToken);
$apiClient = new ApiClient($config);
return $apiClient;
}
} catch (Throwable $th) {
// If consent is required we just need to give the consent URL.
if (strpos($th->getMessage(), 'consent_required') !== false) {
$authorizationUrl = config('docusign.oauth_base_path') . '/oauth/auth?' . http_build_query([
'scope' => 'signature impersonation',
'redirect_uri' => config('docusign.redirect_url'),
'client_id' => config('docusign.integrator_key'),
'response_type' => 'code'
]);
dd($authorizationUrl);
}
}
return $apiClient;
}
}
To use this in another controller is like so.
<?php
namespace App\Http\Controllers;
use App\DocuSign\OAuthClient;
class HomeController extends Controller
{
/**
* Display the welcome page.
*/
public function index()
{
$client = OAuthClient::createApiClient();
dd($client);
}
}
There are two issues with this however.
I don't really want a random DocuSign call to end up with a random end user being told they need to provide consent. As I'm using one account for all API requests I'm assuming I can do this before launch and I'd be all good?
The underlying class has a method called
refreshAccessToken()
but I don't really see when I could use it? I'll post the source below.
/**
* Refresh Access Token
*
* @param string $client_id DocuSign OAuth Client Id(AKA Integrator Key)
* @param string $client_secret The secret key you generated when you set up the integration in DocuSign Admin console.
* @param string $code The authorization code
*
* @return array
* @throws ApiException
* @throws InvalidArgumentException
*/
public function refreshAccessToken($client_id = null, $client_secret = null, $refresh_token = null)
{
if (!$client_id) {
throw new \InvalidArgumentException('Missing the required parameter $client_id when calling refreshAccessToken');
}
if (!$client_secret) {
throw new \InvalidArgumentException('Missing the required parameter $client_secret when calling refreshAccessToken');
}
if (!$refresh_token) {
throw new \InvalidArgumentException('Missing the required parameter $refresh_token when calling refreshAccessToken');
}
$resourcePath = "/oauth/token";
$queryParams = [];
$integrator_and_secret_key = "Basic " . utf8_decode(base64_encode("{$client_id}:{$client_secret}"));
$headers = [
"Authorization" => $integrator_and_secret_key,
"Content-Type" => "application/x-www-form-urlencoded",
];
$postData = [
"grant_type" => "refresh_token",
"refresh_token" => $refresh_token,
];
list($response, $statusCode, $httpHeader) = $this->callApi($resourcePath, self::$POST, $queryParams, $postData, $headers, null, null, true);
if (isset($response->access_token))
$this->config->addDefaultHeader("Authorization", "{$response->token_type} {$response->access_token}");
return [$this->getSerializer()->deserialize($response, '\DocuSign\eSign\Client\Auth\OAuthToken', $httpHeader), $statusCode, $httpHeader];
}
In the dump below which is just
dd($response[0])
you can see it gives an expiration but there is no refresh token, does this mean I would have to check the token once an hour and try to refresh it?Finally, if I encrypt it, is it safe to store the access token in the storage folder?
Hopefully this is actually pretty straightforward but I'll amend my question if necessary.
Solution
I don't really want a random DocuSign call to end up with a random end user being told they need to provide consent. As I'm using one account for all API requests I'm assuming I can do this before launch and I'd be all good?
Yes, you'll be all good. Notice, it's not one account but one user, if you use a single user all the time, consent was given once and done and you'll never have to give consent again.
The underlying class has a method called refreshAccessToken() but I don't really see when I could use it? I'll post the source below.
This method is for Auth Code Grant. With JWT whenever you need a new token - you just make the same API call you made to obtain the first time. No need to refresh with JWT, just get a new one.
In the dump below which is just dd($response[0]) you can see it gives an expiration but there is no refresh token, does this mean I would have to check the token once an hour and try to refresh it?
Best practice with JWT is - whenever your app needs a token - you obtain a new one. The exception may be if you have to make 2 consecutive API calls, then you can reuse the same token. But you don't have to necessarily measure time to determine token expiration, just obtain a new one every time.
Finally, if I encrypt it, is it safe to store the access token in the storage folder?
Where did you store the account password in your code when you used legacy auth before? The access token is just like a password. Do not store it where there's a chance someone may get it. If you use something secure - that's ok, but it's your responsibility to secure it.
Answered By - Inbar Gazit Answer Checked By - Candace Johnson (PHPFixing Volunteer)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.