Laravel and PHP

Sign Ticketping identity tokens in Laravel or plain PHP with firebase/php-jwt.

You’ll add one route that signs a token with firebase/php-jwt. The example is Laravel; plain PHP is at the end.

Install php-jwt

bash
composer require firebase/php-jwt

Set the secret

Get the identity secret from Settings → API → Identity secret and add it to .env. It’s the same value everywhere.

bash
TICKETPING_IDENTITY_SECRET=tpis_...

Read it through config, so it still works after php artisan config:cache.

config/services.php:

php
<?php

return [
    'ticketping' => [
        'identity_secret' => env('TICKETPING_IDENTITY_SECRET'),
    ],
];

Add the route

routes/web.php:

php
<?php

use Firebase\JWT\JWT;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;

Route::post('/api/ticketping-token', function (Request $request) {
    $user = $request->user();

    $claims = array_filter([
        'sub' => (string) $user->id,
        'email' => $user->email,
        'name' => $user->name,
        'exp' => time() + 300,
    ], fn ($value) => $value !== null && $value !== '');

    $token = JWT::encode($claims, config('services.ticketping.identity_secret'), 'HS256');

    return response($token)->header('Content-Type', 'text/plain');
})->middleware('auth');
  • The auth middleware stops signed-out requests.
  • array_filter drops an empty email or name, because Ticketping refuses null claims.
  • It’s in routes/web.php so it uses your normal session login. If your frontend authenticates with Sanctum tokens, put it in routes/api.php with auth:sanctum instead.

Call it from your layout

Laravel checks the CSRF token on POST. Send it from a meta tag, and send X-Requested-With so that Laravel answers 401 instead of redirecting to the login page when the session has ended.

html
<meta name="csrf-token" content="{{ csrf_token() }}">

@auth
<script>
  window.Ticketping ||= (...args) => (Ticketping.q ||= []).push(args)

  Ticketping('identify', {
    userId: @json((string) auth()->id()),
    email: @json(auth()->user()->email),
    name: @json(auth()->user()->name),
    getToken: async () => {
      const res = await fetch('/api/ticketping-token', {
        method: 'POST',
        headers: {
          'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
          'X-Requested-With': 'XMLHttpRequest'
        }
      })
      if (!res.ok) throw new Error(`Ticketping token request failed (${res.status})`)
      return res.text()
    }
  })
</script>
@endauth
<script src="https://widget.ticketping.com/v2/loader.js" data-key="pk_..." async></script>

Call Ticketping('logout') when the user signs out.

Plain PHP

Without a framework, the same signing code works in any script that knows the signed-in user:

php
<?php

use Firebase\JWT\JWT;

require __DIR__ . '/vendor/autoload.php';

session_start();

if ($_SERVER['REQUEST_METHOD'] !== 'POST' || empty($_SESSION['user'])) {
    http_response_code(401);
    exit;
}

$user = $_SESSION['user'];
$claims = array_filter([
    'sub' => (string) $user['id'],
    'email' => $user['email'] ?? null,
    'name' => $user['name'] ?? null,
    'exp' => time() + 300,
], fn ($value) => $value !== null && $value !== '');

header('Content-Type: text/plain');
echo JWT::encode($claims, getenv('TICKETPING_IDENTITY_SECRET'), 'HS256');

Check that it works

  1. Sign in on localhost and run this in the browser console:
js
await (await fetch('/api/ticketping-token', {
  method: 'POST',
  headers: {
    'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content,
    'X-Requested-With': 'XMLHttpRequest'
  }
})).text()
  1. Paste the token into the token validator under Settings → API → Identity secret. It shows the claims, or says exactly what to fix.
  2. Reload and send a message. The dashboard shows it with the user’s name and a Verified badge.

A 419 means the CSRF token is missing.

Copy prompt for your AI coding agent

prompt
Add Ticketping identity verification (chat widget v2) to this Laravel (or PHP) app.

Docs index: https://ticketping.com/llms.txt
This page as Markdown: https://ticketping.com/docs/identity-laravel.md

1. composer require firebase/php-jwt.
2. Add 'ticketping' => ['identity_secret' => env('TICKETPING_IDENTITY_SECRET')] to config/services.php,
   and TICKETPING_IDENTITY_SECRET= to .env.example. Never commit the value.
3. Add the POST /api/ticketping-token route exactly as on the docs page, behind the auth middleware: claims
   sub (string user id), email, name (dropped when empty), exp = time() + 300, signed with
   JWT::encode($claims, config('services.ticketping.identity_secret'), 'HS256'), returned as text/plain.
4. In the main layout, add the csrf-token meta tag and, inside @auth, the queue stub and
   Ticketping('identify', { userId, email, name, getToken }) where getToken POSTs with the X-CSRF-TOKEN and
   X-Requested-With: XMLHttpRequest headers and returns res.text(). Add the loader script with data-key="pk_..."
   and ask me for the publishable key. Call Ticketping('logout') on sign-out.
5. Tell me how to verify with the token validator at Settings → API → Identity secret.