Hey team
I’m trying to add members to my Ghost (Pro) account via the Admin API but keep running into the following error —
{
"errors": [
{
"message": "Invalid token: invalid signature",
"context": null,
"type": "UnauthorizedError",
"details": null,
"property": null,
"help": null,
"code": "INVALID_JWT",
"id": "d3271f10-be6a-11ec-a615-c128442a4338"
}
]
}
I was able to successfully run the API on Node.js so I know that all my credentials, endpoint, POST payload etc. are in the correct format.
Here’s the code but you can just as easily make a copy of my Google Apps Script project instead —
const accessToken = `<replace-this-with-your-access-token>`;
const admin_domain = `<replace-this-with-your-admin-domain>`;
let [id, secret] = accessToken.split(':');
function addMemberToGhost() {
let options = {
'method': 'POST',
'headers': {
'Authorization': `Ghost ${createJwt()}`, // https://ghost.org/docs/admin-api/#token-authentication
},
'muteHttpExceptions': true,
'contentType': 'application/json',
'payload': JSON.stringify({
"members": [
{
"email": "sourabh@choraria.io",
"name": "Sourabh Choraria",
}
]
}),
}
const response = UrlFetchApp.fetch(`https://${admin_domain}/ghost/api/v3/admin/members/`, options);
console.log(response.getResponseCode());
console.log(JSON.stringify(JSON.parse(response.getContentText()), null, 2));
}
function createJwt() { // adopted from https://www.labnol.org/code/json-web-token-201128
const header = Utilities.base64EncodeWebSafe(JSON.stringify({
alg: 'HS256',
kid: id,
typ: 'JWT'
})).replace(/=+$/, '');
const now = Date.now();
let expires = new Date(now);
expires.setMinutes(expires.getMinutes() + 5);
const payload = Utilities.base64EncodeWebSafe(JSON.stringify({
exp: Math.round(expires.getTime() / 1000),
iat: Math.round(now / 1000),
aud: '/v3/admin/'
})).replace(/=+$/, '');
// https://gist.github.com/tanaikech/707b2cd2705f665a11b1ceb2febae91e#sample-script
// Convert hex 'secret' to byte array then base64Encode
secret = Utilities.base64EncodeWebSafe(secret
.match(/.{2}/g)
.map((e) =>
parseInt(e[0], 16).toString(2).length == 4
? parseInt(e, 16) - 256
: parseInt(e, 16)
)).replace(/=+$/, '');
const toSign = `${header}.${payload}`;
const signatureBytes = Utilities.computeHmacSha256Signature(toSign, secret);
const signature = Utilities.base64EncodeWebSafe(signatureBytes).replace(/=+$/, '');
const jwt = `${toSign}.${signature}`;
console.log({jwt});
return jwt;
};
I think my issues are with trying to convert hex secret to byte array (line 45) part of the code but I could be wrong
Any help would be greatly appreciated