DocuSign' requestJWTUserToken method errors out with 'Not Initialized" - node.js

I'm trying to implement the DocuSign JWT Auth following this code example: https://github.com/docusign/eg-01-node-jwt/blob/master/lib/dsJwtAuth.js
But I get this error when calling requestJWTUserToken():
Error: Not initialised
at Sign.update (crypto.js:99:16)
at Object.sign (/code/node_modules/jwa/index.js:159:23)
at Object.jwsSign [as sign] (/code/node_modules/jws/lib/sign-stream.js:32:24)
at Object.module.exports [as sign (/code/node_modules/jsonwebtoken/sign.js:190:16)
at generateAndSignJWTAssertion (/code/node_modules/docusign-esign/src/ApiClient.js:63:16)
at exports.requestJWTUserToken (/code/node_modules/docusign-esign/src/ApiClient.js:892:19)
at ConsentGateway.<anonymous> (/code/app/gateways/ConsentGateway.ts:73:53)
at Generator.next (<anonymous>)
at /code/app/gateways/ConsentGateway.ts:19:71
at new Promise (<anonymous>)
at __awaiter (/code/app/gateways/ConsentGateway.ts:15:12)
at ConsentGateway.getToken (/code/app/gateways/ConsentGateway.ts:64:16)
at ConsentGateway.<anonymous> (/code/app/gateways/ConsentGateway.ts:54:41)
at Generator.next (<anonymous>)
at /code/app/gateways/ConsentGateway.ts:19:71
at new Promise (<anonymous>)
at __awaiter (/code/app/gateways/ConsentGateway.ts:15:12)
at ConsentGateway.checkToken (/code/app/gateways/ConsentGateway.ts:46:16)
at ConsentGateway.<anonymous> (/code/app/gateways/ConsentGateway.ts:139:24)
at Generator.next (<anonymous>)
at /code/app/gateways/ConsentGateway.ts:19:71
at new Promise (<anonymous>)
at __awaiter (/code/app/gateways/ConsentGateway.ts:15:12)
at ConsentGateway.getTemplateList (/code/app/gateways/ConsentGateway.ts:132:16)
at ConsentService.<anonymous> (/code/app/services/ConsentService.ts:58:50)
at Generator.next (<anonymous>)
at /code/app/services/ConsentService.ts:19:71
at new Promise (<anonymous>)
the code calling the method looks like this:
private async getToken(reqId: string): Promise<any> {
try {
const pathToPrivateKey = fs.readFileSync(path.resolve('/code/app/gateways/', 'test.pem'));
this.dsApiClient.setOAuthBasePath(this.authServer);
const jwtToken = await this.dsApiClient.requestJWTUserToken(
this.integrationKey, // clientId
this.guidAccountId, // userId
'signature',
pathToPrivateKey,
10 * 60
);
const expiresAt = moment().add(jwtToken.body.expires_in, 's');
return { accessToken: jwtToken.body.access_token, tokenExpirationTimestamp: expiresAt };
} catch (e) {
this.logger.error(
'Consent Error', reqId, ['accessToken'], { status: e.response.body.errorCode, message: e.response.body.message }
);
}
}
I cannot find any documentation for the requestJWTUserToken method which makes this error hard to debug.
Is there anyone familiar with the JWT Auth flow in node that could help out with this?

Here are the things that you must ensure:
You have an Integration key (clientID) that is configured correctly.
You have an RSA Private key. that key was copied/pasted exactly as given to your configuration file. New lines must be preserved
Your URLs are matching the environment. Meaning you use account-d and demo.docusign.net for the sandbox env endpoints.
You need the userId which is a GUid for the user that would be impersonated. That user must consent to the application. You have to ensure you pass userId and not accountId and that it is for the same account that you would be using.
If you confirm all of this and still get an error - I would consider to use our code example to start. I don't see code in your question, but our code example should be a good way to start.

Related

Channel Factory not registered when trying to store a SharedString within root SharedDirectory

I tried to create and store a new SharedString DDS on my root SharedDirectory with following code:
protected async initializingFirstTime() {
const text = SharedString.create(this.runtime);
this.root.set("text", text.handle)
}
When I run the app, I get following error in JavaScript console:
app.ts:49 Error: Channel Factory https://graph.microsoft.com/types/mergeTree not registered
at new LocalChannelContext (localChannelContext.js:19)
at FluidDataStoreRuntime.createChannel (dataStoreRuntime.js:169)
at Function.create (sharedString.js:33)
at DiceRoller.<anonymous> (dataObject.ts:43)
at Generator.next (<anonymous>)
at dataObject.ts:4
at new Promise (<anonymous>)
at ./src/dataObject.ts.__awaiter (dataObject.ts:4)
at DiceRoller.initializingFirstTime (dataObject.ts:42)
at DiceRoller.initializeInternal (pureDataObject.js:87)
You need to ensure you are registering all DDS types with your Data Object Factory.
public static readonly factory = new DataObjectFactory(
SomeFluidObject.Name,
SomeFluidObject,
[
SharedString.getFactory(),
],
{},
);

How authenticate to an API with SSL certificate?

I need to access to the API of a service provider (for my company)
So, they gave me a 'doc' and a SSL certificate in multiple form (.jks, .p12, .pem)
I work with NodeJS so I took the .pem, inside there is 2 certificates and 1 encrypted private key.
I split the .pem in 3 files, mycert.crt.pem, mycert.key.pem, mycert2.crt.pem
(I checked on https://www.sslshopper.com/certificate-key-matcher.html to know which cert use with the key)
So my NodeJS, I used the least possible module to avoid module problem :
const cert = fs.readFileSync(path.resolve('cert', 'mycert.crt.pem'))
const key = fs.readFileSync(path.resolve('cert', 'mycert.key.pem'))
let options = {
hostname: 'https://serviceproviderurl.com',
path: 'v1/api/example',
method: 'POST',
key: key,
cert: cert
}
let req = https.request(options, function (res) {
console.log(res.statusCode)
res.on('data', function (d) {
process.stdout.write(d)
})
})
req.end()
And the error message :
Error: error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
at Object.createSecureContext (_tls_common.js:151:17)
at Object.connect (_tls_wrap.js:1407:48)
at Agent.createConnection (https.js:125:22)
at Agent.createSocket (_http_agent.js:234:26)
at Agent.addRequest (_http_agent.js:193:10)
at new ClientRequest (_http_client.js:276:16)
at Object.request (https.js:309:10)
at Object.<anonymous> (/mnt/c/Project/test.js:74:17)
at Module._compile (internal/modules/cjs/loader.js:959:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:995:10) {
opensslErrorStack: [
'error:0907B00D:PEM routines:PEM_read_bio_PrivateKey:ASN1 lib',
'error:2306A075:PKCS12 routines:PKCS12_item_decrypt_d2i:pkcs12 pbe crypt error',
'error:23077074:PKCS12 routines:PKCS12_pbe_crypt:pkcs12 cipherfinal error'
],
library: 'digital envelope routines',
function: 'EVP_DecryptFinal_ex',
reason: 'bad decrypt',
code: 'ERR_OSSL_EVP_BAD_DECRYPT'
I think I missed something with the 3 certificates. Also they didn't gave me a passphrase, is it normal ?
I don't have a good knowledge about SSL certificate use and I hope you can help me.
Thank you

Verifying JWT using jsonwebtoken in node.js with a token generated by jose4j HMAC_SHA256

OK, so I have a Back-end Java service that is generating JWTs using the jose4j library. This is already in production and we have several other Java services that are verifying these tokens and it all works just fine. I'm now trying to create a NodeJS service and it also needs to verify the JWTs that are being generating by the original Java Service.
Here is the Java code using jose4j to generate a token.
public static HmacKey getKey() throws UnsupportedEncodingException, NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(Vars.SECRET_KEY.getBytes("UTF-8"));
byte[] key = md.digest();
return new HmacKey(key);
}
public String buildJwt(){
JwtClaims claims = new JwtClaims();
claims.setIssuer(issuer == null ? Vars.NETD_ISSUER : issuer);
claims.setExpirationTimeMinutesInTheFuture(timeToLiveInMinutes);
claims.setGeneratedJwtId();
claims.setIssuedAtToNow();
claims.setNotBeforeMinutesInThePast(2);
claims.setSubject(subject);
JsonWebSignature jws = new JsonWebSignature();
// Add the Claims payload to the JWS
jws.setPayload(claims.toJson());
jws.setKey(getKey());
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.HMAC_SHA256);
jwt = jws.getCompactSerialization();
}
Here is the NodeJS code where I'm attempting to validate the JWT.
let decoded = await jwt.verify(token, Buffer.from(config.signature));
The config.signature and the Vars.SECRET_KEY are the same values.
But this results in a 'invalid signature'.
{ JsonWebTokenError: invalid signature
at C:\Users\jmiles\code\nodeJS\NetDGateway\node_modules\jsonwebtoken\verify.js:122:19
at getSecret (C:\Users\jmiles\code\nodeJS\NetDGateway\node_modules\jsonwebtoken\verify.js:76:14)
at Object.module.exports [as verify] (C:\Users\jmiles\code\nodeJS\NetDGateway\node_modules\jsonwebtoken\verify.js:80:10)
at Object.validateOriForVendor (C:\Users\jmiles\code\nodeJS\NetDGateway\src\utils.js:37:33)
at getCaseDetail (C:\Users\jmiles\code\nodeJS\NetDGateway\src\operations.js:94:29)
at Layer.handle [as handle_request] (C:\Users\jmiles\code\nodeJS\NetDGateway\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\jmiles\code\nodeJS\NetDGateway\node_modules\express\lib\router\route.js:137:13)
at Route.dispatch (C:\Users\jmiles\code\nodeJS\NetDGateway\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (C:\Users\jmiles\code\nodeJS\NetDGateway\node_modules\express\lib\router\layer.js:95:5)
at C:\Users\jmiles\code\nodeJS\NetDGateway\node_modules\express\lib\router\index.js:281:22
at param (C:\Users\jmiles\code\nodeJS\NetDGateway\node_modules\express\lib\router\index.js:354:14)
at paramCallback (C:\Users\jmiles\code\nodeJS\NetDGateway\node_modules\express\lib\router\index.js:401:21)
at oriHelper (C:\Users\jmiles\code\nodeJS\NetDGateway\src\operations.js:234:5) name: 'JsonWebTokenError', message: 'invalid signature' }
I was able to get the jsonwebtoken to validate it if I change the getKey method to the following.
public static HmacKey getKey() throws UnsupportedEncodingException {
return new HmacKey(Vars.SECRET_KEY.getBytes("UTF-8"));
}
and then change the validation call for jsonwebtoken to the following.
let decoded = await jwt.verify(token, config.signature, config.jwtOptions);
So that the verify function is taking a string instead of a Buffer.from()
This is not ideal as now I need to do a pull request for a service that is already in production. And doing this change will require that all existing JWTs will become invalid.

Error Message : InvalidKey: A key should contain at least a kind

I am getting following error while trying to update the entity in google cloud datastore:
InvalidKey: A key should contain at least a kind.
at keyToKeyProto (/Volumes/Drive B/dev/zapi/node_modules/#google-cloud/datastore/src/entity.js:696:11)
at Array.map (<anonymous>)
at DatastoreRequest.createReadStream (/Volumes/Drive B/dev/zapi/node_modules/#google-cloud/datastore/src/request.js:226:23)
at DatastoreRequest.get (/Volumes/Drive B/dev/zapi/node_modules/#google-cloud/datastore/src/request.js:461:8)
at /Volumes/Drive B/dev/zapi/node_modules/#google-cloud/common/build/src/util.js:681:32
at new Promise (<anonymous>)
at Datastore.wrapper [as get] (/Volumes/Drive B/dev/zapi/node_modules/#google-cloud/common/build/src/util.js:662:20)
at fetchEntity (/Volumes/Drive B/dev/zapi/node_modules/gstore-node/lib/model.js:204:36)
at Function.get (/Volumes/Drive B/dev/zapi/node_modules/gstore-node/lib/model.js:174:16)
at Promise (/Volumes/Drive B/dev/zapi/node_modules/gstore-node/lib/utils.js:39:35)
at new Promise (<anonymous>)
at Function.wrapper (/Volumes/Drive B/dev/zapi/node_modules/gstore-node/lib/utils.js:27:16)
at resolve (/Volumes/Drive B/dev/zapi/graphql/mutations/user/linkConsult.js:101:44)
I don't know why is this coming for.
Thanks in advance.
When you trying to access key and key is not available when no data available, it gives the error
"Error Message : InvalidKey: A key should contain at least a kind"
To avoid this error first make sure that [datastrore.KEY] is available.
Thanks
I want to add to this answer with a little more detail. Here are some other helpful points to investigate if you run into this error when using the datastore.save method. The entity needs the correct key property like the example below.
// remember to use the key method on the google data store instance
const entity = {
key: dataStore.key('Name of your Kind') // this is Kind property you see on the GCP dashboard,
data: {
example: 'this is an example',
...
}
};
// then save the entity
const dbResult = await dataStore.save(entity)

Firebase functions logs error working with Cloud Firestore and Node JS

The Firebase functions by Nodejs is not retrieving the results from the data stored in the Cloud Firestore Database. Giving a:
TypeError of Undefined user_id
NodeJS Code
'use-strict'
const admin = require('firebase-admin');
const functions = require('firebase-functions');
const serviceAccount = require("./serviceAccountKey.json");
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.firestore.document("Users/{user_id}/Notifications/{notification_id}").onWrite(event => {
const user_id = event.params.user_id;
const notification_id = event.params.notification_id;
console.console.log("User ID: " + user_id + " | Notification ID: " + notification_id);
});
Error in Logs of Firebase Functions
TypeError: Cannot read property 'user_id' of undefined at
exports.sendNotification.functions.firestore.document.onWrite.event
(/user_code/index.js:10:33) at Object.<anonymous>
(/user_code/node_modules/firebase-functions/lib/cloud-functions.js:112:27)
at next (native) at /user_code/node_modules/firebase-functions/lib/cloud-
functions.js:28:71 at __awaiter (/user_code/node_modules/firebase-
functions/lib/cloud-functions.js:24:12) at cloudFunction
(/user_code/node_modules/firebase-functions/lib/cloud-functions.js:82:36) at
/var/tmp/worker/worker.js:700:26 at process._tickDomainCallback
(internal/process/next_tick.js:135:7)
Database Rules
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true; } } }
It looks like you're using version 1.0 of the firebase-functions module in your Cloud Functions code. The API has changed in 1.0. Please consult the migration guide to understand what changed in 1.0.
There is no longer a params property on the first argument passed to the the callback for an onWrite trigger. It was split into two arguments, a Change, and an EventContext object. The EventContext argument has a params property you should use now.

Resources