FastAPI

Sign Ticketping identity tokens in FastAPI with PyJWT, using your existing auth dependency.

You’ll add one router with a POST route. It reuses the dependency your app already has for the signed-in user.

Install PyJWT

bash
pip install PyJWT

Set the secret

Get the identity secret from Settings → API → Identity secret and set it in your server’s environment. It’s the same value everywhere.

bash
TICKETPING_IDENTITY_SECRET=tpis_...

Add the route

app/ticketping.py:

python
import os
import time

import jwt
from fastapi import APIRouter, Depends
from fastapi.responses import PlainTextResponse

from app.auth import get_current_user

router = APIRouter()


@router.post("/api/ticketping-token", response_class=PlainTextResponse)
def ticketping_token(user=Depends(get_current_user)):
    claims = {"sub": str(user.id), "exp": int(time.time()) + 300}
    if user.email:
        claims["email"] = user.email
    if user.name:
        claims["name"] = user.name

    return jwt.encode(claims, os.environ["TICKETPING_IDENTITY_SECRET"], algorithm="HS256")

get_current_user is your existing auth dependency. It should raise 401 when nobody is signed in, so the route never signs a token for an anonymous request. Change user.id, user.email and user.name to match your user model.

Register the router:

python
from app.ticketping import router as ticketping_router

app.include_router(ticketping_router)

The route is a plain def, so FastAPI runs it in a thread pool. Signing takes microseconds, so async def works just as well.

Call it from the frontend

js
Ticketping('identify', {
  userId: user.id,
  email: user.email,
  name: user.name,
  getToken: async () => {
    const res = await fetch('/api/ticketping-token', { method: 'POST', credentials: 'include' })
    if (!res.ok) throw new Error(`Ticketping token request failed (${res.status})`)
    return res.text()
  }
})

If your API authenticates with a bearer token, add your Authorization header to the fetch. If the frontend is on another origin, use the API’s full URL and allow the frontend in CORSMiddleware with allow_credentials=True.

Check that it works

  1. Sign in to your app on localhost and fetch a token from the browser console with the fetch above.
  2. Paste it into the token validator under Settings → API → Identity secret. It shows the claims, or says exactly what to fix.
  3. Reload and send a message. The dashboard shows it with the user’s name and a Verified badge.

In tests, override the dependency and decode the result:

python
from types import SimpleNamespace

import jwt
from fastapi.testclient import TestClient

from app.auth import get_current_user
from app.main import app


def test_signs_the_signed_in_user(monkeypatch):
    monkeypatch.setenv("TICKETPING_IDENTITY_SECRET", "test-secret-at-least-32-bytes-long")
    user = SimpleNamespace(id=123, email="ada@acme.com", name="Ada")
    app.dependency_overrides[get_current_user] = lambda: user

    res = TestClient(app).post("/api/ticketping-token")

    claims = jwt.decode(res.text, "test-secret-at-least-32-bytes-long", algorithms=["HS256"])
    assert claims["sub"] == "123"

Copy prompt for your AI coding agent

prompt
Add Ticketping identity verification (chat widget v2) to this FastAPI app.

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

1. Add PyJWT to the dependencies.
2. Create app/ticketping.py exactly as on the docs page, using this app's existing current-user dependency
   (it must raise 401 when signed out): POST /api/ticketping-token with response_class=PlainTextResponse, returning
   jwt.encode({"sub": str(user.id), "exp": int(time.time()) + 300, plus email and name only when non-empty},
   os.environ["TICKETPING_IDENTITY_SECRET"], algorithm="HS256"). Include the router in the app.
3. Add TICKETPING_IDENTITY_SECRET= to the env example file. Never commit the value.
4. In the frontend, call Ticketping('identify', { userId, email, name, getToken }) where getToken POSTs to the route
   with this app's auth (cookies or Authorization header) and returns res.text(). Configure CORS if the frontend is on another origin.
5. Add a test that overrides the auth dependency and decodes the token.
6. Tell me how to verify with the token validator at Settings → API → Identity secret.