Docusign run code grant steps programmatically in node? - node.js

New to docusign and have been reading the docs, and I can't seem to get around these problems.
Per the docs it says that gets a code getAuthorizationUri() which can then be used by generateAccessToken() to get a token. After that, the token can be used to explore the API with other methods.
I'm stuck in two places: First I configured my get Authorization like this (typescript)
import { ApiClient } from 'docusign-esign'
const apiClient = new ApiClient()
const url: string = apiClient.getAuthorizationUri(
config.docusign.INTERGRATION_KEY,
['signature'],
'http://localhost/',
'code',
'ready'
)
console.log(url)
I get the url fine, but it is always starts with acccounts.docusign as opposed to the required account-d.docusign that's required because my app is in dev.
Secondly, I can't figure out how to transition that URL into a code programtically. Yes, I can copy and paste it from the browser URL (as in the instruction videos), but obviously my next step is to run something like:
async getToken(authCode){
const token = await apiClient.generateAccessToken(
INTERGRATION_KEY,
SECRET_KEY,
authCode
)
console.log(token)
return token
}

To change authentication from prod to demo, you need to make this call:
apiClient.setOAuthBasePath("account-d.docusign.com");
You may also want to change the URL for API calls if you use this later like this:
apiClient.setBasePath("https://demo.docusign.net/restapi");
I suggest using an OAuth npm package and not doing this yourself.
See how it's done in the quickstart (Pick Node.js and Auth Code Grant)

Related

Unable to request click.manage or click.send scopes in Docusign click API

I'm attempting to authenticate a call to Docusign's Click API using the Node SDK. I'm importing the ApiClient through the docusign-click as import { ApiClient } from 'docusign-click';.
My API setup looks like this:
this.apiClient = new ApiClient({
basePath: this.configService.get('DOCUSIGN_CLICKWRAP_BASE_PATH'),
oAuthBasePath: '',
});
and I'm requesting a JWT like this:
const response = await this.apiClient.requestJWTUserToken(
this.configService.get('DOCUSIGN_INTEGRATOR_KEY'),
this.configService.get('DOCUSIGN_USER_ID'),
['click.manage'],
Buffer.from(
this.configService
.get<string>('DOCUSIGN_PRIVATE_KEY')
.replace(/\\n/g, '\n'),
),
30,
);
When I try to request a JWT this way, I get Error: Bad Request. However, when I replace ['click.manage'] with ['signature'] the JWT is generated, so I know the rest of the call is fine.
Is there something else I need to do to allow me to request a click API scope and call to the click API?
Your consent request should also include click.manage and click.send. These are two separate things.
To get consent you need to build a URL that looks like this:
https://account-d.docusign.com/oauth/auth?redirect_uri=[Redirect URL in IK]&scope=click.manage%20click.send&client_id=[YOUR IK]&response_type=code
And simply go to this URL in the browser.
Then make the request for JWT again and it should work.

How do I get the access token without using the browser

When I go to the following URL in the browser with my own client_id:
https://account-d.docusign.com/oauth/auth?response_type=token&scope=signature&client_id=6d1a8594-xxxx-xxxx-xxxx-878e593de049&state=a39fh23hnf23&redirect_uri=http://localhost:8888/auth
I need to login and afterwards I get redirected to:
http://localhost:8888/auth#access_token=myAccessToken&expires_in=28800&token_type=bearer&state=a39fh23hnf23
Now I have a node.js application where I want to make API calls using my access token, until now I did the above manually every time to get my access token, of course, this isn't optimal. My question, therefore, is: how do I get my access token without using the browser?
Right now I have the following
sendRequestAccessToken(): Promise<any> {
const scope = 'signature';
const clientId = '*my client id*';
const state = 'a39fh23hnf23';
const url = `https://account-d.docusign.com/oauth/auth?
response_type=token
&scope=${scope}
&client_id=${clientId}
&state=${state}
&redirect_uri=http://localhost:8888/auth
`;
return this.httpService.get(url).toPromise(); }
The response from this function contains a lot of data, but no access token.
Please review the SDK examples we have here: https://github.com/docusign/code-examples-node
In those samples, we have examples on how to use the tokens using the apis.

