I’m attempting to connect to a service app in Okta using the sdk. To connect to the service app, I’m creating a JWT for authentication however I’m having a lot of trouble when using it for authentication.
If I use the PEM as the private key for the client then I receive this error:
Error: Parse error: child value length (58) is greater than remaining parent length (-54 = 8 - 62)
If I use a signed JWT then it comes up with this error:
Error: premature end-of-file (index: 2 length: NaN)
This is the first time I am working with a JWT that I have created myself so I am quite lost to why it is not successful.
Please find the code below:
'use strict';
var debug = require('debug')('my express app');
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
const okta = require('@okta/okta-sdk-nodejs');
const jwt = require('jsonwebtoken');
const crypto = require("crypto");
const base64 = require("base64url");
var app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
var client = undefined;
crypto.generateKeyPair('rsa', {
modulusLength: 2048,
publicKeyEncoding: {
type: 'spki',
format: 'pem'
},
privateKeyEncoding: {
type: 'pkcs8',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: 'top secret'
}
}, (err, publicKey, privateKey) => {
const signatureFunction = crypto.createSign('RSA-SHA256');
const headerObj = {
alg: 'RSA256',
typ: 'JWT',
size: 2048
};
const payloadObj = {
"aud": "https://{{org}}/oauth2/v1/token",
"iss": "{{clientId}",
"sub": "{{clientId}}",
"exp": Date.now() + 3600,
"iat": Date.now()
};
const headerObjString = JSON.stringify(headerObj);
const payloadObjString = JSON.stringify(payloadObj);
const base64UrlHeader = base64(headerObjString);
const base64UrlPayload = base64(payloadObjString);
signatureFunction.write(base64UrlHeader + '.' + base64UrlPayload);
signatureFunction.end();
// The private key without line breaks
const PRIV_KEY = privateKey;
// Will sign our data and return Base64 signature (not the same as Base64Url!)
const signatureBase64 = signatureFunction.sign({ key: PRIV_KEY, passphrase: 'top secret' }, 'base64');
const signatureBase64Url = base64.fromBase64(signatureBase64);
client = new okta.Client({
orgUrl: 'https://{{org}}.oktapreview.com/',
authorizationMode: 'PrivateKey',
clientId: '{{clientId}}',
scopes: ['okta.users.manage'],
privateKey: signatureBase64Url
//privateKey: privateKey //authentication using PEM
});
});
app.get('/', function (req, res) {
try {
console.log("listUsers:")
const orgUsers = client.listUsers();
orgUsers.each(user => {
console.log(user);
}).then(() => console.log('All users have been listed')).catch((e) => console.log(e));
} catch (e) {
console.log("list error:" + e);
}
res.render('index', { title: 'Express' });
});
// catch 404 and forward to error handler
app.use(function (req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
app.set('port', process.env.PORT || 3000);
var server = app.listen(app.get('port'), function () {
debug('Express server listening on port ' + server.address().port);
});
Sources:
SDK-GitHub - okta/okta-sdk-nodejs: Node.js API Client for the Okta Platform API
Okta Services API app-Overview | Okta Developer