Laravel

Embedded signing DocuSign laravel

Hello everyone, today we will see how we can do an embedded signing with Docusign in Laravel 8. If you are reading my blog which means you also want to integrate DocuSign with your Laravel Application. Please follow the below instruction to integrate Docusign in one shot.

To integrate Docusign in Laravel, we will follow below steps:

  1. Create a developer account on DocuSign
  2. Create an application and get the keys on DocuSign
  3. Install laravel project
  4. Install Docusign Package
  5. Setting up .env with DocuSign keys
  6. Create Routes
  7. Create Controller
  8. Create Blade File
  9. Test the integration

Step: 1 Create a developer account on DocuSign

To create the developer account on Docusign please click here. this link will redirect you to docusign developer account, you will have something like the below image.

Docusign create account

After the registration, you will receive an account verification email on your registered email, verify that email and proceed.Once you logged in you have image like the below one.

Docusign app and key section

From this section we need API Account ID, please copy API Account ID and place it in safe place we will use it later.

Step: 2 Create an application and get the keys on DocuSign

Now click on ADD APP AND INTEGRATION KEY button to create a new application.

docusign create app

Once you create the app you can see something like the below image.

From here you have to copy integration key and secret key and keep it in a safe place we will use it later.

Step: 3 Install laravel project

Open your command prompt under your htdocs and run the below command

composer create-project laravel/laravel laravel-docusign

Step: 4 Install Docusign Package

Composer require docusign/esign-client

Step: 5 Setting up .env with Docusign keys

Add the below in your .env file, and then run php artisan optimize:clear

DOCUSIGN_BASE_URL=https://demo.docusign.net/restapi
DOCUSIGN_ACCOUNT_ID=Your API Account ID
DOCUSIGN_CLIENT_ID= Your Integrator key
DOCUSIGN_CLIENT_SECRET=Your secret key

Step:6 Create routes

Create routes for the docusign add the below route in your routes/web.php file.

Route::get('docusign',[DocusignController::class, 'index'])->name('docusign');
Route::get('connect-docusign',[DocusignController::class, 'connectDocusign'])->name('connect.docusign');
Route::get('docusign/callback',[DocusignController::class,'callback'])->name('docusign.callback');
Route::get('sign-document',[DocusignController::class,'signDocument'])->name('docusign.sign');

Step: 7 Create Controller

Now we will create a controller for our routes, to create the controller run the below command in your terminal from the project root folder.

php artisan make:controller DocusignController

After creating the controller add the controller namespace in your routes/web.php file on the top.

use App\Http\Controllers\DocusignController;

see the below image, how my routes.php looks like

docusign routes in laravel application

Now add the below code in your DocusignController.php file

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use DocuSign\eSign\Configuration;
use DocuSign\eSign\Api\EnvelopesApi;
use DocuSign\eSign\Client\ApiClient;
use Exception;
use Session;

class DocusignController extends Controller
{   
    
     /** hold config value */
     private $config;

    private $signer_client_id = 1000; # Used to indicate that the signer will use embedded

    /** Specific template arguments */
    private $args;


    /**
     * Show the html page
     *
     * @return render
     */
    public function index()
    {
        return view('docusign.connect');
    }


    /**
     * Connect your application to docusign
     *
     * @return url
     */
    public function connectDocusign()
    {
        try {
            $params = [
                'response_type' => 'code',
                'scope' => 'signature',
                'client_id' => env('DOCUSIGN_CLIENT_ID'),
                'state' => 'a39fh23hnf23',
                'redirect_uri' => route('docusign.callback'),
            ];
            $queryBuild = http_build_query($params);

            $url = "https://account-d.docusign.com/oauth/auth?";

            $botUrl = $url . $queryBuild;

            return redirect()->to($botUrl);
        } catch (Exception $e) {
            return redirect()->back()->with('error', 'Something Went wrong !');
        }
    }

