Flask
Sign Ticketping identity tokens in Flask with PyJWT and Flask-Login.
You’ll add a blueprint with one POST route. This example uses Flask-Login; with another auth extension, swap in its decorator and current user.
Install PyJWT
pip install PyJWTSet 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.
TICKETPING_IDENTITY_SECRET=tpis_...Add the route
ticketping.py:
import os
import time
import jwt
from flask import Blueprint
from flask_login import current_user, login_required
ticketping = Blueprint("ticketping", __name__)
@ticketping.post("/api/ticketping-token")
@login_required
def ticketping_token():
claims = {"sub": str(current_user.id), "exp": int(time.time()) + 300}
if current_user.email:
claims["email"] = current_user.email
if current_user.name:
claims["name"] = current_user.name
token = jwt.encode(claims, os.environ["TICKETPING_IDENTITY_SECRET"], algorithm="HS256")
return token, 200, {"Content-Type": "text/plain"}Register the blueprint where you create the app:
from ticketping import ticketping
app.register_blueprint(ticketping)Change current_user.name to match your user model.
@login_required answers 401 when nobody is signed in, unless you’ve set a login_view. Then it redirects to your login page, and fetch would return that page’s HTML as the “token”. Make this blueprint answer 401 instead:
login_manager.blueprint_login_views = {"ticketping": None}If you use Flask-WTF’s CSRFProtect, either send the CSRF token from getToken (below), or exempt this route with csrf.exempt(ticketping). The route only signs a token for the user who’s already signed in, and its response can’t be read cross-origin.
Call it from your templates
{% if current_user.is_authenticated %}
<script>
window.Ticketping ||= (...args) => (Ticketping.q ||= []).push(args)
Ticketping('identify', {
userId: {{ current_user.id|string|tojson }},
email: {{ current_user.email|tojson }},
name: {{ current_user.name|tojson }},
getToken: async () => {
const res = await fetch('/api/ticketping-token', {
method: 'POST',
headers: { 'X-CSRFToken': '{{ csrf_token() }}' }
})
if (!res.ok) throw new Error(`Ticketping token request failed (${res.status})`)
return res.text()
}
})
</script>
{% endif %}
<script src="https://widget.ticketping.com/v2/loader.js" data-key="pk_..." async></script>Drop the X-CSRFToken header if you don’t use Flask-WTF. Call Ticketping('logout') when the user signs out.
Check that it works
- Sign in on localhost and run
await (await fetch('/api/ticketping-token', { method: 'POST' })).text()in the browser console (add the CSRF header if you use it). - Paste the token into the token validator under Settings → API → Identity secret. It shows the claims, or says exactly what to fix.
- Reload and send a message. The dashboard shows it with the user’s name and a Verified badge.
Copy prompt for your AI coding agent
Add Ticketping identity verification (chat widget v2) to this Flask app.
Docs index: https://ticketping.com/llms.txt
This page as Markdown: https://ticketping.com/docs/identity-flask.md
1. Add PyJWT to the dependencies.
2. Create the ticketping blueprint exactly as on the docs page and register it: POST /api/ticketping-token,
protected by this app's login decorator, returning jwt.encode({"sub": str(current_user.id), "exp": int(time.time()) + 300,
plus email and name only when non-empty}, os.environ["TICKETPING_IDENTITY_SECRET"], algorithm="HS256") as text/plain.
3. Add TICKETPING_IDENTITY_SECRET= to the env example file. Never commit the value.
4. In the base template, for signed-in users only, add the queue stub and Ticketping('identify', { userId, email, name, getToken })
with getToken POSTing to the route (with the CSRF header if Flask-WTF is used) and returning 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.