Node.js and Express
Sign Ticketping identity tokens in Node.js with jose, as an Express route.
You’ll add one Express handler that signs a token with jose. jose has no dependencies and runs on Node.js, Bun, Deno and edge runtimes. For Next.js, SvelteKit and other full-stack frameworks, see their install pages.
Install jose
npm install joseSet 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-token.js:
import process from 'node:process'
import { SignJWT } from 'jose'
const secret = new TextEncoder().encode(process.env.TICKETPING_IDENTITY_SECRET)
export async function ticketpingToken(req, res) {
const user = req.user
if (!user) return res.sendStatus(401)
const profile = {}
if (user.email) profile.email = user.email
if (user.name) profile.name = user.name
const token = await new SignJWT(profile)
.setProtectedHeader({ alg: 'HS256' })
.setSubject(String(user.id))
.setExpirationTime('5m')
.sign(secret)
res.type('text/plain').send(token)
}req.user is the signed-in user, as set by Passport or your own session middleware. Mount the handler after that middleware:
import { ticketpingToken } from './ticketping-token.js'
app.post('/api/ticketping-token', ticketpingToken)The handler leaves out email and name when they’re empty, because Ticketping refuses null claims.
Already using jsonwebtoken? It works too: jwt.sign({ sub: String(user.id), email, name }, secret, { algorithm: 'HS256', expiresIn: '5m' }). Leave email and name out of that object when they’re empty.
Call it from the frontend
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 you use CSRF middleware such as csrf-csrf, add its header to the fetch. For a frontend on another origin, use the full URL and allow the origin with credentials in cors().
Check that it works
- Sign in on localhost and run
await (await fetch('/api/ticketping-token', { method: 'POST' })).text()in the browser console. - 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 Node.js / Express server.
Docs index: https://ticketping.com/llms.txt
This page as Markdown: https://ticketping.com/docs/identity-node.md
1. Install jose.
2. Add the ticketpingToken handler exactly as on the docs page and mount it at POST /api/ticketping-token after the
session/auth middleware: 401 when req.user is missing, otherwise
new SignJWT({ email, name }).setProtectedHeader({ alg: 'HS256' }).setSubject(String(user.id)).setExpirationTime('5m')
signed with new TextEncoder().encode(process.env.TICKETPING_IDENTITY_SECRET), sent as text/plain.
Leave email and name out of the payload when they're empty.
3. Add TICKETPING_IDENTITY_SECRET= to the env example file. Never commit the value or expose it to the browser.
4. In the frontend, call Ticketping('identify', { userId, email, name, getToken }) where getToken POSTs to the route
(with any CSRF header this app uses) and returns res.text().
5. Tell me how to verify with the token validator at Settings → API → Identity secret.