    /**
     * This function called when you auth your application with docusign
     *
     * @return url
     */
    public function callback(Request $request)
    {
        $code = $request->code;

        $client_id = env('DOCUSIGN_CLIENT_ID');
        $client_secret = env('DOCUSIGN_CLIENT_SECRET');

        $integrator_and_secret_key = "Basic " . utf8_decode(base64_encode("{$client_id}:{$client_secret}"));

        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, 'https://account-d.docusign.com/oauth/token');
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        $post = array(
            'grant_type' => 'authorization_code',
            'code' => $code,
        );
        curl_setopt($ch, CURLOPT_POSTFIELDS, $post);

        $headers = array();
        $headers[] = 'Cache-Control: no-cache';
        $headers[] = "authorization: $integrator_and_secret_key";
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

        $result = curl_exec($ch);
        if (curl_errno($ch)) {
            echo 'Error:' . curl_error($ch);
        }
        curl_close($ch);
        $decodedData = json_decode($result);
        $request->session()->put('docusign_auth_code', $decodedData->access_token);
    
        return redirect()->route('docusign')->with('success', 'Docusign Succesfully Connected');
    }

    public function signDocument()
    {       
        try{
            $this->args = $this->getTemplateArgs();

        $args = $this->args;
       

        $envelope_args = $args["envelope_args"];
        
        # Create the envelope request object
        $envelope_definition = $this->make_envelope($args["envelope_args"]);
        $envelope_api = $this->getEnvelopeApi();
        # Call Envelopes::create API method
        # Exceptions will be caught by the calling function

        $api_client = new \DocuSign\eSign\client\ApiClient($this->config);
        $envelope_api = new \DocuSign\eSign\Api\EnvelopesApi($api_client);
        $results = $envelope_api->createEnvelope($args['account_id'], $envelope_definition);
        $envelope_id = $results->getEnvelopeId();

        $authentication_method = 'None'; # How is this application authenticating
        # the signer? See the `authenticationMethod' definition
        # https://developers.docusign.com/esign-rest-api/reference/Envelopes/EnvelopeViews/createRecipient
        $recipient_view_request = new \DocuSign\eSign\Model\RecipientViewRequest([
            'authentication_method' => $authentication_method,
            'client_user_id' => $envelope_args['signer_client_id'],
            'recipient_id' => '1',
            'return_url' => $envelope_args['ds_return_url'],
            'user_name' => 'shaiv', 'email' => 'shaivroy1@gmail.com'
        ]);

        $results = $envelope_api->createRecipientView($args['account_id'], $envelope_id,$recipient_view_request);

        return redirect()->to($results['url']);
        } catch (Exception $e) {
            dd($e);
        }
        
    }


    private function make_envelope($args)
    {   
        
        $filename = 'World_Wide_Corp_lorem.pdf';

        $demo_docs_path = asset('doc/'.$filename);

        $arrContextOptions=array(
            "ssl"=>array(
                "verify_peer"=>false,
                "verify_peer_name"=>false,
            ),
        );  

        $content_bytes = file_get_contents($demo_docs_path,false, stream_context_create($arrContextOptions));
        // dd($content_bytes);
        $base64_file_content = base64_encode($content_bytes);
        // dd($base64_file_content);
        # Create the document model
        $document = new \DocuSign\eSign\Model\Document([# create the DocuSign document object
        'document_base64' => $base64_file_content,
            'name' => 'Example document', # can be different from actual file name
            'file_extension' => 'pdf', # many different document types are accepted
            'document_id' => 1, # a label used to reference the doc
        ]);
        # Create the signer recipient model
        $signer = new \DocuSign\eSign\Model\Signer([# The signer
        'email' => 'shaivroy1@gmail.com', 'name' => 'shaiv',
            'recipient_id' => "1", 'routing_order' => "1",
            # Setting the client_user_id marks the signer as embedded
            'client_user_id' => $args['signer_client_id'],
        ]);
        # Create a sign_here tab (field on the document)
        $sign_here = new \DocuSign\eSign\Model\SignHere([# DocuSign SignHere field/tab
        'anchor_string' => '/sn1/', 'anchor_units' => 'pixels',
            'anchor_y_offset' => '10', 'anchor_x_offset' => '20',
        ]);
        # Add the tabs model (including the sign_here tab) to the signer
        # The Tabs object wants arrays of the different field/tab types
        $signer->settabs(new \DocuSign\eSign\Model\Tabs(['sign_here_tabs' => [$sign_here]]));
        # Next, create the top level envelope definition and populate it.

        $envelope_definition = new \DocuSign\eSign\Model\EnvelopeDefinition([
            'email_subject' => "Please sign this document sent from the CodeHunger",
            'documents' => [$document],
            # The Recipients object wants arrays for each recipient type
            'recipients' => new \DocuSign\eSign\Model\Recipients(['signers' => [$signer]]),
            'status' => "sent", # requests that the envelope be created and sent.
        ]);

        return $envelope_definition;
    }

    /**
     * Getter for the EnvelopesApi
     */
    public function getEnvelopeApi(): EnvelopesApi
    {   
        $this->config = new Configuration();
        $this->config->setHost($this->args['base_path']);
        $this->config->addDefaultHeader('Authorization', 'Bearer ' . $this->args['ds_access_token']);    
        $this->apiClient = new ApiClient($this->config);

        return new EnvelopesApi($this->apiClient);
    }

    /**
     * Get specific template arguments
     *
     * @return array
     */
    private function getTemplateArgs()
    {   
        $envelope_args = [
            'signer_client_id' => $this->signer_client_id,
            'ds_return_url' => route('docusign')
        ];
        $args = [
            'account_id' => env('DOCUSIGN_ACCOUNT_ID'),
            'base_path' => env('DOCUSIGN_BASE_URL'),
            'ds_access_token' => Session::get('docusign_auth_code'),
            'envelope_args' => $envelope_args
        ];
        
        return $args;
        
    }
}

