DocuSign Developers: A Look Inside the New Authentication APIs

The following blog posts discusses a new set of features scheduled to be slowly released in May and June. Since it discusses unreleased features, there may be small changes in the APIs and user interfaces before they are made broadly available.

Hello Developer Community! My name is Brian Wishan and I lead the engineering team responsible for our identity and authentication systems here at DocuSign. With Momentum 2017 around the corner, I'm excited to share a new set of authentication features that you'll be able to use to help build your applications with the DocuSign API.

Before we get into the new stuff, I wanted to take a moment to review what we’ve built in the last year and explain some of the thought behind it. In early 2016, we launched our new authentication service. We had two primary goals in building the new system, 1) providing a foundation for the evolution of identity and authentication at DocuSign, and 2) providing a familiar set of tools that the developer community can build upon for their own integrations. The new platform introduced enhanced support for our customers to use federated identity with the industry standard OAuth 2.0 protocol. The authentication platform was built with the future in mind. The authentication layer is only one part of building a defense-in-depth strategy for the DocuSign platform, and authentication is one of the first places attackers and fraudsters poke at when looking to exploit online services. The threat landscape in this space is continually changing and having the ability for an authentication system to change just as quickly, to counter new threats, is critical for us to be able to grow the trust you put in using us for your digital transaction management needs.

Why we chose OAuth 2.0 and OpenID Connect

Our choice to support OAuth 2.0 and OpenID Connect goes beyond their use as industry standards. They provide a simple framework that enables us to continually innovate on how we allow users access to the system without asking our developer community to make changes to their applications to support these new features.

The OAuth 2.0 protocol provides a well-defined developer contract for initiating and completing an authentication request. From an integration perspective, you’re required to understand two things: how to initiate an authentication and how to respond to the callback when it’s completed. We think of what happens in the middle as being a black box, or something that you as a developer don’t have to worry about.

So, what do I mean by this? Let me give you an example. When we originally launched the new login server, we needed the ability to support federated identity through the SAML 2.0 protocol in addition to traditional password authentication. We wanted these services to be available not only to our first party applications, but to all your applications as well. The challenge with typical RPC or REST-style programming models is that APIs need to be designed with a backwards compatibility strategy in place. Breaking an API to support new features is generally a non-starter as it requires our entire ecosystem to make changes to their integrations for things to continue working for all users. For example, if we used the following hypothetical API to obtain an access token:

POST /login  HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache

The response might look something like this:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 63
   "user_id": "12345",
   "access_token": "dAb4z9dd3a"

And an error response might be simply an HTTP status code of 403 representing the request was understood but not authorized. Later, if we tried to evolve this API to now support that a user requires login via federated identity, a response might look like this:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Content-Length: 63
   "error": "user_requires_federated_identity"

Understanding that the specific error response in the above example would mean that your application would have to make changes, not just in error handling, but in supporting a new authentication method with additional API calls to facilitate this new method. Clearly, building code to support these types of flows isn’t where you want to be investing your development cycles.

Instead, the use of OAuth 2.0 provides the ability for the evolution of our authentication services to change without requiring you to make changes to your code. The below diagram describes how our front page allows a user to log into DocuSign without having to worry about what security policies apply to a given user.

From a developer perspective, the contract we put in place is knowing how to construct your start URI and knowing how to understand the response on the stop URI, which is a location hosted on your servers (or a callback within your native application).

In the next month, we will be rolling out global support for two-step verification, allowing our customers to add additional authentication methods to their accounts to avoid the common problems with passwords. When you turn on two-step verification, a new challenge will be displayed during the login process. Since this happens between the start URI and the stop URI, it's transparent to your applications. Over time we will be launching new security features, both those that are visible to users logging in and those that run behind the scenes, watching and protecting access to your most trusted data. This platform will ensure that as our system grows, we won't have to ask you, the developer community, to make changes each time to keep up.

We will continue to invest in new dynamic security features to protect unauthorized access to your accounts and we plan to leverage this framework to make that possible while keeping your applications running without changes.

Authentication Options for Different Types of Integrations

