Ghost admin API - token-based authentication from the browser

Discover how to acquire a Ghost Admin API key, generate JWT tokens within the browser, and utilize them to make requests to your Ghost admin API. Unlock automation capabilities and more with these powerful tools!

4 min read
Image with programming code

The Admin API in Ghost CMS, authentication primarily relies on two key methods: JSON Web Tokens (JWTs) authentication and Session-based authentication. Typically, session-based authentication is the preferred option due to its simplicity, utilizing familiar login credentials such as email and password. However, through extensive testing—particularly on Ghost (Pro) instances—we found that session-based authentication encounters CORS issues. Fortunately, this is not a concern when self-hosting on your own servers with a tailored configuration.

In the words of Ghost's official documentation:

"The admin API key must be kept private; therefore, token authentication is not suitable for browsers or other insecure environments, unlike the Content API key."

Indeed, token-based authentication raises security concerns in the browser environment. In this article, we will explore the use case of using JWT authentication in the browser with the Ghost Admin API.
JWT tokens are typically generated on servers and the admin API key must be kept secret. However, there may be situations where you need to request the Ghost Admin API directly from the browser.
For example, we recently developed an advertisement system for a Ghost client. The simplest way to do this was to create a custom setup config panel on a hidden URL in their Ghost templates. We used JWT authentication to automate the entire process.

Just Friendly reminder, never ever store Admin API key anywhere in front-end code!!!

We need to get our Admin API key

First, let's start by acquiring our Admin API key. You can create a new Custom Integration under the Integrations screen in Ghost Admin to obtain the Admin API key. An Admin API key consists of an ID and a secret, separated by a colon. These values are utilized separately to generate a signed JWT token, crucial for the Authorization header in the request.

Obtaining Ghost admin API key

Token Generation inside Browser

In general we need to make 3 following steps with our Admin API key:

  • Divide the API key using the colon (:) to separate the ID and the secret.
  • Decode the hexadecimal secret into its original binary byte array.
  • Transmit these values to your preferred JWT library, ensuring the accuracy of the header and payload.

In our case we are going to use famous JOSE library for token generation.

<script type="module">

import * as jose from '[email protected]/+esm'

function fromHex(hexString) {
        const hexDigits = hexString.split('');
        const bytes = [];
        for (let i = 0; i < hexDigits.length; i += 2) {
          const byteValue = parseInt(hexDigits[i] + hexDigits[i + 1], 16);
        return new Uint8Array(bytes);

const genToken = async(key) => {
     let KEY = key;

     const [id,secret] = KEY.split(':');

     const jwt = await new jose.SignJWT({ 'urn:example:claim': true })
    .setProtectedHeader({ alg:'HS256', kid:id })

    return jwt


Javascript code for generation JSON WEB token for Ghost Admin API

In short this code do:

  1. Importing the JOSE Library:
    The code imports a JavaScript library called JOSE using a specific version hosted on a content delivery network (CDN).
  2. "fromHex" function:
    This function takes a hexadecimal string and converts it into a sequence of bytes (an array of numbers).
    It does this by splitting the hexadecimal string into pairs of characters, then converting each pair to its equivalent byte value.
    The result is an array of bytes that represents the original hexadecimal value.
  3. "genToken" function:
    This function generates a JWT (JSON Web Token) for authentication. It takes an API key as an input. The API key is split into two parts: an ID and a secret, separated by a colon. It then uses the JOSE library to create a signed JWT. It signs the token using the secret (after converting it from hexadecimal to binary using the fromHex function).
  4. Returning the JWT:
    The function returns the generated JWT, which can be used for authentication with the Ghost Admin API.

Putting it all together

We're all set to send a requests to our Ghost Admin API. Here's a brief example demonstrating how we can utilize our Token Generation function to access Ghost Admin API endpoints.

const BASE_URL = ``;
const BASE_DOMAIN = '';

const test = async() =>{

  let token = await genToken(api_key); //Generate our token
      let res = await fetch(BASE_URL + 'pages/',{
              "Authorization": `Ghost ${token}`,
              "Content-Type": "application/json",
              "Origin": BASE_DOMAIN,
              "Accept-Version": "v3.0"

      if (res.status != 200){
          if(res.status == 403){ 
              throw new Error("Forbbiden");
              throw new Error(`Error with status code ${res.status}`);
          let pages = await res.json();
          console.log('[+] pages -> ', pages);

      console.log('[X] err ', err.message);

Fetching Ghost Admin API Data Using Our JWT Token

To sum it up

In this guide, we've walked you through the process of obtaining your Ghost Admin API key. With a little help from the JOSE library, we've cooked up JWT tokens and showed you how to communicate with the Ghost Admin API.

Having access to the Ghost Admin API is like having a master key to your website's kingdom. It grants you significant control within the Ghost admin dashboard. That's why treating your Ghost Admin API key like a top-secret agent is crucial. Through the API, you can create, edit, and manage content such as posts, pages, tags, and authors. This means you can automate content creation and manage all your website's settings.

Hello 👋

If you have any questions or need help with your project, please don't hesitate to contact us!