Secure JWT handshake¶
GET https://dev.sahl-ai.pages.dev/jwt-auth-secure
Use this mode with PKI authentication. Your page sends the signed assertion to the panel. The panel exchanges it for a session token itself, so your backend never calls the exchange endpoint.
1. Embed the panel¶
<iframe id="sahl-iframe"
src="https://dev.sahl-ai.pages.dev/jwt-auth-secure?theme=<your-theme>"
allow="microphone; display-capture"></iframe>
Only theme goes in the URL. Leave it out if Sahl AI has not given you one.
2. Answer the handshake¶
const SAHL_ORIGIN = "https://dev.sahl-ai.pages.dev";
const sahlFrame = document.getElementById("sahl-iframe");
window.addEventListener("message", (event) => {
if (event.origin !== SAHL_ORIGIN) return;
if (event.source !== sahlFrame.contentWindow) return;
if (event.data?.type === "SAHL_IFRAME_READY") {
sahlFrame.contentWindow.postMessage(
{
type: "SAHL_IFRAME_INIT",
payload: {
token: SIGNED_ASSERTION, // required: note the key is "token"
px_id: "PATIENT_ID",
ex_id: "ENCOUNTER_ID",
ux_id: "USER_ID",
age: 3652, // age in days (10 years)
gender: "male",
cta: "Send to HIS"
}
},
SAHL_ORIGIN
);
return;
}
if (event.data?.type === "AUTH_ERROR") {
console.error("Sahl authentication failed:", event.data.error);
return;
}
handleSahlData(event.data);
});
Differences from the access-token handshake¶
| Secure handshake | Secure JWT handshake | |
|---|---|---|
| Entry point | /iframe-secure |
/jwt-auth-secure |
| Credential key in payload | access_token |
token |
| Credential | Access token from /users/login |
Signed assertion |
| On failure | Error shown in the panel | Error shown in the panel and AUTH_ERROR posted to your page |
Rules¶
- One assertion per launch. Each assertion can be exchanged only once. Sign a new one every time you load or reload the panel. Follow the claim rules in Signed JWT:
expno more than 5 minutes ahead, a currentiatand a freshjti. - Reply within 10 seconds of
SAHL_IFRAME_READY. - Reloads: set
srcback to/jwt-auth-secure?theme=...and answer the newREADYwith a new assertion. - No context in the URL:
px_id,ex_id,ux_id,age,genderandctago in the payload only. - Write-back messages go only to the origin that completed the handshake.
Errors¶
When the panel cannot authenticate, it posts:
Log it or show it. Common causes are an expired or reused assertion, a kid that has not been registered, or a clock that is out of sync.