{"record":{"id":"2b7490d31090f7f7","repo":"usebruno/bruno","slug":"edgegrid-clientsecret-is-required","errorCode":null,"errorMessage":"EdgeGrid: clientSecret is required","messagePattern":"EdgeGrid: clientSecret is required","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/bruno-requests/src/auth/edgegrid-helper.js","lineNumber":48,"sourceCode":" * @param {string} [config.timestamp] - optional timestamp override\n * @param {string} [config.headersToSign] - comma-separated header names to sign\n * @param {string|number} [config.maxBodySize=131072]\n * @param {Object} request - axios request config ({ method, url, headers, data })\n * @returns {Promise<string>} Authorization header value\n */\nexport async function signEdgeGridRequest(config, request) {\n  const { accessToken, clientToken, clientSecret, baseURL, headersToSign } = config;\n  const maxBodySize = config.maxBodySize ? parseInt(config.maxBodySize, 10) : MAX_BODY_SIZE_DEFAULT;\n\n  // Validate required fields\n  if (!isStrPresent(accessToken)) {\n    throw new Error('EdgeGrid: accessToken is required');\n  }\n  if (!isStrPresent(clientToken)) {\n    throw new Error('EdgeGrid: clientToken is required');\n  }\n  if (!isStrPresent(clientSecret)) {\n    throw new Error('EdgeGrid: clientSecret is required');\n  }\n\n  // Generate or use provided nonce and timestamp\n  const nonce = isStrPresent(config.nonce) ? config.nonce : makeEdgeGridNonce();\n  const timestamp = isStrPresent(config.timestamp) ? config.timestamp : makeEdgeGridTimestamp();\n\n  // Determine the URL to sign — use baseURL's host/protocol if provided, otherwise the request URL.\n  let urlToSign = request.url;\n  if (isStrPresent(baseURL)) {\n    const requestUrl = new URL(request.url);\n    // A scheme-less baseURL like \"localhost:6000\" mis-parses (\"localhost:\" becomes the protocol\n    // and the host is empty). If there's no \"scheme://\", borrow the request URL's scheme.\n    const normalizedBaseURL = /^[a-z][a-z0-9+.-]*:\\/\\//i.test(baseURL.trim())\n      ? baseURL.trim()\n      : `${requestUrl.protocol}//${baseURL.trim()}`;\n    const baseParsed = new URL(normalizedBaseURL);\n    urlToSign = `${baseParsed.protocol}//${baseParsed.host}${requestUrl.pathname}${requestUrl.search}`;\n  }","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/usebruno/bruno/blob/9bdd81c7bdc57006e5f5ebffb79321a8d979f712/packages/bruno-requests/src/auth/edgegrid-helper.js#L30-L66","documentation":"Thrown by Bruno's Akamai EdgeGrid signing helper when the `clientSecret` field is missing or blank (isStrPresent returns false). The client secret is the HMAC key material for the signing key, so without it the signature cannot be computed.","triggerScenarios":"Configuring EdgeGrid auth with an empty or unset clientSecret — e.g. the secret was never pasted in, or the Bruno variable holding it is undefined in the active environment.","commonSituations":"Secret field cleared for security and not re-populated; secret stored under a different variable name; wrong environment active.","solutions":["Set config.clientSecret to the Akamai API client secret.","Confirm the Bruno variable providing the secret is defined in the current environment.","Treat all three EdgeGrid fields as required and validate them together before signing."],"exampleFix":"// before\nconst config = { accessToken: '...', clientToken: '...' }; // clientSecret missing\n\n// after\nconst config = {\n  accessToken: bru.getVar('EDGEGRID_ACCESS_TOKEN'),\n  clientToken: bru.getVar('EDGEGRID_CLIENT_TOKEN'),\n  clientSecret: bru.getVar('EDGEGRID_CLIENT_SECRET')\n};","handlingStrategy":"validation","validationCode":"function validateEdgeGrid(cfg) {\n  const missing = ['clientSecret'].filter((k) => !cfg[k] || !String(cfg[k]).trim());\n  if (missing.length) throw new Error('EdgeGrid missing: ' + missing.join(','));\n}","typeGuard":"const hasClientSecret = (cfg) => typeof cfg?.clientSecret === 'string' && cfg.clientSecret.trim().length > 0;","tryCatchPattern":"try { await signEdgeGridRequest(config, request); }\ncatch (err) {\n  if (/clientSecret is required/.test(err.message)) { config.clientSecret = bru.getVar('EDGEGRID_CLIENT_SECRET'); }\n  else throw err;\n}","preventionTips":["Never clear a secret field without recording where to re-supply it.","Store secrets in the active Bruno environment, not the collection.","Validate the trio together before signing."],"tags":["bruno-requests","auth","edgegrid","akamai","validation","secrets"],"backgroundTag":null,"analyzedSha":"9bdd81c7bdc57006e5f5ebffb79321a8d979f712","analyzedAt":"2026-08-13T04:09:25.751Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}