Note: You must have to add callback URL in your docusign , to get your laravel application get authenticated.

See the below image.

Step:8 Create a blade file

Now create a folder named as docusign under your resouces/views under docusign folder create a file connect.blade.php and write the below code in it.

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Docusign Integration Example</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
  <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</head>
<body>
  <div class="container">
    @if ($message = Session::get('success'))
      <div class="alert alert-success alert-block">
          <button type="button" class="close" data-dismiss="alert">×</button>    
          <strong>{{ $message }}</strong>
      </div>
    @endif
    <div class="card">
      <div class="card-header">
        CodeHunger Private Limited
      </div>
      <div class="card-body">
        <h5 class="card-title">Docusign Tutorial</h5>
        <p class="card-text">Click the button below to connect your appication with docusign</p>
        @if ($message = Session::get('success'))
          <a href="{{route('docusign.sign')}}" class="btn btn-primary">Click to sign document</a>
        @else
          <a href="{{route('connect.docusign')}}" class="btn btn-primary">Connect Docusign</a>
        @endif
        
      </div>
    </div>
  </div>
</body>

Step-9 Test the integration

Now visit this url from your browser http://localhost/docusign/public/docusign , you will have something like the below image.

laravel application connect docusign

Click on connect DocuSign, you will redirect to DocuSign’s official website where they told you to enter your DocuSign email and password, after giving your credentials you will come back to your laravel application with the below image.

docusign auth with laravel application

When you click on the button to sign the document you will have something like the below one.

docusign embeded signing

Here click on continue put signature and press finish, after that you embeded signing process is done and you will come back to your laravel application.

docusign embeded signing

After signing process complete you can see something like the below one.

docusign siging process complete

I hope it works for you. please rate me 5 if it helps you.

Shaiv Roy

Hy Myself shaiv roy, I am a passionate blogger and love to share ideas among people, I am having good experience with laravel, vue js, react, flutter and doing website and app development work from last 7 years.

Related Articles

11 Comments

  1. Please help me,
    How I can share same document to multiple signers?
    I want to signed same document from multiple people

  2. file_get_contents(http://127.0.0.1:8000/doc/World_Wide_Corp_lorem.pdf): Failed to open stream: HTTP request failed!
    

    anyone tell me please how i can resolve this issue?

  3. Hi,

    Please help me,

    I got this error :
    
     file_get_contents(http://127.0.0.1:8000/doc/World_Wide_Corp_lorem.pdf): Failed to open stream: HTTP request failed!
    

    I also tried to change the file and even change the file name but it did not work,

    Do you have any idea about this?

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button