DocuSign Implicit Grant v1
This example implements the OAuth Implicit grant flow, and retrieves the user's information via the /userinfo endpoint. See my Medium article XXX for more information.
by Larry Kluger
HTML
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.2/css/bootstrap.min.css">
<div id="content">
<h1>OAuth Implicit Grant</h1>
<section id="spinner" class="hide">
<div class="spinner">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
</section>
<div id="login">
<a id="btnOauth" class="btn btn-primary"
type="button" role="button">
Login with DocuSign</a>
<p class="mt-3">
Use your DocuSign Developer Account. Don't have one?
<a href="https://go.docusign.com/o/sandbox/?utm_campaign=GBL_XX_DEV_NEW_2208_ExternalProgrammingTools&utm_medium=display&utm_source=jsfiddle" target="_blank">Free signup!</a>
</p>
<p><a href="https://javascript.plainenglish.io/oauth-implicit-grant-for-single-page-applications-jsfiddle-and-codepen-10c2c7946f05" target="_blank">Medium article</a></p>
</div>
<div id="msg">
</div>
<div id="fetch" class="hide">
<a id="btnFetch" class="btn btn-primary"
type="button" role="button">
Fetch data</a>
</div>
<div id="notSecure" class="hide">
<p class="text-danger">Error: this page is using HTTP.</p>
<p class="text-danger">Solution: reload this page using HTTPS.</p>
</div>
<div id="oauthResults" class="hide">
<h3>OAuth Results</h3>
<div class="panel-body"></div>
</div>
<div id="results" class="hide">
<h3>Fetch Results</h3>
<div class="panel-body"></div>
</div>
</div>
CSS
pre {
text-align: left;
background-color: aliceblue;
font-size: smaller;
margin: 15px;
}
h1, h2, h3 {margin-top: 1.5em;}
#content {
text-align: center;
}
#content p {
padding: 0 25px 0 25px;
}
#demo {
display: none;
}
#raw_data {
text-align: left;
}
#demo img {
height: 64px;
width: 64px;
border-radius: 50%;
}
.panel {
margin: 50px 75px;
}
.hide {
display: none;
}
/* From http://tobiasahlin.com/spinkit/ */
.spinner {
margin: auto;
width: 150px;
height: 140px;
text-align: center;
font-size: 10px;
}
.spinner > div {
background-color: blueviolet;
height: 100%;
width: 6px;
display: inline-block;
-webkit-animation: sk-stretchdelay 1.2s infinite ease-in-out;
animation: sk-stretchdelay 1.2s infinite ease-in-out;
}
.spinner .rect2 {
-webkit-animation-delay: -1.1s;
animation-delay: -1.1s;
}
.spinner .rect3 {
-webkit-animation-delay: -1.0s;
animation-delay: -1.0s;
}
.spinner .rect4 {
-webkit-animation-delay: -0.9s;
animation-delay: -0.9s;
}
.spinner .rect5 {
-webkit-animation-delay: -0.8s;
animation-delay: -0.8s;
}
@-webkit-keyframes sk-stretchdelay {
0%, 40%, 100% { -webkit-transform: scaleY(0.4) }
20% { -webkit-transform: scaleY(1.0) }
}
@keyframes sk-stretchdelay {
0%, 40%, 100% {
transform: scaleY(0.4);
-webkit-transform: scaleY(0.4);
}
20% {
transform: scaleY(1.0);
-webkit-transform: scaleY(1.0);
}
}
JavaScript
// Copyright © 2022 DocuSign, Inc.
// License: MIT Open Source https://opensource.org/licenses/MIT
// Set basic variables
const oAuthServiceProvider = "https://account-d.docusign.com";
const implicitGrantPath = "/oauth/auth";
const userInfoPath = "/oauth/userinfo";
// Client IDs are NOT secrets. See
// https://www.rfc-editor.org/rfc/rfc6749.html#section-2.2
const oAuthClientID = "d70c3a89-97b9-48d1-8bf3-5401cbbd6f82";
const oAuthScopes = "signature";
const oAuthReturnUrl = "https://docusign.github.io/jsfiddleImplicitGrantReturn.html"
const eSignBase = '/restapi/';
debugger; // uncomment with debugger open to find the right JS file.
/*
* ImplicitGrant handles the functionality of the implicit grant flow
*
* It opens, then later closes, a new browser tab.
* The client app must call handleMessage when the window receives a message event
*
* args -- an object containing attributes:
* oAuthServiceProvider
* implicitGrantPath
* oAuthClientID
* oAuthScopes
* oAuthReturnUrl
* workingUpdateF -- function called when working state changes
*
* public values
* .errMsg -- null or contains the error information
* .working -- is the implicit grant flow in process?
* .accessToken -- the access_token or null
* .accessTokenExpires -- a Date object or null
*/
class ImplicitGrant {
constructor(args) {
this.oAuthServiceProvider = args.oAuthServiceProvider;
this.implicitGrantPath = args.implicitGrantPath;
this.oAuthClientID = args.oAuthClientID;
this.oAuthScopes = args.oAuthScopes;
this.oAuthReturnUrl = args.oAuthReturnUrl;
this.workingUpdateF = args.workingUpdateF || null;
// public variables
this.working = false;
this.accessToken = null;
this.accessTokenExpires = null;
this.errMsg = null;
// internal
this._loginWindow = null;
this._nonce = null;
}
async login() {
this.working = true;
this.errMsg = null;
if (this.workingUpdateF) {
...