Getting premature end of file error when creating key

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

1 Like

Hi there. I’m unfortunately not very familiar with Node’s crypto library - but would love to see you parse down the issue to see if there is a problem in your key generation or how you created the service app.

Are you familiar with Python at all? I created a private key JWT flow in 3 commands, repo can be found here:

I wouldn’t mind seeing you try commands 1 and 2:

python generate_keys.py
python create_okta_service_app.py

Then hardcode the private key into your Node JWT signing. If it still fails then maybe it’s an issue with the signature. If it works - then something is off in your key generation or Okta service app creation.

it may be an actual issue with the SDK as I attempted to use an generated JWT with it and it brought up a strange error.

I would rather not hardcode the key if possible as it may cause security issue etc but i’ll keep it in mind if I continue to struggle with it once the issue is resolved.

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.