Ghost admin api v2

Hi,
I try to use the v2 api with python 3.7. I use the script below to create a post but I always get the error ‘Invalid token’. Tried many things but with no success. What’s wrong with my code?
Kind regards,
Jacques Bopp

import json
import requests
import jwt	# https://pyjwt.readthedocs.io
import datetime

key = 'my:admin_key'   # Admin API keys can be obtained by creating a new Custom Integration
id, secret = key.split(':') *# Split the API key by the : into an id and a secret*
secret = bytes.fromhex(secret)  # Decode the hexadecimal secret into the original binary byte array
now = int(datetime.datetime.now().timestamp())
payload = {'iat': now,'exp': now+(5*60),'aud': '/v2/admin/'}    # Timestamps are seconds sine the unix epoch: 'iat': 'now', 'exp': Max 5 minutes after 'now'
token = jwt.encode({'payload': payload}, secret, algorithm='HS256', headers={'alg': 'HS256', 'kid': id, 'typ': 'JWT'})

url = 'https://mydomain.com/ghost/api/v2/admin/posts/'
body = {'posts': [{'title': 'Hello World'}]}
headers = {'Authorization': 'Ghost {}'.format(token)}
r = requests.post(url, data=json.dumps(body), headers=headers)

# r.content = b'{"errors":[{"message":"Invalid token","context":null,"type":"BadRequestError","details":null,"property":null,"help":null,"code":"INVALID_JWT","id":"b77efe10-d3e7-11e9-b529-c11e6c33226b"}]}'

Was very close to working, have fixed the issues and included below:

  1. payload should be given to jwt.encode directly, not as an object
  2. token is a python3 byte string, so the authorization header was was being sent as Ghost b'long-token-here'. Calling token.decode() fixes this.
  3. Once the token was fixed it became clear requests wasn’t sending the data as json. One solution was to add a “content-type: application/json” header, but more elegant is to remove the json lib and use requests built-in ability to serialize json.
import requests
import jwt	# https://pyjwt.readthedocs.io
import datetime

key = 'my:admin_key'   # Admin API keys can be obtained by creating a new Custom Integration
id, secret = key.split(':') # Split the API key by the : into an id and a secret*
secret = bytes.fromhex(secret)  # Decode the hexadecimal secret into the original binary byte array
now = int(datetime.datetime.now().timestamp())
payload = {'iat': now,'exp': now+(5*60),'aud': '/v2/admin/'}    # Timestamps are seconds sine the unix epoch: 'iat': 'now', 'exp': Max 5 minutes after 'now'
token = jwt.encode(payload, secret, algorithm='HS256', headers={'alg': 'HS256', 'kid': id, 'typ': 'JWT'})

url = 'http://localhost:2368/ghost/api/v2/admin/posts/'
body = {'posts': [{'title': 'Hello World'}]}
headers = {'Authorization': 'Ghost {}'.format(token.decode())}
r = requests.post(url, json=body, headers=headers)

print(r)

I’d like to get this example added to our API docs :slight_smile:

Hi Hannah,
Works great. Thanks! A Python example will be a worthy addition to the api docs.
Jacques

1 Like