From the Trenches: Making API calls for members of multiple accounts
Offer users their choice of accounts and store their preferences for later.
Table of contents
For many Docusign users, their access rights are straightforward: they're a member of a Docusign account and they use it to send envelopes. Nice and simple.
As a developer, however, you can't always rely on your clients to make things easy for you. Many Docusign users are members of multiple accounts, and while the UserInfo API will tell you which one is their default, that isn't always going to be the one used with your integration. Because of this, you'll need to plan ahead to make sure your application is still useful when a user has more than one membership.
For the most flexibility, you'll want to let the user choose. To start, the first time the user authenticates, go ahead and make the UserInfo call with their token and parse out the response. If there's only one account, you can be reasonably sure that's the correct one for the user. If there's more than one, you'll want to display the account name at a minimum, and marking the default account (isDefault: true
) will help them decide. The account ID value and the subdomain of the base URI (the "na3" of "na3.docusign.net") may be helpful, but most users are only familiar with the short form ID, while UserInfo returns the GUID, long form of the account ID.
Instead of having each user make the choice individually, you may want an administrator to make the choice for them. To do so, when the admin is presented with a list of accounts, your integration could save one of them in your database or in a configuration file. Then, when future users authenticate for the first time, you can reference that stored account ID and check the UserInfo response to see if it is available. If so, you can move forward with that account and base URL; but if it isn't, you'll need to decide if you should throw an error or allow the user to pick a different account.
Once the user has made their choice, your application should store their preferences and use that to avoid having to make the UserInfo call in the future. Of course, a user's membership can change, so you should have an option available to reset the stored preference in the event that the previous selection is no longer valid.
The C# class below demonstrates how to retrieve user information and match a required user account that has already been set in Web.config (In a case of a .NET Framework application). Of course, you can customize the code and save your preferred account ID (in a GUID format) in your database and later retrieve its value.
public class Myclass
{
private static HttpClient client;
.
.
.
. Logic to retrieve the token
.
.
private DSUserInfo GetUserInfo(string access_token)
{
var userInfoEndpoint = "https://account-d.docusign.com/oauth/userinfo";
client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, userInfoEndpoint);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", access_token);
var response = client.SendAsync(request).Result;
var result = JObject.Parse(response.Content.ReadAsStringAsync().Result);
List<Account> accounts = new List<Account>();
accounts = (from a in result["accounts"]
select new Account
{
AccountName = (string)a["account_name"],
AccountId = (string)a["account_id"],
BasePath = (string)a["base_uri"] + "/restapi",
IsDefault = (bool)a["is_default"]
}
).OrderByDescending(o => o.IsDefault ? 1 : 0).ToList();
if (ConfigurationManager.AppSettings["RequiredAccount"].Length > 0)
{
accounts = accounts.Where(a => a.AccountId.Equals(ConfigurationManager.AppSettings["RequiredAccount"])).ToList();
}
return new DSUserInfo()
{
Sub = (string)result["sub"],
Name = (string)result["name"],
Email = (string)result["email"],
Accounts = accounts
};
}
public class DSUserInfo
{
public string Sub { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public List<Account> Accounts { get; set; }
}
public class Account
{
public string AccountName { get; set; }
public string AccountId { get; set; }
public string BasePath { get; set; }
public bool IsDefault { get; set; }
}
}
Note that accounts that are joined to an organization will have a few extra data points at the account level. Here's an example account object that's tied to an organization:
{
"account_id": "08b4799a-xxxx-xxxx-xxxx-b5b4b8a97604",
"is_default": false,
"account_name": "ExampleOrgAccount",
"base_uri": "https://demo.docusign.net",
"organization": {
"organization_id": "0da0a9c0-xxxx-xxxx-xxxx-05a0fe6aa5c4",
"links": [
{
"rel": "self",
"href": "https://account-d.docusign.com/organizations/0da0a9c0-xxxx-xxxx-xxxx-05a0fe6aa5c4"
}
]
}
}
As always, we do recommend testing in the developer environment to make sure your application is compatible with the widest variety of potential situations. If you need assistance setting up multiple developer accounts, feel free to reach out to Docusign Support. Either way, see you next time!
Additional resources
Related posts