We find that most of the integrations with our APIs fall into one of two categories; user integrations and service integrations. We think of user integrations as the type of applications that interact directly with a user present. Applications like our mobile applications, have a button that initiates a login flow and then completes the OAuth dance obtaining an access token that can be used to call the DocuSign APIs. The user being present is important so that they are successfully able to complete identity challenges like using their company credentials via SAML 2.0 federation or verifying their identity via a second factor. Without the user being physically present to interact with the challenges, we won’t issue an authentication token.

Of course, not all applications have the ability for a user to interact with the login server directly. Some of these applications might have deep integration into a CRM system where end-users don’t interact with DocuSign directly but instead, the integration sends envelopes on their behalf or creates links to sign document. Or perhaps work is queued up in a job system and is processed nightly. To support these types of applications we will be introducing a new set of authentication APIs that provide organizations the same level of control they have in managing user identity while enforcing their own security policies without having to use passwords.

Application Identity

To have an integration with DocuSign, you’re required to obtain an integrator key (also known as an OAuth client id). The integrator key identifies your application to DocuSign and provides you the ability to make API calls when you have a user token. When using the OAuth flows, a user must provide consent to your application to make calls to the APIs on their behalf and their consent is tied to your integrator key. Users can also revoke this consent at any time. But integrator keys can’t do much on their own without a user credential. To support richer integrations and a new upcoming set of APIs, we’re going to enable applications to have a first-class identity of their own. Applications will be able to request access tokens that represent the application itself instead of a user (or a dedicated service user) in an account. Select new APIs will be able to be called without an end-user token. This will eventually eliminate challenges with today’s integrations where an accounted user (or service user) was required to be a member of the sending account to perform API calls. Through another new set of APIs, applications will be able to request act-as (or impersonation) tokens that represent an individual user, like how the existing Send-on-behalf-of (SOBO) functionality works today. More on this below.

Impersonation Scope and Requesting Act-As Tokens

With our upcoming release, we’ll be launching support for the impersonation scope, allowing applications to request tokens with their application credentials that allow them to act as a specific user in the system. Before an application can request an access token for a user, that user must approve that application to access its data and resources. We call this granting consent. There will be two ways in which consent can be granted; either directly by the end-user themselves, or by an administrator of an Organization on behalf of all users in their list of reserved domains. The former is available today and the latter is coming soon.

User and Admin OAuth Consent Flows

First, a little about DocuSign Organizations. A DocuSign Organization is a collection of accounts typically managed by a common administrator or company. The feature set was introduced last year with our enhanced support for SAML 2.0 and provided the ability for certain configuration objects to be managed and shared across organizations. Organizations provide centralized management of identity providers and registered e-mail domains. Over the next couple months, we will be releasing a set of new capabilities to Organizations making it easier for you to centrally manage DocuSign when you have multiple accounts.

Now back to talking about identity. The process of verifying an e-mail domain gives the Organizational Administrator the ability to control users in that domain, for example, all users with an e-mail. An instance of this is allowing a federated identity provider the ability to assert identity over a user and log them into the system. Or apply a security policy that all users with an e-mail address must use the federated identity provider instead of a password.

Normally, the first time a user interacts with an application, they see a dialog like the following:

Clicking the Accept button authorizes the system to give Bindord Customer Relationship Manager, an application inside the Bindord Tools account, an access token which can then be used to make API calls on the user’s behalf. The bulleted list describes the specific permissions being requested. These are represented to the developer as scopes in the OAuth start URI, but described in text in the dialog. For example, this request may have used a URL that looks like the this:

Organization Administrators will have the ability to grant consent to all of the users in who are members of their domains. When this first rolls out, we’ll support the ability to consent to an application owned by one of the accounts in your organization, but we’ll soon support the ability for 3rd party applications to request these permissions.

The flow will allow you to select from all the applications in your Organization. Once you’ve selected your application you can choose the set of scopes you wish to consent on their behalf. This can be useful from a user experience perspective where you don’t want your users to see the dialog during their login process.

Once consent has been granted to your application you can later revoke that consent at any time which will prevent future access token grants by using the Actions button on the left.

Impersonation Scope

