Agent77

Token Endpoint Setup

The token endpoint is an API route on your backend that exchanges a user's existing session (cookie, OAuth token, etc.) for a short-lived JWT. The Agent77 widget calls this endpoint when a conversation starts.

Required JWT Claims

Claim Description Example
sub User identifier "user_92x7f"
aud Audience — must be "chatbot" "chatbot"
iss Issuer — your domain "https://app.example.com"
iat Issued-at timestamp (epoch seconds) 1700000000
exp Expiration timestamp 1700001800

Django Example

Uses djangorestframework-simplejwt for signing. Install with pip install djangorestframework-simplejwt.

# views.py
from datetime import timedelta
from django.conf import settings
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
import jwt, time

@api_view(["POST"])
@permission_classes([IsAuthenticated])
def chatbot_token(request):
    now = int(time.time())
    payload = {
        "sub": str(request.user.id),
        "aud": "chatbot",
        "iss": settings.SITE_URL,       # e.g. "https://app.example.com"
        "iat": now,
        "exp": now + 1800,              # 30 minutes
    }
    private_key = settings.CHATBOT_PRIVATE_KEY  # RSA PEM string
    token = jwt.encode(payload, private_key, algorithm="RS256",
                       headers={"kid": settings.CHATBOT_KEY_ID})
    return Response({"token": token})

Express / Node.js Example

Uses jsonwebtoken. Install with npm install jsonwebtoken.

// routes/chatbot-token.js
const jwt = require("jsonwebtoken");
const fs = require("fs");

const PRIVATE_KEY = fs.readFileSync("./keys/private.pem");
const KEY_ID = process.env.CHATBOT_KEY_ID;

module.exports = (req, res) => {
  if (!req.user) return res.status(401).json({ error: "Not authenticated" });

  const token = jwt.sign(
    {
      sub: req.user.id,
      aud: "chatbot",
      iss: process.env.SITE_URL,
    },
    PRIVATE_KEY,
    {
      algorithm: "RS256",
      expiresIn: "30m",
      keyid: KEY_ID,
    }
  );

  res.json({ token });
};

Rails Example

Uses ruby-jwt. Add gem "jwt" to your Gemfile.

# app/controllers/api/chatbot_tokens_controller.rb
class Api::ChatbotTokensController < ApplicationController
  before_action :authenticate_user!

  def create
    now = Time.now.to_i
    payload = {
      sub: current_user.id.to_s,
      aud: "chatbot",
      iss: ENV["SITE_URL"],
      iat: now,
      exp: now + 1800
    }
    private_key = OpenSSL::PKey::RSA.new(ENV["CHATBOT_PRIVATE_KEY"])
    token = JWT.encode(payload, private_key, "RS256",
                       { kid: ENV["CHATBOT_KEY_ID"] })
    render json: { token: token }
  end
end

Security Notes

  • Short-lived tokens. Set exp to 15–30 minutes. The widget will re-fetch a token when it expires.
  • Use RS256. Asymmetric signing lets Agent77 verify tokens using your public key without ever seeing your private key.
  • Authenticate first. The token endpoint must only issue JWTs for already-authenticated users. Never issue tokens to unauthenticated requests.
  • Include kid in the header. This lets Agent77 look up the correct public key from your JWKS endpoint, enabling key rotation.