如何使用 PHP SDK 处理 DocuSign JWT 流程

How to work with the DocuSign JWT flow using the PHP SDK

我有一个应用程序,我在其中使用 DocuSign API 从信封中读取数据。

直到最近我还在使用这个包:https://github.com/Tucker-Eric/Laravel-Docusign 我停止使用的唯一原因是 DocuSign 现在强制使用 OAuth2,而之前它只是电子邮件、密码和集成密钥.

我做了很多阅读,还在 GitHub 上找到了上述包中问题的起点。

请注意,我使用的是 PHP SDK。这是我的尝试。

<?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;
    }
}

在另一个控制器中使用它就像这样。

<?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);
    }
}

但是这有两个问题。

  1. 我真的不希望随机的 DocuSign 调用以随机的最终用户被告知他们需要提供同意而告终。由于我对所有 API 个请求使用一个帐户,所以我假设我可以在发布前完成此操作并且一切都很好?

  2. 底层class有一个方法叫做refreshAccessToken()但是我真的不知道什么时候可以使用它?我会 post 下面的来源。

    /**
     * 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]; 
    }
  1. 在下面的转储中 dd($response[0]) 你可以看到它已经过期但是没有刷新令牌,这是否意味着我必须每小时检查一次令牌并且尝试刷新它?

  2. 最后,如果我对其进行加密,将访问令牌存储在存储文件夹中是否安全?

希望这实际上非常简单,但如有必要,我会修改我的问题。

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.

此方法用于授权码授予。使用 JWT,无论何时您需要一个新令牌 - 您只需进行与第一次获取时相同的 API 调用。不用用JWT刷新,直接换一个。

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?

JWT 的最佳实践是——只要您的应用需要令牌——您就可以获得一个新令牌。例外情况可能是如果您必须连续进行 2 次 API 调用,那么您可以重复使用相同的令牌。但是您不必一定测量时间来确定令牌过期时间,只需每次获取一个新令牌即可。

Finally, if I encrypt it, is it safe to store the access token in the storage folder?

您之前使用legacy auth时,您将帐户密码存储在代码中的什么位置?访问令牌就像密码一样。不要将它存放在有人可能拿到它的地方。如果您使用安全的东西 - 没关系,但保护它是您的责任。