We’re introducing support for a new scope called impersonation. Applications that request and are granted the impersonation scope will have the ability to request tokens for a specific user without them being present. In other words, after consent has been granted, either by end-users themselves or by an Organization Administrator, the application will have the ability to request new tokens directly via an API call instead of having to use the browser-based OAuth code and token flows.

The impersonation scope can be specified on the OAuth Start URI or via the Admin consent flows described above. Remember, the scope parameter is a space delimited list of scopes, so a start URI asking for the signature and impersonation scope would look like this:

The impersonation scope can also be supplied via the Connected Applications dialog in the Organization management section of the DocuSign Admin tool.

Once the consent has been granted for the impersonation scope, applications will be able to request tokens to act-as a user. The tokens returned from an act-as request can be used just like a traditional access token via the standard Authorization header.

Requesting an act-as token uses a signed JSON Web Token (JWT) (commonly pronounced as “jot”) as described in RFC 7523. A JWT is a small, URL-safe mechanism to transfer claims from your application to our systems. A JWT is logically comprised of three components; a header, a set of claims and a signature. Each section is base64url encoded and concatenated by a '.' (dot).

The JWT format allows for myriad cryptographic algorithms for signing and encryption. For the purposes of requesting an act-as token, applications will need to use the RS256 algorithm which uses the RSASSA-PKCS1-v1_5 SHA-256 digital signature. Libraries are available for creating signed JWTs in almost every major language but below is a brief overview of how to construct a JWS. Before we jump into talking about constructing signed JWTs, let’s take a look at the APIs for key management. Being able to sign a JWT with the RS256 algorithm requires an RSA key. Requesting a new key is as simple as obtaining an access token and making a POST to the keys endpoint for your client application. Managing app keys requires a new scope, manage_app_keys which must be requested when getting your access token for the following call. Note: You must also be the account administrator of an account that manages the Integrator Key in order to request the new key.
POST /v1/applications/feb8892b-4160-4a3e-8ad0-8a9a172c86ac/keys HTTP/1.1
Authorization: Bearer eyJ0eXAiOiJNVCIsImFsZyI6IlJTMjU2Iiwia2lkIjoiMDM3ZmM0ZmMtODZmYi00ODg2LTg5ODAtZjg4N2E1NDA0YTk5In0.AQoAAAABAAUABwAAggX64YLUSAgAAOrJW-qC1EgCAKEibI8GEthGpJI9qpzeYvUNACQAAABmZWI4ODkyYi00MTYwLTRhM2UtOGFkMC04YTlhMTcyYzg2YWMVAAEAAAASAAAAAAAYAAEAAAAFAAAAIAAAggX64YLUSCMAJAAAAGZlYjg4OTJiLTQxNjAtNGEzZS04YWQwLThhOWExNzJjODZhYw.cd2jbobmXT9Y_PfOPP2G99ql6zY2NlVI1ohBYfZTvU6utJG536aYaMuabSXNDZFgH6qQT2ShP-bUc44du0ojiDuA3HaN5Fo-mA0h0sXPpIil-oofLPceo6UxhHx4ofYznfPR2fsHgvwXfEekwFQ3KRM8qaaox9_QBkJ2w2m_Gqh3oVIDhKhq4klO-nA3sPiJUCC_MMUQ6DJ_dHpiLufjj3PgqEMaMSPlxd-hVUx8--R8zCLIYCptlP9hdsxClkAGUaf7dCa0y_hxl6Le510lvK5J4YatfiYLUAFPoeNWTo1-PzaE8A9vmLhhjPki_wKt04kRvizV9syhMs2TcpGGPw
Content-Type: application/x-www-form-urlencoded

