Getting Access Token from Google Cloud service account
- 
Hi all, 
 I need to retrieve an access token from google cloud using a service account json.Here is my code: generateJWT(const QString &clientEmail, const QString &privateKey) { // Header QJsonObject header; header["alg"] = "RS256"; header["typ"] = "JWT"; QString encodedHeader = base64UrlEncode(QJsonDocument(header).toJson(QJsonDocument::Compact)); qDebug() << "encodedHeader:" << encodedHeader; // Payload QJsonObject payload; payload["iss"] = clientEmail; payload["scope"] = "https://www.googleapis.com/auth/firebase.messaging"; payload["aud"] = "https://oauth2.googleapis.com/token"; payload["exp"] = QDateTime::currentSecsSinceEpoch() + 3600; // 1 hour expiration payload["iat"] = QDateTime::currentSecsSinceEpoch(); QString encodedPayload = base64UrlEncode(QJsonDocument(payload).toJson(QJsonDocument::Compact)); // Signature QString message = encodedHeader + "." + encodedPayload; qDebug() << "message:\n" << message; QByteArray signature = QMessageAuthenticationCode::hash(message.toUtf8(), privateKey.toUtf8(), QCryptographicHash::Sha256); QString encodedSignature = base64UrlEncode(signature); // JWT QString jwt = encodedHeader + "." + encodedPayload + "." + encodedSignature; qDebug() << "JTW: "<< jwt; return jwt; }getAccessToken() { QFile keyFile("/mnt/temporanea/Downloads/myproject-1122344956ca77.json"); if (!keyFile.open(QIODevice::ReadOnly)) { qWarning() << "Failed to open key file"; return; } QByteArray keyData = keyFile.readAll(); QJsonDocument keyDoc = QJsonDocument::fromJson(keyData); QJsonObject keyObject = keyDoc.object(); QString clientEmail = keyObject["client_email"].toString(); QString privateKey = keyObject["private_key"].toString(); qDebug() << clientEmail << privateKey; // Generate JWT QString jwt = generateJWT(clientEmail, privateKey); // Request access token QNetworkRequest request(QUrl("https://oauth2.googleapis.com/token")); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); QUrlQuery params; params.addQueryItem("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"); params.addQueryItem("assertion", jwt); QNetworkReply *reply = manager.post(request, params.toString(QUrl::FullyEncoded).toUtf8()); connect(reply, &QNetworkReply::finished, [reply] { if (reply->error() == QNetworkReply::NoError) { QByteArray response = reply->readAll(); QJsonDocument jsonDoc = QJsonDocument::fromJson(response); QString accessToken = jsonDoc.object()["access_token"].toString(); qDebug() << "Access Token:" << accessToken; // Use the access token for API calls } else { qWarning() << "Error:" << reply->errorString(); } reply->deleteLater(); }); } base64UrlEncode(const QByteArray &data) { QByteArray encoded = data.toBase64(); encoded = encoded.replace('+', '-').replace('/', '_').replace("=", ""); return QString::fromUtf8(encoded); }When executing I get: Error: "Error transferring https://oauth2.googleapis.com/token - server replied: Bad Request"Did anyone manage to get the access token this way? Thanks 
- 
Hi all, 
 I need to retrieve an access token from google cloud using a service account json.Here is my code: generateJWT(const QString &clientEmail, const QString &privateKey) { // Header QJsonObject header; header["alg"] = "RS256"; header["typ"] = "JWT"; QString encodedHeader = base64UrlEncode(QJsonDocument(header).toJson(QJsonDocument::Compact)); qDebug() << "encodedHeader:" << encodedHeader; // Payload QJsonObject payload; payload["iss"] = clientEmail; payload["scope"] = "https://www.googleapis.com/auth/firebase.messaging"; payload["aud"] = "https://oauth2.googleapis.com/token"; payload["exp"] = QDateTime::currentSecsSinceEpoch() + 3600; // 1 hour expiration payload["iat"] = QDateTime::currentSecsSinceEpoch(); QString encodedPayload = base64UrlEncode(QJsonDocument(payload).toJson(QJsonDocument::Compact)); // Signature QString message = encodedHeader + "." + encodedPayload; qDebug() << "message:\n" << message; QByteArray signature = QMessageAuthenticationCode::hash(message.toUtf8(), privateKey.toUtf8(), QCryptographicHash::Sha256); QString encodedSignature = base64UrlEncode(signature); // JWT QString jwt = encodedHeader + "." + encodedPayload + "." + encodedSignature; qDebug() << "JTW: "<< jwt; return jwt; }getAccessToken() { QFile keyFile("/mnt/temporanea/Downloads/myproject-1122344956ca77.json"); if (!keyFile.open(QIODevice::ReadOnly)) { qWarning() << "Failed to open key file"; return; } QByteArray keyData = keyFile.readAll(); QJsonDocument keyDoc = QJsonDocument::fromJson(keyData); QJsonObject keyObject = keyDoc.object(); QString clientEmail = keyObject["client_email"].toString(); QString privateKey = keyObject["private_key"].toString(); qDebug() << clientEmail << privateKey; // Generate JWT QString jwt = generateJWT(clientEmail, privateKey); // Request access token QNetworkRequest request(QUrl("https://oauth2.googleapis.com/token")); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); QUrlQuery params; params.addQueryItem("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"); params.addQueryItem("assertion", jwt); QNetworkReply *reply = manager.post(request, params.toString(QUrl::FullyEncoded).toUtf8()); connect(reply, &QNetworkReply::finished, [reply] { if (reply->error() == QNetworkReply::NoError) { QByteArray response = reply->readAll(); QJsonDocument jsonDoc = QJsonDocument::fromJson(response); QString accessToken = jsonDoc.object()["access_token"].toString(); qDebug() << "Access Token:" << accessToken; // Use the access token for API calls } else { qWarning() << "Error:" << reply->errorString(); } reply->deleteLater(); }); } base64UrlEncode(const QByteArray &data) { QByteArray encoded = data.toBase64(); encoded = encoded.replace('+', '-').replace('/', '_').replace("=", ""); return QString::fromUtf8(encoded); }When executing I get: Error: "Error transferring https://oauth2.googleapis.com/token - server replied: Bad Request"Did anyone manage to get the access token this way? Thanks @luca You are signing the JWT incorrectly. The JWT header says that the algorithm is RS256which means RSA signature of SHA-256 hashed payload, but the actual signature is a HMAC (which would fit analgvalue ofHS256).If RS256is expected signature algorithm, you need to do a RSA signature, which I don't believe Qt has built-in. You'll need an additional library for that.P.S QByteArray::toBase64takes an options argument, that you can use to tell it to use the URL-safe base64 variant.
- 
Hi, Out of curiosity, why not use the Qt NetworkAuth module ? 
- 
Hi all, 
 I need to retrieve an access token from google cloud using a service account json.Here is my code: generateJWT(const QString &clientEmail, const QString &privateKey) { // Header QJsonObject header; header["alg"] = "RS256"; header["typ"] = "JWT"; QString encodedHeader = base64UrlEncode(QJsonDocument(header).toJson(QJsonDocument::Compact)); qDebug() << "encodedHeader:" << encodedHeader; // Payload QJsonObject payload; payload["iss"] = clientEmail; payload["scope"] = "https://www.googleapis.com/auth/firebase.messaging"; payload["aud"] = "https://oauth2.googleapis.com/token"; payload["exp"] = QDateTime::currentSecsSinceEpoch() + 3600; // 1 hour expiration payload["iat"] = QDateTime::currentSecsSinceEpoch(); QString encodedPayload = base64UrlEncode(QJsonDocument(payload).toJson(QJsonDocument::Compact)); // Signature QString message = encodedHeader + "." + encodedPayload; qDebug() << "message:\n" << message; QByteArray signature = QMessageAuthenticationCode::hash(message.toUtf8(), privateKey.toUtf8(), QCryptographicHash::Sha256); QString encodedSignature = base64UrlEncode(signature); // JWT QString jwt = encodedHeader + "." + encodedPayload + "." + encodedSignature; qDebug() << "JTW: "<< jwt; return jwt; }getAccessToken() { QFile keyFile("/mnt/temporanea/Downloads/myproject-1122344956ca77.json"); if (!keyFile.open(QIODevice::ReadOnly)) { qWarning() << "Failed to open key file"; return; } QByteArray keyData = keyFile.readAll(); QJsonDocument keyDoc = QJsonDocument::fromJson(keyData); QJsonObject keyObject = keyDoc.object(); QString clientEmail = keyObject["client_email"].toString(); QString privateKey = keyObject["private_key"].toString(); qDebug() << clientEmail << privateKey; // Generate JWT QString jwt = generateJWT(clientEmail, privateKey); // Request access token QNetworkRequest request(QUrl("https://oauth2.googleapis.com/token")); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); QUrlQuery params; params.addQueryItem("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"); params.addQueryItem("assertion", jwt); QNetworkReply *reply = manager.post(request, params.toString(QUrl::FullyEncoded).toUtf8()); connect(reply, &QNetworkReply::finished, [reply] { if (reply->error() == QNetworkReply::NoError) { QByteArray response = reply->readAll(); QJsonDocument jsonDoc = QJsonDocument::fromJson(response); QString accessToken = jsonDoc.object()["access_token"].toString(); qDebug() << "Access Token:" << accessToken; // Use the access token for API calls } else { qWarning() << "Error:" << reply->errorString(); } reply->deleteLater(); }); } base64UrlEncode(const QByteArray &data) { QByteArray encoded = data.toBase64(); encoded = encoded.replace('+', '-').replace('/', '_').replace("=", ""); return QString::fromUtf8(encoded); }When executing I get: Error: "Error transferring https://oauth2.googleapis.com/token - server replied: Bad Request"Did anyone manage to get the access token this way? Thanks @luca You are signing the JWT incorrectly. The JWT header says that the algorithm is RS256which means RSA signature of SHA-256 hashed payload, but the actual signature is a HMAC (which would fit analgvalue ofHS256).If RS256is expected signature algorithm, you need to do a RSA signature, which I don't believe Qt has built-in. You'll need an additional library for that.P.S QByteArray::toBase64takes an options argument, that you can use to tell it to use the URL-safe base64 variant.
- 
@SGaist AFAIK Qt NetworkAuth can be used to authenticate via browser. Can't be used for server-to-server communication using a service account. @IgKh said in Getting Access Token from Google Cloud service account: @luca You are signing the JWT incorrectly. The JWT header says that the algorithm is RS256which means RSA signature of SHA-256 hashed payload, but the actual signature is a HMAC (which would fit analgvalue ofHS256).If RS256is expected signature algorithm, you need to do a RSA signature, which I don't believe Qt has built-in. You'll need an additional library for that.P.S QByteArray::toBase64takes an options argument, that you can use to tell it to use the URL-safe base64 variant.Thanks, this could be the reason. Do you know how to do that using openssl? 
- 
It seems this code works fine: 
 https://jorisvergeer.nl/2023/03/22/c-qt-openssl-jwt-minimalistic-implementation-to-create-a-signed-jtw-token/
- 
L luca has marked this topic as solved on
