TinyMCE AI with JWT authentication (PHP) Guide

Introduction

TinyMCE AI requires setting up JSON Web Token (JWT) authentication to maintain control over AI feature access. A JWT endpoint generates and provides authorization tokens that verify users are authorized to use AI features, preventing unauthorized access. As a standard web services authorization solution, JWT is documented extensively at https://jwt.io/. TinyMCE recommends using the libraries listed on jwt.io/libraries to create JWT tokens.

This guide provides a comprehensive walkthrough for integrating TinyMCE AI with TinyMCE, including TinyMCE AI functionality, by using a PHP server for JWT token generation. It covers project setup, server configuration, and TinyMCE customization.

What Will Be Built

Before diving into the technical details, here is what will be achieved with this guide:

  • A working TinyMCE editor running the TinyMCE AI plugin

  • A secure authentication system using JWT tokens

  • A simple PHP server to handle the authentication

This guide is designed for developers new to JWT authentication and TinyMCE integration.

Prerequisites

Before starting, ensure you have:

  • PHP installed on the computer (to check, run php -v in the terminal)

  • OpenSSL installed on the computer (to check, run openssl version in the terminal)

  • Composer installed on the computer (to check, run composer -v in the terminal)

  • A TinyMCE API key with TinyMCE AI enabled (get one from TinyMCE’s website)

  • Basic familiarity with the command line

Ensure the API key is ready before starting. It will be needed for both the server and client configuration.

Update PHP Configuration File

Use the following command to locate the PHP configuration file:

php --ini

Open the configuration file in a text editor and ensure the following settings are enabled:

extension=openssl
extension_dir='ext'
The path to the extension directory may vary depending on the system.

Quick Start Guide

Project Setup

# Create and enter project directory
mkdir tinymce-app
cd tinymce-app
# Initialize Composer
composer require firebase/php-jwt

Create Project Structure

# Create the public folder for web files
touch index.html
touch jwt.php

The project should look like this:

/tinymce-app
  index.html  (TinyMCE webpage)
  jwt.php     (Server code)
  composer.json
  composer.lock
  vendor

Generate a Public/Private Key Pair

The TinyMCE AI Server requires a public key generated from the same private key that will be used on the JSON Web Token (JWT) provider endpoint. The public key(s) stored on the TinyMCE AI Server are used to ensure that content is sent by authorized users.

There are two methods for generating and adding a public key in the JWT Keys section of the account portal:

  1. Generate New Keypair at Tiny Account - JWT Keys (recommended).

  2. Generate a key pair locally and Import Public Key at Tiny Account - JWT Keys.

Generate a key pair using the Tiny Account JWT Keys page

The Tiny Account - JWT Keys page provides a "Generate New Keypair" option, providing a quick and secure way of generating the required keys. This will store a copy of the public key, and provide a downloadable file for both the public and private keys. Tiny does not store the private key and the key pair cannot be retrieved later.

Generate a key pair locally and add it to the account

This method involves two steps: generating the key pair locally, then adding the public key to the account portal.

Generate a key pair locally

When generating a key pair locally, use one of the supported algorithms. TinyMCE AI does not support symmetrical encryption algorithms, such as HS256. Tiny recommends using the RS256 algorithm. The following algorithms are supported:

  • RS256

  • RS384

  • RS512

  • PS256

  • PS384

  • PS512

For instructions on generating a key pair locally, see: Creating a private/public key pair for Tiny Cloud.

Add a public key in the JWT Keys section of the account portal

Once a public key has been generated locally, use the "Import Public Key" option in the JWT Keys section of the account portal at: Tiny Account - JWT Keys.

JWT Configuration Requirements

This section explains what needs to be configured for JWT authentication, whether using a managed service (such as AWS or Azure JWT services) or setting up a manual endpoint.

For complete information about JWT requirements, claims, and permissions, see JWT Authentication.

A JSON Web Token (JWT) endpoint is a service for generating and providing authorization tokens to users. These tokens can then be used to verify that submitted content was sent by an authorized user and to prevent unauthorized access.

The following diagram shows how JWTs are used:

JSON Web Token Call Flow
Figure 1. JSON Web Token Call Flow

When a user opens TinyMCE AI:

  1. TinyMCE AI requests a signed JWT on behalf of the user.

  2. If your JWT endpoint authorizes the user, your JWT endpoint will send a JWT to TinyMCE AI, certifying the user.

  3. The JWT includes a sub (subject) claim that identifies the user. This user identifier is used to lock down conversation history, AI-generated content, and other user-specific data to individual users, ensuring privacy and data isolation.

  4. When the user makes a request (such as starting a chat conversation, requesting AI actions, or submitting reviews), the JWT will be sent with the request to show that the user is authorized. This JWT is verified using the public key stored on the AI service.

  5. The AI service sends a response, indicating that the request was successful (or unauthorized if necessary).

JWT endpoint requirements

A JSON Web Token (JWT) endpoint for TinyMCE AI requires:

  • The endpoint or server accepts a JSON HTTP POST request.

  • User authentication: A method of verifying the user, and that they should have access to the TinyMCE AI.

  • The JWTs are generated (signed) using the private key that pairs with the public key provided to Tiny Account - JWT Keys.

  • The endpoint or server produces a JSON response with the token. TinyMCE AI will submit the token with requests to the AI service.

Required JWT claims for TinyMCE AI

JSON Web Tokens produced by the JWT endpoint must include the following claims:

aud (required)

Type: String

The aud is a case-sensitive string that must match a valid API key that has the TinyMCE AI plugin enabled.

sub (required)

Type: String

The sub claim identifies the user. This should be a unique identifier for the user making the request.

iat (required)

Type: Number