The server will respond with an RSA public/private key pair in the following JSON structure:

    "client_id": "feb8892b-4160-4a3e-8ad0-8a9a172c86ac",
    "key_id": "348ec40e-6ad5-4fae-b977-6d9fe011ca32",
    "key_size": 2048,
    "private_key": "-----BEGIN RSA PRIVATE KEY-----\r\nMIIEowIBAAKCAQEA8pTMKTpwLiO9Ib0hRlglYQTVbJFzjSeJLQDYFVlxgRshACMn\r\nZuRxkLvG9PO8lTr0ar2U54J55Aoucyu10qAOq4tCyTWA7aQI1RCa2eCaqmDEN6pU\r\nVXTO7pNh//IB4ThaZtK/lVxAJ5qmIYl9Evfim3CJMp6by/kiMwB7xP8gGHfUI9rQ\r\nFANbQkfyk2WLkH0UtnF5PEzJFK+bnFjeX6ttYSXHVLThTsitZrVPY14fv76Ku1wk\r\nhih35Rr7D+jr2ydZbkOp89TJrb37MGXsjnDNs2QqZB6YQNcCXYKv03V3sV8b6j5H\r\nhFr9UjGOMLzNEO4cHh4DqV6k28w4EteOuFmuOwIDAQABAoIBACfjeNjUr6qenNSF\r\n7YlMKEVWTqPuHPKajC92wpFsJkJlDB2iKjH8oYH7pqETzTA6xAMjTm9tII7zb6Tn\r\njJvoTtE9cot0fVFWVk92zgfCq5wVkl5W50wwC3DmkkhMaqu2oQLkZ7VvOGtqviOo\r\noIT0dvI5ZI4Kz7KQMmPxkeiYTRZImAP8yYrj8Te7bFxkXe9IHgI8Xhoeb0im/A+8\r\nW46IuO31T/U6aYoPKazXRs1HqyHpJYAee8H53kOZGiYiCBd9dNCJsT9bovwM0Ccb\r\nCRSJp3NimN66QAY2CwigdtKHlRFf773cm31Tw1V4pQLnAp8Sb2TB1CC75CuJhxTl\r\nh8WyNa0CgYEA/nYQDGyudHD3kjNH8sco3WRY21ACbzgUH4W3bgQTOumOH+16L91D\r\n9zGzKVDVjf9QdZ5N43vRzDLpszRwZ1PDddfvFGBs/7X536kaQgfY3NVgXxZNHuIA\r\nnFXligsjudvMWBQmI8OfTYxGyiWdhMUrzXW2nGjw6N8IH99JvV9Q/fUCgYEA9AxX\r\n29UYxi96HMu101P864VNyQoULd1cdOKhycym1NGw3EIOHyWCGt7WO8WH9Csb3f6j\r\nJNf8axIATZax0n5ZoZ5fFtn5PC3ozgdJAEfu38AkKqyWaYbK3xJBnogEBgERvyY/\r\novPiZ3G6e74nejpSOumbcTcv9fC6rDYOuO8JrW8CgYEApcutJztE6++TD3pEPcZQ\r\nNPgmATd/bpH+Yo+QdalIElGM3fawbzFfEFgcoSXfDzc0aH5tx3OsvbzKko3vUxO7\r\nvjOkvgUZ3/7kwTsANdfBEBojQbFZLG8a8MHy3l/ltjqlSRpPw2u5hyCIGzwpBxIl\r\nOSiihATIOyLeu02UUUQilGUCgYBcPx4mlhHbN67sm4OK8cA0NhsE1q5x964u8Es/\r\nP///iZNUbhNwankXNwu7ZBrTjEfoTYvVLV7YCeHbcg6dBe1TTc2bkaDHwoKw/cf2\r\nNzpvkO0axEnGcZDVaM0s4zTCID1ZB1gefBkkCLT4eRPq+4iBhDOhQ775M5kb5wMB\r\nnDkIOQKBgCi+tqBvoR01GrRPt9FepcC4vF73JYLszOjkGJ3cdGSoTN3HO+1zP4sB\r\n1PihxL62kfy8qFVdShCyuAqqKgiJ/tXy9oSwxHPbTDBv5eHb/uAmT0VGziyHbcqn\r\nHz+LcvTgC2jXNpCUEIIg1Bqo8auE1nqa7NbbWAm7rFO0KjGkN6uf\r\n-----END RSA PRIVATE KEY-----\r\n",
    "public_key": "-----BEGIN PUBLIC KEY-----\r\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8pTMKTpwLiO9Ib0hRlgl\r\nYQTVbJFzjSeJLQDYFVlxgRshACMnZuRxkLvG9PO8lTr0ar2U54J55Aoucyu10qAO\r\nq4tCyTWA7aQI1RCa2eCaqmDEN6pUVXTO7pNh//IB4ThaZtK/lVxAJ5qmIYl9Evfi\r\nm3CJMp6by/kiMwB7xP8gGHfUI9rQFANbQkfyk2WLkH0UtnF5PEzJFK+bnFjeX6tt\r\nYSXHVLThTsitZrVPY14fv76Ku1wkhih35Rr7D+jr2ydZbkOp89TJrb37MGXsjnDN\r\ns2QqZB6YQNcCXYKv03V3sV8b6j5HhFr9UjGOMLzNEO4cHh4DqV6k28w4EteOuFmu\r\nOwIDAQAB\r\n-----END PUBLIC KEY-----\r\n"

