Skip to Content
Technical Articles
Author's profile photo Dhiraj Kumar

Authenticate Docusign APIs By JWT OAuth Grant Mechanism In Cloud Integration

Docusign is a digital transaction platform that lets users send, sign and manage legal documents securely in the cloud. Docusign has the following authentication mechanism currently supported.

  1. Authorization code grant
  2. Implicit Grant
  3. JSON Web Token Grant

In this post, I will be demonstrating the generation of Docusign OAuth using JWT grant mechanism in cloud Integration tool. Advantages of this technique includes RSA key pair consisting of public-private key pair which provides great data security and management of large users at organizational level. The prerequisites before token generation includes following steps to be completed in Docusign Admin console.

  1. Generation of Integrator key also known as Client ID(iss).
  2. GUID format of user granting access permissions(sub).
  3. RSA public & private keys generation.

The integration flow for this process is given below.

Integration%20Flow

Integration Flow

The integration flow consists of 4 basic steps.

  1. In the first step, the token properties are stored in the message property which consists of public and private key in plain text format, iss, sub, aud, exp and scope as signature impersonation as shown below.Message%20Properties
  2. In the second step, there is a groovy code to generate JSON web token by utilizing java.security libraries as shown below.
    import com.sap.gateway.ip.core.customdev.util.Message;
    import java.util.HashMap;
    
    import java.io.IOException;
    import java.io.BufferedReader;
    import java.io.FileReader;
    import java.util.Date;
    import java.security.GeneralSecurityException;
    import java.security.KeyFactory;
    import java.security.interfaces.RSAPrivateKey;
    import java.security.interfaces.RSAPublicKey;
    import java.security.spec.X509EncodedKeySpec;
    import java.security.spec.PKCS8EncodedKeySpec;
    
    import org.apache.commons.codec.binary.Base64;
    
    import com.auth0.jwt.JWT;
    import com.auth0.jwt.interfaces.DecodedJWT;
    import com.auth0.jwt.algorithms.Algorithm;
    
    def Message processData(Message message) {
        
           map = message.getProperties();
           exp = map.get("exp");
           aud = map.get("aud");
           scope = map.get("scope");
           iss = map.get("iss");
           subject = map.get("subject");
           accountNo = map.get("accountNo");
           contentType = map.get("contentType");
           accept = map.get("accept");
           privateKey = map.get("privateKey");
           publicKey = map.get("publicKey");
           
           java.security.Security.addProvider(
    		         new org.bouncycastle.jce.provider.BouncyCastleProvider()
    		         );
    		         
    	   // Read private key from property
    		RSAPrivateKey privKey = getPrivateKey(privateKey);
    		// Read public key from property
    		RSAPublicKey pubKey = getPublicKey(publicKey);
    		// Create RSA algorithm from keys
    		Algorithm algorithm = Algorithm.RSA256(pubKey, privKey);
    		// Get epoch time
    		long currentTimeMs = System.currentTimeMillis();
    		Date issuedAt = new Date(currentTimeMs);
    		// Get expiration time with validity of 1 hour
    		long expiryTimeMs = currentTimeMs + Integer.parseInt(exp) * 3600000;
    		Date expiresAt = new Date(expiryTimeMs);
    		// Create JWT for impersonation
    		String token = JWT.create()
    				.withIssuer(iss)
    				.withSubject(subject)
    				.withIssuedAt(issuedAt)
    				.withExpiresAt(expiresAt)
    				.withAudience(aud)
    				.withClaim("scope", scope)
    				.sign(algorithm);	         
    		         
    		         
           message.setBody(token)
           
           return message;
    }
    
    
    public static RSAPrivateKey getPrivateKey(String privKey) throws IOException, GeneralSecurityException {
    	    
    	    return getPrivateKeyFromProperty(privKey);
    	    
    	}	
    
    
    public static RSAPrivateKey getPrivateKeyFromProperty(String key) throws IOException, GeneralSecurityException {
    	    String privateKey = key;
    	    privateKey = privateKey.replace("-----BEGIN RSA PRIVATE KEY-----", "");
    	    privateKey = privateKey.replace("-----END RSA PRIVATE KEY-----", "");
    	   
    	    byte[] encoded = Base64.decodeBase64(privateKey);
    	    KeyFactory kf = KeyFactory.getInstance("RSA");
    	    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
    	    RSAPrivateKey privKey = (RSAPrivateKey) kf.generatePrivate(keySpec);
    	    return privKey;
    	}
    
    
    public static RSAPublicKey getPublicKey(String pubKey) throws IOException, GeneralSecurityException {
    	    
    	    return getPublicKeyFromProperty(pubKey);
    	}
    	
    	
    public static RSAPublicKey getPublicKeyFromProperty(String key) throws IOException, GeneralSecurityException {
    	    String publicKey = key;
    	    publicKey = publicKey.replace("-----BEGIN PUBLIC KEY-----", "");
    	    publicKey = publicKey.replace("-----END PUBLIC KEY-----", "");
    	    
    	    byte[] encoded = Base64.decodeBase64(publicKey);
    	    KeyFactory kf = KeyFactory.getInstance("RSA");
    	    RSAPublicKey pubKey = (RSAPublicKey) kf.generatePublic(new X509EncodedKeySpec(encoded));
    	    return pubKey;
    	}
    ​

    The following external jars has to be added in the resources section of the integration flow.Libraries

    Libraries

  3. Trigger a POST HTTP request to the Docusign authentication service with the following message body where ${in.body} is the JWT token generated from previous groovy step grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=${in.body}. Add a Content-Type header with value application/x-www-form-urlencoded.
  4. Request-Reply step to Docusign authentication service as shown below.HTTP%20Call

The integration flow has been configured and deployed successfully and now it is time to test our implementation from postman.OAuth%20Token%20Response

OAuth Token Response

As seen above, the OAuth Bearer token has been generated with expiry duration of an hour successfully for authenticating Docusign APIs. Copy the generated JWT token from the monitoring.JWT%20Token

JWT Token

 

Now lets analyze the  JWT token generated by the script step with the help of jwt.io website. jwt.io

jwt.io

So in this post we have learnt how we can generate JWT token, which we can further use to generate OAuth tokens to authenticate Docusign APIs. In the next article I will be demonstrating the steps as part of calling the envelopes API which is used in signing process for documents.

Following are the links for reference.

  1. Docusign JWT Grant Documentation –  https://developers.docusign.com/platform/auth/jwt/jwt-get-token/
  2. JWT Debugger – https://jwt.io/
  3. Integrator Key – https://www.youtube.com/watch?v=GgDqa7-L0yo
  4. Docusign Trial Account – https://go.docusign.com/o/trial/
  5. SAP BTP Products Trial – https://www.sap.com/products/free-trials

Assigned Tags

      Be the first to leave a comment
      You must be Logged on to comment or reply to a post.