Pickaxe Learn

Get Started

Authenticated Embeds

Automatically sign website users into embeds using a short-lived signed ES256 JWT.


Related In Learn

Embeds

Add your agents directly to any website with embed code snippets.

Open Learn

Authenticated Embeds let you place a Pickaxe embed on your own website and automatically sign in visitors who are already logged into your app.

Pickaxe handles the final session creation for the embed. Your website only needs to prove the visitor's identity by returning a short-lived signed JWT.

Important: this system uses a signed JWT, not an encrypted JWT.

What Your Website Must Implement

Your website needs four pieces:

  • A normal logged-in session for your own users.
  • A server-side ES256 private key stored securely on your backend.
  • A backend endpoint that returns a short-lived signed JWT for the current logged-in user.
  • A frontend getJwt function inside window.PickaxeConfig so the embed can request that JWT.

Your website does not need to exchange the JWT for a Pickaxe session token itself. The Pickaxe embed runtime does that automatically.

Workspace Setup In Pickaxe

Open Workspace Settings > Embed SSO and configure:

  • Enable customer-authenticated embeds: turn this on.
  • Trusted issuer: the exact issuer string your backend signs into the JWT, for example https://app.example.com.
  • Signing key ID: the exact kid value your backend puts in the JWT header, for example customer-key-2026-04.
  • Public key: the PEM-encoded public key matching your backend private key.
  • Allowed host origins: every website origin where the embed will run, for example https://app.example.com or https://portal.example.com:8443.

Origin format rules:

  • Include protocol: https://app.example.com
  • Include port when needed: https://app.example.com:3000
  • Do not include a path: use https://app.example.com, not https://app.example.com/account
  • Avoid issuer mismatches caused by trailing slash differences

Also make sure the deployment itself allows the same website domain in its normal embed domain allowlist. Embed SSO does not replace the deployment domain check.

JWT Requirements

Use this JWT header shape:

{
  "alg": "ES256",
  "kid": "customer-key-2026-04",
  "typ": "JWT"
}

Required Claims

Use these claims in the JWT payload:

{
  "iss": "https://app.example.com",
  "aud": "pickaxe-embed",
  "sub": "user_123",
  "customer_id": "YOUR_WORKSPACE_ID",
  "email": "user@example.com",
  "external_user_id": "user_123"
}

These are the minimum identity claims your website should send.

Field rules:

  • iss: must exactly match Trusted issuer in Pickaxe.
  • aud: must be exactly pickaxe-embed.
  • sub: should be a stable external user identifier from your system.
  • customer_id: should be your Pickaxe workspace ID.
  • email: should be the end user's real email address.
  • external_user_id: should usually match sub.

Frontend Example

Add the embed bundle, container, and getJwt function on your page:

<script>
  window.PickaxeConfig = {
    "deployment-YOUR_DEPLOYMENT_ID": {
      sso: {
        getJwt: async ({ deploymentId, studioId, pickaxeId }) => {
          const response = await fetch("/api/pickaxe/embed-sso-token", {
            method: "POST",
            credentials: "include",
            headers: {
              "Content-Type": "application/json",
            },
            body: JSON.stringify({
              deploymentId,
              studioId,
              pickaxeId,
            }),
          });

          if (!response.ok) return null;

          const data = await response.json();
          return data.token || null;
        },
      },
    },
  };
</script>

<script src="https://studio.pickaxe.co/api/embed/bundle.js" defer></script>
<div id="deployment-YOUR_DEPLOYMENT_ID"></div>

The getJwt function receives:

  • deploymentId
  • studioId
  • pickaxeId

It should return:

  • a signed JWT string when the visitor is logged in
  • null when the visitor is not logged in or your site does not want to auto-sign them in

If you want one shared handler for all embeds on the page, you can also define window.PickaxeConfig.sso.getJwt globally instead of attaching it to one deployment ID.

Backend Example Contract

Your backend endpoint can use any internal route you want. A common pattern is:

Request

POST /api/pickaxe/embed-sso-token

{
  "deploymentId": "deployment-YOUR_DEPLOYMENT_ID",
  "studioId": "studio-123",
  "pickaxeId": "pickaxe-123"
}

The endpoint should:

  • read the current logged-in website user from your own cookie or session
  • reject the request if the browser is not logged in
  • build a short-lived JWT for that user
  • sign it with your private ES256 key
  • return the signed JWT

Response

{
  "token": "SIGNED_JWT_HERE"
}

Important security rules:

  • Keep the private key on the server only.
  • Never put the private key in frontend JavaScript.
  • Do not return a long-lived token.
  • Do not send passwords or raw login credentials to Pickaxe.

What Pickaxe Does After getJwt

Once your frontend returns the signed JWT:

  1. The embed sends that JWT to Pickaxe.
  2. Pickaxe verifies the signature using the public key from your workspace settings.
  3. Pickaxe checks issuer, audience, expiry, key ID, and origin.
  4. Pickaxe finds or creates the matching studio user.
  5. Pickaxe creates the final Pickaxe session token for the embed.
  6. The embed stores and uses that Pickaxe session automatically.

Your website does not need to handle the Pickaxe session token directly.

Quick Checklist

  • Create an embed deployment and allow your website domain.
  • Turn on Workspace Settings > Embed SSO.
  • Add issuer, key ID, public key, and allowed origins.
  • Generate ES256-signed JWTs on your backend.
  • Return those JWTs from a backend endpoint for the current logged-in user.
  • Implement window.PickaxeConfig.sso.getJwt or window.PickaxeConfig[deploymentId].sso.getJwt.
  • Mount the normal Pickaxe embed bundle and deployment <div>.

If getJwt returns null, the embed can still fall back to its normal auth flow.