The keys are returned using the Privacy-enhanced Electronic Mail (PEM) format, which are Base64 encoded DER certificates. The private key is used for signing the JWT and should be protected in accordance with your existing security policies. The private key is a stronger equivalent of your password for your application and it’s the only credential that can be used when requesting act-as tokens. You can find tools on almost any major platform for working with PEM encoded cryptographic keys as well as tools on the web to help you construct JWTs in a browser.

Creating the JWT Header

To construct your signed JWT (JWS), we require a header specifying the token type (identified by the typ parameter) as a JWT and an algorithm parameter of RS256.

The base64url representation of the header is

Creating the Act-As Body

In order to request an act-as token, a set of required claims must be supplied in the body of the request:

Name Description Required
iss The issuer of the JWT. In all cases this should be the integrator key or client identifier for your application Yes
sub The user id of the principal you are requesting a token for. If omitted a token will be issued to represent the application itself instead of a user in the system. No
iat The time the assertion was issued. Specified as the number of seconds since the Unix epoch (January 1, 1970). Yes
exp The expiration date of the token. Specified as the number of seconds since the Unix epoch (January 1, 1970). We will respect a maximum time of 1 hour, however will honor shorter expiration times as defined by this claim. Yes
aud The hostname of the login server for the respective environment. (i.e., Yes
scope The list of space delimited scopes being requested in this token (i.e. signature). This is the same as the list used in a traditional OAuth flow. Yes

An example body would look like:


The base64url representation of the body would look like this:


Calculating the Signature

To create the signature, you must first construct the header and then base64url encode it. Then construct the body and base64url encode it. Concatenate these two segments with a '.' and then compute the signature over those values.

Once the signature has been computed, base64url encode the resultant bytes and concatenate it with the input, forming the following structure:

A fully constructed JWT will look like the following:

Once the JWT has been constructed, it’s now time to POST it against the token endpoint to request an access token.

The JWT Bearer Token Grant Type

Like the authorization_code and ­refresh_token grant types, an example JWT bearer token request looks like this:

POST /oauth/token  HTTP/1.1
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache

The server will respond with an access token that can be used for making API requests as the user specified in the subject of the JWT.

    "token_type": "Bearer",
    "expires_in": 3600

The token returned can now be used in any API that accepts a user token, such as the OAuth UserInfo endpoint.

GET /oauth/userinfo  HTTP/1.1
Cache-Control: no-cache

And the server will response as if the user made the request directly.

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
Expires: -1
X-DocuSign-TraceToken: edd754b1-9600-4419-a307-facd90071e9e
Content-Length: 828
   "accounts": [
           "account_id": "49c8b130-69bd-4010-87b9-008ba29a3a27",
           "account_name": "Bindord Tools",
           "base_uri": "",
           "is_default": true,
           "organization": {
               "links": [
                       "href": "",
                       "rel": "self"
               "organization_id": "b9d1f0ff-2172-4ad5-a632-0166b57b35c7"
   "created": "2015-11-02T19:02:46.17",
   "email": "",
   "family_name": "User",
   "given_name": "End",
   "name": "End User",
   "sub": "8f6c22a1-1206-46d8-a492-3daa9cde62f5"

This new functionality should make it easier than ever before to build applications with the DocuSign API.

Come say hi to me at Momentum 2017 where I’ll be giving two talks in the Developer track. One covering authentication and another one that takes a behind the scenes look at the engineering infrastructure that powers DocuSign.

Developers can attend the conference (and my session) for free by registering here. Look forward to seeing you there.