Server-side token generation (SSO)¶
Both the Trip Planner Widget and the SSO Button Widget request a signed token from your backend (data-token-url). Traveln verifies it on /sso-login/ and creates a session.
Token endpoint¶
Implement a POST endpoint (for example /api/traveln/sso/) that returns:
{ "token": "..." }
Request payloads¶
The two web embeds send slightly different client payloads to your token endpoint.
Trip Planner Widget request¶
{ "prompt": "string", "trace_id": "string" }
SSO Button Widget request¶
{ "trace_id": "string" }
You can ignore fields you do not need. The button target itself is controlled by data-button-type on the Traveln loader and is forwarded by Traveln during the /sso-login/ redirect.
Token format¶
This is not a JWT.
The token is:
base64url(payload_json_bytes) + "." + base64url(hmac_sha256(secret, payload_json_bytes))
Required payload fields¶
tenant_slug(string)user_id(string)ts(integer, unix seconds)nonce(string, unique per token)
Optional payload fields¶
first_name,last_name,email,phone,picturehost(string): when present, Traveln binds the token to both the request host and the token host (both must be registered for the tenant).is_anonymous(bool/string): when true or identity is missing, Traveln may create a "Guest User" session.
Replay protection
Nonces are one-time use and timestamps are short-lived. Do not reuse tokens.
Example (Python)¶
import base64
import hmac
import json
import time
from hashlib import sha256
from uuid import uuid4
def b64url(data: bytes) -> str:
return base64.urlsafe_b64encode(data).decode("utf-8").rstrip("=")
def create_traveln_sso_token(*, tenant_slug: str, user_id: str, secret: str, host: str | None = None) -> str:
payload = {
"tenant_slug": tenant_slug,
"user_id": user_id,
"ts": int(time.time()),
"nonce": uuid4().hex,
}
if host:
payload["host"] = host
payload_bytes = json.dumps(payload, separators=(",", ":"), ensure_ascii=False).encode("utf-8")
sig = hmac.new(secret.encode("utf-8"), payload_bytes, sha256).digest()
return f"{b64url(payload_bytes)}.{b64url(sig)}"
Runtime behavior after token creation¶
Once your endpoint returns { "token": "..." }:
- Traveln receives the signed token.
- Traveln verifies the tenant, timestamp, nonce, and HMAC signature.
- Traveln creates a local session for the user.
- Traveln redirects the user to the destination requested by the widget flow:
- Trip planner widget ->
/ai-trip-planner/ - Button widget with
trip_planner->/ai-trip-planner/ - Button widget with
trips->/trips/ - Button widget with
accommodation_search->/accommodation-search/