{"record":{"id":"5282433a8372f39f","repo":"BoundaryML/baml","slug":"missing-crypto-api","errorCode":null,"errorMessage":"Missing crypto API","messagePattern":"Missing crypto API","errorType":"exception","errorClass":"JwtError","httpStatus":null,"severity":"error","filePath":"engine/baml-runtime/src/internal/wasm_jwt.rs","lineNumber":33,"sourceCode":"use js_sys::{Array, Object, Uint8Array};\nuse serde::{Deserialize, Serialize};\nuse serde_json::json;\nuse thiserror::Error;\nuse wasm_bindgen::JsValue;\nuse wasm_bindgen_futures::JsFuture;\nuse web_sys::{window, CryptoKey, SubtleCrypto};\n\n#[derive(Error, Debug)]\npub enum JwtError {\n    #[error(\"JavaScript error: {0:?}\")]\n    JsError(JsValue),\n    #[error(\"Base64 decode error: {0}\")]\n    Base64Error(#[from] base64::DecodeError),\n    #[error(\"JSON error: {0}\")]\n    JsonError(#[from] serde_json::Error),\n    #[error(\"Missing window object\")]\n    NoWindow,\n    #[error(\"Missing crypto API\")]\n    NoCrypto,\n}\n\nimpl From<JsValue> for JwtError {\n    fn from(err: JsValue) -> Self {\n        JwtError::JsError(err)\n    }\n}\n\npub async fn encode_jwt(\n    claims: &serde_json::Value,\n    private_key_pem: &str,\n) -> Result<String, JwtError> {\n    // Extract the crypto.subtle API\n    let window = window().ok_or(JwtError::NoWindow)?;\n    let crypto = window.crypto()?;\n    let subtle = crypto.subtle();\n","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/BoundaryML/baml/blob/bd85ce9dee1463ff04d27efd20531013a4ff46c1/engine/baml-runtime/src/internal/wasm_jwt.rs#L15-L51","documentation":"JwtError::NoCrypto is returned when the window exists but the WebCrypto API (window.crypto or crypto.subtle) is unavailable. SubtleCrypto is required for signing JWTs and is only exposed in secure contexts.","triggerScenarios":"Accessing window.crypto.subtle on a page served over plain http:// (insecure origin); very old browsers lacking WebCrypto; embedded webviews with crypto disabled.","commonSituations":"Local development served over http on non-localhost hosts (e.g. LAN IP); testing in an embedded WebView; corporate browser policies disabling crypto.subtle.","solutions":["Serve the application over HTTPS (or http://localhost, which is a secure context).","Check window.crypto?.subtle at startup and show a clear feature-unsupported message.","Upgrade to a browser that implements the Web Crypto API.","If stuck on http, proxy through a TLS-terminating server for development."],"exampleFix":"// before\nlet crypto = window.crypto().unwrap();\n// after\nlet crypto = window.crypto().ok_or(JwtError::NoCrypto)?;\nlet subtle = crypto.subtle().ok_or(JwtError::NoCrypto)?;","handlingStrategy":"validation","validationCode":"if (!window.isSecureContext || !window.crypto?.subtle) {\n  throw new Error(\"NoCrypto: WebCrypto requires a secure context (HTTPS)\");\n}","typeGuard":"function cryptoAvailable(w) {\n  return !!w.crypto && !!w.crypto.subtle;\n}","tryCatchPattern":"try {\n  const key = await importKey(rawKey);\n} catch (e) {\n  if (!window.crypto?.subtle) showHttpsWarning();\n  else throw e;\n}","preventionTips":["Serve all pages over HTTPS or localhost.","Feature-detect crypto.subtle at app startup and degrade gracefully.","Check embedded WebView crypto support before enabling JWT features."],"tags":["wasm","webcrypto","https","jwt"],"backgroundTag":"feature-not-enabled","analyzedSha":"bd85ce9dee1463ff04d27efd20531013a4ff46c1","analyzedAt":"2026-09-12T03:38:25.718Z","contentChangedAt":"2026-09-12T03:38:25.718Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}