Authorization Code Grant refresh tokens

Since August 2020, new integrations (and beginning September 2022, all integrations) are required to use OAuth to communicate with DocuSign services. The recommended authentication method is Authorization Code Grant, and it offers the use of refresh tokens.

To use DocuSign's services, you must first obtain a token. This is to guarantee that the user has adequate resource access. Access tokens have a limited lifespan: the Authorization Code Grant token, for example, has an eight-hour lifespan. The user should generate a new access token after eight hours, which would ordinarily require the user to reauthenticate.

This is where refresh tokens come into play: instead of logging in again, you can use a refresh token to request a new access token. The full details of how to obtain the access token using the authorization code are already covered in our ACG guide. Instead, in this blog, I’m going to focus on refresh tokens and how to use them. 

Below is an example response from a successful access token authentication request:

{
    "access_token":"eyJ0eXAi......mX9f7k1g",
    "token_type":"Bearer",
    "refresh_token":"eyJ0eXAi......mruC5c3A",
    "expires_in":28800
}

As you can see, I have an access token of type Bearer with a lifetime of 28800 seconds (eight hours) and a refresh token. (While it’s not specified in the response, refresh tokens have a lifetime of 30 days.)

Once the access token expires, the app will need to request a new one. Trying to use an expired access token will result in a 401-Unauthorized error.

Token generation

To request a new access token from DocuSign using a refresh token, you need to make a POST request call to:

Here’s the structure of the call:

  • Header: Authorization: Basic Base64-encoded integration_key:secret_key
  • Body: refresh_token=Value of refresh token from a previous response grant_type=refresh_token

Here’s how a sample request to the developer environment would look in Curl:

curl --location --request POST 'https://account-d.docusign.com/oauth/token' \
--header 'Authorization: Basic 'NWYxZTg4…………...TJkOGI2Yg==' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'refresh_token=eyJ0eX…………...Dp_hA' \
--data-urlencode 'grant_type=refresh_token'

For a request to the developer environment in C#, you can use the code from the GenerateAccessToken method from the official C# client SDK by updating the parameters’ keys and values:

string baseUri = string.Format("https://account-d.docusign.com/");
string codeAuth = (clientId ?? "") + ":" + (clientSecret ?? "");
byte[] codeAuthBytes = Encoding.UTF8.GetBytes(codeAuth);
string codeAuthBase64 = Convert.ToBase64String(codeAuthBytes);

RestClient restClient = new RestClient(baseUri);
restClient.Timeout = Configuration.Timeout;
restClient.UserAgent = Configuration.UserAgent;
restClient.Proxy = Proxy;

RestRequest request = new RestRequest("oauth/token", Method.POST);

request.AddHeader("Authorization", "Basic " + codeAuthBase64);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
// Don't cache authentication requests
request.AddHeader("Cache-Control", "no-store");
request.AddHeader("Pragma", "no-cache");

Dictionary<string, string> formParams = new Dictionary<string, string>
{
    { "grant_type", "refresh_token" },
    { "refresh_token", existing_refresh_token}
};

foreach (var item in formParams)
    request.AddParameter(item.Key, item.Value);

IRestResponse response = restClient.Execute(request);

As you can see, exchanging a refresh token for an access token is quite easy. However, DocuSign offers even more flexibility when it comes to refresh token lifespan by using the extended scope.

The extended scope

When an access token is generated, you must specify scopes

Scopes are labels for permissions; that is, what your app is allowed to do through the API. One of the scopes, extended, is used only in regards to Authorization Code Grant.

Note: The extended scope is requested when an authorization code is used to request an access token. The extended scope cannot be specified when exchanging a refresh token for an access token. 

What is so special about the extended scope? To explain, I’ll demonstrate the access and refresh token lifetimes without and with the extended scope:

Without the extended scope

Use case: An access token (shown in red in the image below) was generated from an authorization code on April 15. The access code is valid for eight hours; the refresh token (green) is valid for 30 days (its lifetime ends on May 15).

Access and refresh token lifetimes without the extended scope

If you request a new access token using the refresh token on May 15, the new access token will be valid for eight hours, and the refresh token lifetime will still end on May 15. On May 16 the refresh token will expire, and you will need to generate a fresh access token from a new authorization code; hence the user will need to log in.

With the extended scope

Now consider the same scenario, but this time with the extended scope:

Access and refresh token lifetimes with the extended scope

If you request an access token on May 15, the access token will be valid for eight hours and the refresh token will get an extended lifetime until June 15. On May 16 the refresh token will have 30 more days of life and the user will not be required to log in.

The easiest way to think of this is that, if you specify the extended scope, every time a refresh token is used, its life will be extended by 30 days.

Summary

With the use of refresh tokens with the extended scope, it is possible for a user to remain logged in indefinitely by requesting the extended scope and continually refreshing its access token.

Additional resources

Ivan DInkov
Author
Ivan Dinkov
Sr. Developer Support Advisory Engineer
Published