{"record":{"id":"bd6f9f1f21a712a9","repo":"Budibase/budibase","slug":"unexpected-token-payload","errorCode":null,"errorMessage":"Unexpected token payload","messagePattern":"Unexpected token payload","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/server/src/sdk/workspace/embedSSO/index.ts","lineNumber":85,"sourceCode":"): string | undefined => {\n  const value = emailClaim\n    .split(\".\")\n    .reduce<any>((acc, part) => (acc == null ? acc : acc[part]), payload)\n  return typeof value === \"string\" ? value : undefined\n}\n\nconst verifyToken = (\n  token: string,\n  config: EmbedSSOConfig\n): Record<string, any> => {\n  const key = decodeSecret(config.key)\n  const options: jwt.VerifyOptions = { algorithms: [config.algorithm] }\n  if (config.issuer) {\n    options.issuer = config.issuer\n  }\n  const decoded = jwt.verify(token, key, options)\n  if (typeof decoded === \"string\") {\n    throw new Error(\"Unexpected token payload\")\n  }\n  return decoded\n}\n\n/**\n * Verify a signed token from the embedding host, map its identity to an\n * existing Budibase user and, if found, establish a Budibase session by setting\n * the auth cookie. Returns true if the user was authenticated.\n */\nexport async function authenticateEmbedUser(\n  ctx: Ctx,\n  config: EmbedSSOConfig,\n  token: string\n): Promise<boolean> {\n  let payload: Record<string, any>\n  try {\n    payload = verifyToken(token, config)\n  } catch (err) {","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/embedSSO/index.ts#L67-L103","documentation":"jwt.verify normally returns either a string (when the JWT is an unsecured/unencoded payload or parsed as JWS with a string body) or a decoded object. This plain Error is thrown when jsonwebtoken returns a string payload instead of an object, meaning the token body is not the JSON object with claims (email, etc.) that embed SSO requires. The library only accepts object payloads because it reads claims like the configured emailClaim from the payload.","triggerScenarios":"Authenticating an embed user with a token whose decoded payload is a plain string — e.g. a token built with jsonwebtoken.sign(\"some-string\", secret) rather than sign(payloadObject, secret), or a hand-crafted/opaque token that happens to pass signature verification.","commonSituations":"The embedding host signs a raw string or non-JSON payload instead of a claims object; an old or incompatible SDK on the host side emits string tokens; a proxy or test harness sends an arbitrary opaque token signed with the shared secret.","solutions":["Fix the token producer to sign a JSON object payload containing at least the email claim, e.g. jwt.sign({ email: user.email }, key, { algorithm: config.algorithm })","Verify the embedding host's signing code uses the same key and algorithm configured in the embed SSO config","If tokens come from a third party that only produces string payloads, decode/transform them into an object before sending, or map a custom emailClaim path after signing an object"],"exampleFix":"// before (host side)\nconst token = jwt.sign(user.id, sharedSecret) // string payload\n// after\nconst token = jwt.sign({ email: user.email }, sharedSecret, { algorithm: \"HS256\" })","handlingStrategy":"try-catch","validationCode":"const headerB64 = token.split(\".\")[1]\nconst payload = JSON.parse(Buffer.from(headerB64, \"base64url\").toString())\nif (typeof payload !== \"object\" || payload === null || Array.isArray(payload)) {\n  throw new Error(\"Token payload must be a JSON object\")\n}","typeGuard":"const isJwtPayload = (v: unknown): v is Record<string, any> =>\n  typeof v === \"object\" && v !== null && !Array.isArray(v)","tryCatchPattern":"let payload: Record<string, any>\ntry {\n  payload = verifyToken(token, config)\n} catch (err) {\n  if (err.message === \"Unexpected token payload\") {\n    // token was signed with a non-object payload — reject and re-authenticate\n    return false\n  }\n  throw err\n}","preventionTips":["Sign JWTs with object payloads containing at least the email claim","Keep the embedding host's signing library and algorithm aligned with the embed SSO config","Validate token shape (decoded header/payload) in the host app before sending"],"tags":["jwt","sso","payload"],"backgroundTag":"jwt-invalid-payload","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}