This code should be quite self explanatory.
#include <QSharedPointer>
#include <QJsonObject>
#include <QJsonDocument>
#include <openssl/rsa.h>
#include <openssl/pem.h>
#include <openssl/sha.h>
bool tryCalculateRS256Signature(const QByteArray& data, const QString& privateKeyPem, QByteArray& signature)
{
QByteArray privateKeyPemBytes = privateKeyPem.toUtf8();
auto bio = QSharedPointer<BIO>(BIO_new_mem_buf(privateKeyPemBytes.constData(), -1), &BIO_free_all);
if (!bio) {
qDebug() << "Error loading pem";
return false;
}
auto rsa = QSharedPointer<RSA>(PEM_read_bio_RSAPrivateKey(bio.data(), nullptr, nullptr, nullptr), &RSA_free);
if (!rsa) {
qDebug() << "Error loading private key";
return false;
}
QByteArray sha256_hash(SHA256_DIGEST_LENGTH, 0);
SHA256(reinterpret_cast<const unsigned char*>(data.constData()), data.length(), reinterpret_cast<unsigned char*>(sha256_hash.data()));
QByteArray signatureBuffer(RSA_size(rsa.data()), 0);
unsigned int signatureLength = 0;
if (RSA_sign(NID_sha256, reinterpret_cast<unsigned char*>(sha256_hash.data()), SHA256_DIGEST_LENGTH, reinterpret_cast<unsigned char*>(signatureBuffer.data()), &signatureLength, rsa.data()) != 1) {
qDebug() << "Error signing data";
return false;
}
signature = signatureBuffer.left(signatureLength);
return true;
}
bool tryCreateJwtToken(const QJsonObject& payload, const QString& privateKeyPem, QString& token)
{
QJsonObject header;
header["alg"] = "RS256";
header["typ"] = "JWT";
QJsonDocument headerDoc;
headerDoc.setObject(header);
QByteArray headerBytes = headerDoc.toJson(QJsonDocument::Compact);
QJsonDocument payloadDoc;
payloadDoc.setObject(payload);
QByteArray payloadBytes = payloadDoc.toJson(QJsonDocument::Compact);
QString headerAndBody =
QString(headerBytes.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals))
+ "."
+ QString(payloadBytes.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals));
QByteArray signature;
if(!tryCalculateRS256Signature(headerAndBody.toUtf8(), privateKeyPem, signature))
{
qDebug() << "Failed to generate JWT signature";
return false;
}
token = headerAndBody + "." + signature.toBase64(QByteArray::Base64UrlEncoding | QByteArray::OmitTrailingEquals);
return true;
}
And this is how you can use it. Of course you should never have your private key in your code.
int main(int argc, char *argv[])
{
QString privateKeyPem =
"-----BEGIN PRIVATE KEY-----\r\n"
"YOUR PRIVATE KEY HERE\r\n"
"-----END PRIVATE KEY-----\r\n";
QJsonObject payload;
payload["name"] = "Johny Doe";
QString jwt;
tryCreateJwtToken(payload, privateKeyPem, jwt);
qDebug() << "jwt: " << jwt;
}