Get Data Out Of Server-Side Plugin

I’m going to make this plugin public/open-source after so I don’t mind pasting the code:
function(properties, context) {

console.log("Starting Data Load");
const gISS = properties.iss;
const gSCOPE = properties.scope;
const gSUB = properties.sub;
const gFILE = properties.file;

const googleAuth = require("google-oauth-jwt");
console.log("Finished Data Load");

var assertion = {"assertion":googleAuth.encodeJWT({
// use the email address of the service account, as seen in the API console
email: gISS,
// use the PEM file we generated from the downloaded key
keyFile: gFILE,
// specify the scopes you which to access
scopes: [gSCOPE],
delegationEmail: gSUB,
//sub: ''
}, function (err, jwt) {
    return jwt;

//var assertion = {"assertion":rMe};
console.log("Now Returning");
return assertion;


I’m having trouble returning the data to the user. Any thoughts? I saw something about run_server(), but I’m totally new to this and not sure what I’m doing.

Any help is greatly appreciated! Like I said, this will all be open source after. It’s a plugin to generate the header for a Google Service Account request.

As it stands, this runs 100% perfectly in VisualStudio code; I’m just struggling with recreating it in bubble.


Here’s the link to the plugin. I already published it under the MIT license for everyone to use (which can’t be undone) to show you I’m not using your help just to throw up a pay-wall.


You should return as JSON. so it should be something like

return { "assertion": assertion };

That part I get. The problem I’m having is that I can only log data and can’t seem to retrieve it. In my code, I call
function (err, jwt) {
return jwt;

But the return variable inside does not return.

Here’s the source code:

var fs = require('fs'),
	crypto = require('crypto'),
	request = require('request'),
	debug = require('debug')('google-oauth-jwt');

// constants

 * Request an authentication token by submitting a signed JWT to Google OAuth2 service.
 * @param {Object} options The JWT generation options.
 * @param {Function} callback The callback function to invoke with the resulting token.
exports.authenticate = function (options, callback) {

	callback = callback || function () {};

	exports.encodeJWT(options, function (err, jwt) {

		if (err) return callback(err);

		return, {
			headers: {
				'Content-Type': 'application/x-www-form-urlencoded'
			form: {
				grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
				assertion: jwt
		}, function (err, res, body) {

			if (err) {
				return callback(err);
			} else {
				debug('response from OAuth server: HTTP %d -> %j', res.statusCode, body);

			try {
				body = JSON.parse(body);
			catch (e) {
				return callback(new Error('failed to parse response body: ' + body));

			if (res.statusCode != 200) {
				err = new Error(
					'failed to obtain an authentication token, request failed with HTTP code ' +
					res.statusCode + ': ' + body.error
				err.statusCode = res.statusCode;
				err.body = body;
				return callback(err);

			return callback(null, body.access_token);


 * Encode a JSON Web Token (JWT) using the supplied options.
 * The token represents an authentication request for a specific user and is signed with a private key to ensure
 * authenticity.
 * Available options are:
 *   ``: the email address of the service account (required)
 *   `options.scopes`: an array of scope URIs to demand access for (required)
 *   `options.key` or options.keyFile: the private key to use to sign the token (required)
 *   `options.expiration`: the duration of the requested token, in milliseconds (default: 1 hour)
 *   `options.delegationEmail`: an email address for which access is being granted on behalf of (optional)
 * @param {Object} options The options to use to generate the JWT
 * @param {Function} callback The callback function to invoke with the encoded JSON Web Token (JWT)
exports.encodeJWT = function (options, callback) {

	var outerReturnVar;

	if (!options) throw new Error('options is required');
	if (! throw new Error(' is required');
	if (!options.scopes) throw new Error('options.scopes is required');
	if (!Array.isArray(options.scopes)) throw new Error('options.scopes must be an array');
	if (options.scopes.length == 0) throw new Error('options.scopes must contain at least one scope');
	if (!options.key && !options.keyFile) throw new Error('options.key or options.keyFile are required');
	callback = callback || function () {};

	debug('generating jwt for %j', options);

	var iat = Math.floor(new Date().getTime() / 1000),
		exp = iat + Math.floor((options.expiration || 60 * 60 * 1000) / 1000),
		claims = {
			scope: options.scopes.join(' '),
			exp: exp,
			iat: iat

	if (options.delegationEmail) {
		claims.sub = options.delegationEmail;

	var JWT_header = new Buffer(JSON.stringify({ alg: "RS256", typ: "JWT" })).toString('base64'),
		JWT_claimset = new Buffer(JSON.stringify(claims)).toString('base64'),
		unsignedJWT = [JWT_header, JWT_claimset].join('.');

	obtainKey(function (err, key) {

		if (err) return callback(err);

		try {
			var JWT_signature = crypto.createSign('RSA-SHA256').update(unsignedJWT).sign(key, 'base64'),
			signedJWT = [unsignedJWT, JWT_signature].join('.');
		} catch (e) {
			// in Node 0.12, an error is thrown
			var signErr = new Error('failed to sign JWT, the key is probably invalid');
			signErr.inner = e;
			return callback(signErr);

		if (JWT_signature === '') {
			return callback(new Error('failed to sign JWT, the key is probably invalid'));

		debug('signed jwt: %s', signedJWT);
		return callback(null, signedJWT);


	function obtainKey(callback) {
		if (options.key && options.key != '') {
			// key is supplied as a string
			return callback(null, options.key);
		} else if (options.keyFile) {
			// read the key from the specified file
			return fs.readFile(options.keyFile, callback);
		return callback(new Error(
			'key is not specified, use "options.key" or "options.keyFile" to specify the key to use to sign the JWT'


I call googleAuth.encodeJWT(…) and can’t seem to get data out of it/put a return variable somewhere where I can return data (it’s not my code).

@wj_Kim: there was an issue with the code repository I was using. I rewrote the code myself, but now can’t get it into the plugin editor (this is the new thread Need Help Getting Completed Code Into Plugin Editor) would you mind taking a look and seeing if you can help?