Issuing JWT using Nodejs in Apigee

Hi guys, I am trying to generate a JWT using Nodejs. I know there are other ways to generate and verify a JWT within Apigee using JS/Java as per @Dino guides.

Locally the Nodejs works fine and generates an JWT, but in Apigee it is gives 500,

var nJwt = require('njwt');
var secureRandom = require('secure-random');


//var signingKey = secureRandom(256, {type: 'Buffer'}); //highly random byte array of 256 bytes
var signingKey = 'password123'; // for testing purpose


//sample claims....will be changed using apigee env variables....
var claims = {
  iss: "http://rs.com/",  
  sub: "users/uuid",    
}

var jwt = nJwt.create(claims,signingKey);
console.log("jwt is ",jwt);

var token = jwt.compact();
console.log("token is ",token);

var base64SigningKey = signingKey.toString('base64'); //Buffer needs to be converted to a string so that it can be persisted in a database
console.log("base64SigningKey is ",base64SigningKey);

Logs in Apigee,

Apr 26, 2017 11:45:47 AM 
jwt is { header: { typ: 'JWT', alg: 'HS256' }, body: { iss: 'http://rs.com/', sub: 'users/uuid', jti: 'a14089e9-3c1f-4a17-b470-5d815fae257d', iat: 1493187347, exp: 1493190947 }, signingKey: 'password123' }


Apr 26, 2017 11:45:47 AM
*** Error: Digest method not supported: "SHA256" Error: Digest method not supported: "SHA256" at Hmac (crypto.js:244) at Hmac (crypto.js:242) at sign (/organization/environment/api/node_modules/njwt/index.js:226) at compact (/organization/environment/api/node_modules/njwt/index.js:250) at /organization/environment/api/hello-world.js:27 at module.js:456 at module.js:474 at module.js:356 at module.js:312 at module.js:497 at startup (trireme.js:142) at trireme.js:923

Solved Solved
0 10 674
1 ACCEPTED SOLUTION

Not applicable

I've used Auth0I JSON Web Token with Trireme and works fine.

https://github.com/auth0/node-jsonwebtoken

Also, try to this tutorial for a fully functional API Proxy with node-jsonwebtoken:

https://github.com/dzuluaga/apigee-tutorials/tree/master/apiproxies/nodejs-jwt-apiproxy

View solution in original post

10 REPLIES 10

Not applicable

I've used Auth0I JSON Web Token with Trireme and works fine.

https://github.com/auth0/node-jsonwebtoken

Also, try to this tutorial for a fully functional API Proxy with node-jsonwebtoken:

https://github.com/dzuluaga/apigee-tutorials/tree/master/apiproxies/nodejs-jwt-apiproxy

Yeah @Diego Zuluaga, I am aware of json web token module, have to try it in Apigee.

As of now I want to use njwt module.

So is Digest method not supported:"SHA256" Error:Digest method not supported in apigee trireme?

Do we have any work around for this @Dino @Anil Sagar?

@Barahalikar Siddharth, Good stuff.

I haven't tried njwt and also haven't tested HS256 algo on Trireme. But it's plausible that it isn't supported. Check notes https://github.com/apigee/trireme#crypto. That being said, it's trying node-jsonwebtoken. Comparing both repos, I can see that node-jsonwebtoken seems to have a vibrant community around it, so I'd suggest using it as a workaround. The change in your code would be minimal. Something along these lines:

// sign with default (HMAC SHA256)
var jwt = require('jsonwebtoken');
var token = jwt.sign({ foo: 'bar' }, 'shhhhh');

// sign with HS256, but backdate a jwt 30 seconds
var older_token = jwt.sign({ foo: 'bar', iat: Math.floor(Date.now() / 1000) - 30 }, 'shhhhh');

// sign with RSA SHA256
var cert = fs.readFileSync('private.key');  // get private key
var token = jwt.sign({ foo: 'bar' }, 'password123', { algorithm: 'HS256'});

// sign with HS256, asynchronously
jwt.sign({ foo: 'bar' }, 'password123', { algorithm: 'HS256' }, function(err, token) {
  console.log(token);
});

I hope it helps!

Hi @Diego Zuluaga, I have tried the library as suggested and get an JWT(local machine),

// sign with default (HMAC SHA256) 
var jwt = require('jsonwebtoken');
var fs = require("fs");


var token = jwt.sign({ foo: 'bar' }, 'shhhhh');
//backdate a jwt 30 seconds 
var older_token = jwt.sign({ foo: 'bar', iat: Math.floor(Date.now() / 1000) - 30 }, 'shhhhh');
 
// sign with RSA SHA256 
var cert = fs.readFileSync('key.pem');  // get private key
var token = jwt.sign({ foo: 'bar' }, cert, { algorithm: 'RS256'});
 
// sign asynchronously 
jwt.sign({ foo: 'bar' }, cert, { algorithm: 'RS256' }, function(err, token) {
  console.log(token);
});

I do not want to use private key, to keep things simple I just want to use a secret(string).

Can we do that with this library?

If we go with the private key thing...we should be uploading the private key to Apigee trust store right?

http://docs.apigee.com/management/apis/post/organizations/%7Borg_name%7D/environments/%7Benv_name%7D...

Yes, you can sign with HS256 with this library. That code you have.... it signs with both HS256 and RS256. If you want to sign with HS256 and just use the secret, then remove everything before the comment that says "sign with RSA SHA256" .

// sign with default (HMAC SHA256) 
var jwt = require('jsonwebtoken');
var secretKey = 'shhhhhhh';
var token = jwt.sign({ foo: 'bar' }, secretKey);
// done.

If you want to sign with RS256, then you do need to upload the PEM somewhere. For prototype purposes, you can just upload it as a .pem file with the nodejs app and read it with fs, just as your code shows. This will work but the .pem file, which is supposed to be a secret, will be viewable in your API Proxy. In a production scenario, I would suggest that you load the PEM into an encrypted KVM and read it from there. The .pem file would not be viewable if you store it in the encrypted KVM.

More on encrypted KVM here.

Good stuff! I'm glad it worked.

Yes. You can pass a plain text secret as as Dino suggests, or store the PEM it in the filesystem for dev purposes. And yes, storing keys in Apigee Vault https://github.com/apigee/apigee-access#retrieving-values-from-the-secure-store would be most sensible for a production environment.

Nope! Not Vault. Encrypted KVM please.

Agreed. Encrypted KVMs are accessible through XML Policies and Node.js. Apigee Vault is only accessible through Node.js. This one should be captured/documented as a best practice. @docs

Thank you @Diego Zuluaga and @Dino for the ideas and solution.

I get the same error in my apiproxy when I try to use the crypto module directly.

So I think the crypto.js module is not working properly in Trireme. I don't know why that would be the case. It's possible it is relying on a later version of Node or JS than Trireme supports.

The good news is that there are workarounds:

  • Use the Java callout to generate and verify JWT - it's fast, efficient, and it works.
  • if you need to use nodejs, then use a different library, as suggested by Diego.