The iat represents the issue timestamp, specified as the number of seconds. For example, to set the issue time to the current timestamp, calculate the issue time as the current timestamp divided by 1000.

Example
"iat" => time(),  // Issue timestamp
exp (required)

Type: Number

The exp represents the expiration timestamp, specified as the number of seconds. For example, to set a validity period of 10 minutes, calculate the expiration time as the current timestamp plus 600 seconds.

Example
"exp" => time() + (60 * 10),  // Expiration time (10 minutes)
auth (required)

Type: Object

The auth object contains AI-specific permissions that control which features the user can access.

The following example grants access to conversations, the recommended agent model, and system actions and reviews. See Permissions for the full list of available permissions.

Example
auth: {
  ai: {
    permissions: [
      "ai:conversations:read",
      "ai:conversations:write",
      "ai:models:agent",
      "ai:actions:system:*",
      "ai:reviews:system:*"
    ]
  }
}

See Permissions for a complete list of available permissions and best practices for configuring user access.

Set up JWT Endpoint

The following section shows how to create a JWT endpoint manually. If using a managed JWT service (such as AWS or Azure), configure it according to the requirements above and skip to the Configure TinyMCE section.

Server Setup (jwt.php)

In the root directory, copy and paste the server setup code into the jwt.php file.

<?php
require 'vendor/autoload.php'; // Setting up the Autoload
use \Firebase\JWT\JWT;

function fatalError($message) {
    http_response_code(500);
    header('Content-Type: application/json');
    die(json_encode(array("message" => "JWT auth failed: " . $message)));
}

// Check for OpenSSL extension
if (!extension_loaded('openssl')) {
    fatalError('The openssl extension must be enabled in php.ini.');
}

// Enable CORS
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept");

// JWT payload
$payload = array(
    "aud" => "no-api-key", // Replace with the actual API key
    "sub" => "user-id", // Replace with actual user identifier
    "iat" => time(), // Issue timestamp
    "exp" => time() + 60 * 10, // Expiration time (10 minutes)
    // Permissions control which AI features the user can access. See the Permissions page for full details.
    "auth" => array(
        "ai" => array(
            "permissions" => array(
                "ai:conversations:read",
                "ai:conversations:write",
                "ai:models:agent",
                "ai:actions:system:*",
                "ai:reviews:system:*"
            )
        )
    )
);

try {
    // Tokens are signed with the RS256 algorithm using the private key
    $privateKey = <<<'EOD'
-----BEGIN PRIVATE KEY-----
{Your private PKCS8 key goes here}
-----END PRIVATE KEY-----
EOD;
    $token = JWT::encode($payload, $privateKey, 'RS256');

    http_response_code(200);
    header('Content-Type: application/json');
    echo json_encode(array("token" => $token));
} catch (Exception $e) {
    fatalError($e->getMessage());
}
?>

The JWT payload includes an auth.ai.permissions array that defines what AI features the user can access. Adjust these permissions based on requirements. See Permissions for more details on available permissions.

Configure TinyMCE

Web Page (index.html)

Inside the root directory where the index.html file was created, add the HTML setup code.

<!DOCTYPE html>
<html>
<head>
  <title>{productname} with {pluginname}</title>
  <script
    src="https://cdn.tiny.cloud/1/no-api-key/tinymce/8/tinymce.min.js"
    referrerpolicy="origin"
    crossorigin="anonymous">
  </script>
  <script>
    tinymce.init({
      selector: 'textarea',
      plugins: 'tinymceai',
      toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
      // tinymceai_token_provider fetches a token from the `/jwt.php` endpoint.
      // This demo does not verify user session; it simulates an already-authenticated user. Integrate with your auth before returning tokens.
      tinymceai_token_provider: () => {
        return fetch('http://localhost:3000/jwt.php', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
        }).then(response => response.json());
      },
    });
  </script>
</head>
<body>
  <h1>{pluginname} Demo</h1>
  <textarea>
    Welcome to {productname}! Try the AI features like chat, quick actions, and review.
  </textarea>
</body>
</html>

Model configuration

Model selection can be configured using tinymceai_default_model and tinymceai_allow_model_selection. See Chat model configuration for details. Model access is controlled by JWT permissions; see Model permissions for available model permissions and AI Models for the list of available models.

Example: Adding model options to the JWT setup
tinymce.init({
  selector: 'textarea',
  plugins: 'tinymceai',
  toolbar: 'tinymceai-chat tinymceai-quickactions tinymceai-review',
  tinymceai_default_model: 'agent-1',
  tinymceai_allow_model_selection: true,
  // This demo does not verify user session; it simulates an already-authenticated user. Integrate with your auth before returning tokens.
  tinymceai_token_provider: () => {
    return fetch('http://localhost:3000/jwt.php', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
    }).then(response => response.json());
  },
});

Configuration and Running

Configuration Steps

Add API Key

  • Replace no-api-key in both files with the actual TinyMCE API key

  • The API key should be the same in both the HTML script source and the JWT payload

Add Private Key

  • Replace the private key placeholder in jwt.php with the actual private key

  • Make sure it’s in PKCS8 format

  • Keep this key secure and never share it publicly

Configure AI Permissions

  • Adjust the auth.ai.permissions array in the JWT payload based on requirements

  • See Permissions for available permissions and best practices

Configure model selection (optional)

  • Add tinymceai_default_model and tinymceai_allow_model_selection to the editor config if needed

  • See Model configuration for details

Running the Project

  1. Start the server:

    php -S localhost:3000
  2. Open the browser to: http://localhost:3000

  3. The following should be visible:

    • The TinyMCE editor

    • AI feature buttons in the toolbar (tinymceai-chat, tinymceai-quickactions, tinymceai-review)