Xero Api NodeJS - invalid grant issue

I am using the xero-node module to create an app for Xero with NodeJS.
For some reason every single request for a refresh token is coming back as invalid grant
i have been taken the code and made the callback attempt to grab the refresh straight after i do the auth so I can ensure thats its the latest token and still does the same thing.
Code is below this method is called when Xero passes back to the app (callbackURL)
The error i get is "invalid_grant" it does not give any other errors and there is no errors logs in Xero so very unhelful.
exports.callback = async function (req, res) {
const tokenSet = await xero.apiCallback(req.url);
try {
const newTokenSet2 = await xero.refreshWithRefreshToken('ClientID, 'ClientSecret', tokenSet.refresh_token);
}
catch(error){
console.log(`ERROR refresh: \n ${JSON.stringify(error.response.body, null, 2)}`);
};
///console.log(tokenSet);
};
Any ideas ?
Without seeing more of your code for context it's bit tough to tell. I'm assuming you're not actually sending 'ClientID' and 'ClientSecret' as strings.
I would refer you here for refreshing with a fully initialized client leveraging openid-client:
https://github.com/XeroAPI/xero-node-oauth2-app/blob/f1fbd3a08e840e54e8ce57f7050ddde6686208d8/src/app.ts#L233
Or here, to initialize an empty client and refresh by passing the client, secret, and refresh_token:
https://github.com/XeroAPI/xero-node-oauth2-app/blob/f1fbd3a08e840e54e8ce57f7050ddde6686208d8/src/app.ts#L236
I think what's happening is that you're using the second method but with an already initialized client. Again, tough to tell with limited context. If this doesn't resolve it please post more detail.

redirect to another app with session token (jwt) in AngularJS and NodeJS

I have a startup module in angularjs. This module is just to login and have public information (login, prices, newsletter...). I have many roles and for each role, i have an app (angular module). I made this architecture because i have complex module for each role and it was impossible to put all roles in one module.
So, for login, i use jsonwebtoken in node like this :
var token = jwt.sign(user, config.secureToken, { expiresInMinutes: 20*5});
res.json({ token: token, user: user });
It works perfectly. I can login into my app. After that, i have to propose a list of roles to redirect to the right module.
In angular, I have AuthHttp service that adds security headers (with token) to call rest service with $http.
How can i redirect to 'mydomain:port/anotherModule' with $location or $http ?
With this code in nodejs :
app.get('/secondModule', expressJwt({secret: config.secureToken}), function (req, res) {
res.render('restricted/secondModule/index.html');
});
NodeJs sends an html code in response and does'nt redirect...
And if i do this in my angular controller :
location.href = route;
i have this result on nodejs console :
Error: No Authorization header was found
I am not sure about the libraries you are using, but issue seems that you are loosing the token because you navigate to a altogether new page.
Based on your auth library you need to pass the token that you get after auth from one page to another.
The options here are to either use browser sessionStorage or querystring to pass the token along and at it back to the http header collection on the new page (module)
This is an old post but I recently took a long time to figure this out. I may be wrong but I believe nodeJS/expressJS can't read the token from the session storage. I believe you will need to pass the token via the request header using AngularJS.
This depends on the front end that you are using. For me, I am using AngularJS and I have to do something like this.
angular.module('AngularApp').factory('authFactory',
function($window){ //the window object will be able to access the token
var auth = {};
auth.saveToken = function(token){
$window.localStorage['token_name'] = token; //saving the token
}
auth.getToken = function(){
return $window.localStorage['token_name']; //retrieving the token
}
return auth;
}
.service('authInterceptor, function(authFactory){
return { headers: {Authorization: 'Bearer "+ authFactory.getToken()}
} //the last line gets the retrieved token and put it in req.header
Then, you just need to include 'authInterceptor' in all the http methods when you communicate with the backend. This way, nodeJS will be able to pick up the token.
You can see the Authorization field in req.header if you use the chrome developer tool and look at the Network tab. Hope this helps.

Sync contacts using Google Contacts API version 3.0 and NodeJS' Passport

I am using passport, and would like to use the Google Contacts API version 3.0 to sync Google contacts with my application (which would suddenly become 10 times more useful).
Has anybody done this? If so, do you have some example code? Is it even possible to use passport authentication to get it all working?
This comes in two parts, authorization, and then the actual request.
It is basically using OAuth2 protocol, where you redirect the client to google url with scopes(You must at least have https://www.google.com/m8/feeds in your scopes to be able to read and write contacts) and your client id/secret(get them by registering your app. Then google will redirect the user back with the access token on the URL.
You don't need to do this yourself, because there are different modules that already does this:
passport-google-oauth
This makes it easy and assuming you are already using passport, this probably what you want. It is written by the author of passportjs. Just follow the example in it for OAuth 2.0 strategy. Note that you need to you add the right scopes when you are calling passport.authenticate('google', ...). This module when it gets the token, it will get the user profile, so you have to have one of the 3 scopes below:
passport.authenticate('google', { scope: [ // One of the next three `auth` scopes are needed.
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/plus.login',
'https://www.google.com/m8/feeds'
] }),
googleapis
This is module is officially supported by google and created by google employees. You can use it to authenticate, but sadly it doesn't support gData, which contains google contacts. You can check the example to see how you can get the token. You only need the m8/feeds scope with this module, no need for the other ones if you don't want to get the user profile.
gdata-js
This is a non-popular non-maintaining module, but it is more lightweight than the previous two modules. It might need a little polishing out of the box. I suggest also reading the source for understanding the api right.
Once you got the tokens, then you go for the slightly easier part, making the requests and getting the data.
If you read the docs, it's actually very easy. For example to get all contacts(almost all, it's paginated), you need to make a GET request to this url:
https://www.google.com/m8/feeds/contacts/default/full?alt=json&oauth_token=THE_ACCESS_TOKEN
Again there are many modules that can help you in this.
google-contacts
node-gdata
gdata-js Read the source to understand it's api. It's pretty easy actually:
var client = require('gdata-js')(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET);
client.setToken({ access_token: accessToken, refresh_token: refreshToken });
client.getFeed('https://www.google.com/m8/feeds/contacts/default/full', function (err, result) { ... });
Google's official API for NodeJS doesn't support Contacts API, only the People API.
You can connect with Contacts API using the official googleapis library if you're already using it for other purposes by sending a request to the Contacts API after creating the auth client.
Given that you already have the access token of the user (e.g. if you generated it using Passport, here's the code:
const {google} = require("googleapis");
const authObj = new google.auth.OAuth2({
access_type: 'offline',
clientId: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
});
Refresh access token automatically before it expires
authObj.on('tokens', (tokens) => {
const access_token = tokens.access_token
if (tokens.refresh_token){
this.myTokens.refreshToken = tokens.refresh_token
// save refresh token in the database if it exists
}
this.myTokens.accessToken = tokens.access_token
// save new access token (tokens.access_token)
}
authObj.setCredentials({
access_token:this.myTokens.accessToken,
refresh_token:this.myTokens.refreshToken,
});
Make the request to Contacts API (Google uses Gaxios for making the requests to their APIs although it's not documented officially in googleapis, so just be aware that they might change remove/change the request call in the future without documenting it)
authObj.request({
headers:{
"GData-Version":3.0
},
params:{
"alt":"json",
//"q":"OPTIONAL SEARCH QUERY",
//"startindex":0
"orderby":"lastmodified",
"sortorder":"descending",
},
url: "https://www.google.com/m8/feeds/contacts/default/full"
}).then( response => {
console.log(response); // extracted contacts
});

Resources