Jupid Partner Docs

Next.js

Next.js route handler example for signing Jupid Embed tokens.

Use a server-only route handler to sign the token. The exact authentication method depends on the partner app; the route must only run for an authenticated partner user.

Install a JWT signer

bun add jose

Route handler

import { SignJWT } from "jose"
import { NextResponse } from "next/server"

const secret = new TextEncoder().encode(process.env.JUPID_EMBED_SECRET)

export async function GET() {
  const user = await getCurrentUser()
  const now = Math.floor(Date.now() / 1000)
  const token = await new SignJWT({
    email: user.email,
    name: user.name,
    payload: {
      company_name: user.companyName,
    },
  })
    .setProtectedHeader({ alg: "HS256", typ: "JWT" })
    .setIssuer(process.env.JUPID_EMBED_PARTNER_ID)
    .setAudience("jupid-embed")
    .setSubject(user.id)
    .setIssuedAt(now)
    .setExpirationTime(now + 300)
    .setJti(crypto.randomUUID())
    .sign(secret)

  return NextResponse.json({ token })
}

getCurrentUser represents the partner app's own authenticated user lookup. Keep this route on the server and never sign tokens from a Client Component.

Client component

"use client"

import { useEffect, useRef } from "react"

export function JupidEmbed() {
  const containerRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    async function mount() {
      const response = await fetch("/api/jupid/embed-token")
      const data = await response.json()
      const container = containerRef.current!

      window.JupidEmbed.mount({
        partnerId: "your-partner-id",
        token: data.token,
        container,
        initialPath: "/",
        appUrl: "https://jupid-staging-app.example.com",
      })
    }

    mount()
  }, [])

  return <div ref={containerRef} className="min-h-[720px]" />
}

Add the SDK script to the page or layout that renders the component:

import Script from "next/script"

export function JupidEmbedPage() {
  return (
    <>
      <Script
        src="https://jupid-staging-app.example.com/embed.js"
        strategy="afterInteractive"
      />
      <JupidEmbed />
    </>
  )
}

If your TypeScript setup needs the browser global, declare it in the partner app:

declare global {
  interface Window {
    JupidEmbed: {
      mount(options: {
        partnerId: string
        token: string
        container: HTMLElement
        initialPath?: string
        appUrl?: string
      }): {
        destroy(): void
      }
    }
  }
}

On this page