#9371·bruno

bru run: API key auth with placement: queryparams is not sent when the URL or key value contains {{variables}}

Author: norpanCreated Sep 25, 2026Updated Sep 29, 2026
Labelsbugstatus-new

Internal - [BRU-4681]

I have checked the following:

  • I have searched existing issues and found nothing related to my issue.

This bug is:

  • Making Bruno unusable for me.
  • Slowing me down but I'm able to continue working.
  • Annoying.
  • This feature was working in a previous version but is broken in the current release.

Bruno version

CLI 4.2.0

Operating System

Linux

Specific OS Version / Distro

Debian

Describe the bug

With auth:apikey and placement: queryparams, bru run only sends the key when neither the request URL nor the key value contains a variable. That rules out the usual {{baseUrl}}/path + {{apiKey}} setup.

  1. URL starts with a variable ({{baseUrl}}/echo): the CLI logs Invalid URL: {{baseUrl}}/echo?a=1 TypeError: Invalid URL and sends the request without the key. It still reports 200 OK and ✓ PASS when there are no assertions, so the failure is easy to miss.
  2. Literal URL but the value is a variable (value: {{apiKey}}): the key is sent as key=%7B%7BapiKey%7D%7D, the percent-encoded placeholder. The variable is never substituted.

This happens with both collection-level auth (auth: inherit) and request-level auth. placement: header works with variables in both the URL and the value.

The cause is in packages/bruno-cli/src/runner/prepare-request.js. Both the collection-level branch (line 87 in 4.2.0) and the request-level branch (line 343) do:

javascript
const urlObj = new URL(request.url);
urlObj.searchParams.set(request.auth.apikey?.key, request.auth.apikey?.value);
axiosRequest.url = urlObj.toString();

prepareRequest runs before interpolateVars (run-single-request.js lines 183 and 385). So:

  • new URL('{{baseUrl}}/…') throws; the error is caught and only logged.
  • searchParams.set percent-encodes the {{apiKey}} placeholder, and the later interpolation no longer recognizes it.

Adding the query parameter after interpolation would fix both cases.

Related but different: #3492 and #3732 were about API key auth not being applied at all and were fixed in 2.3.0.

Steps to reproduce

  1. Start an echo server: node -e 'require("http").createServer((q,r)=>{console.log(q.url);r.end("ok")}).listen(4599)'
  2. Create the collection below.
  3. Run bru run --env local in the collection folder.
  4. Compare the URLs the server logs with the expected ones:
Request Server received Expected
1 inherited key, {{baseUrl}} URL /echo?a=1 /echo?a=1&key=secret123
2 request key, {{baseUrl}} URL /echo?a=1 /echo?a=1&key=secret123
3 request key {{apiKey}}, literal URL /echo?a=1&key=%7B%7BapiKey%7D%7D /echo?a=1&key=secret123
4 literal key value, literal URL /echo?a=1&key=secret123 ✅
5 placement: header, {{baseUrl}} URL header x-api-key: secret123 ✅

All five requests are reported as 200 OK, and the run as ✓ PASS.

Collection to reproduce

bruno.json

json
{ "version": "1", "name": "apikey-queryparams-repro", "type": "collection" }

collection.bru

auth {
  mode: apikey
}

auth:apikey {
  key: key
  value: {{apiKey}}
  placement: queryparams
}

environments/local.bru

vars {
  baseUrl: http://localhost:4599
  apiKey: secret123
}

1.bru (inherited key)

meta {
  name: 1 inherited key, url with baseUrl
  type: http
  seq: 1
}

get {
  url: {{baseUrl}}/echo?a=1
  body: none
  auth: inherit
}

2.bru (request-level key)

meta {
  name: 2 request key, url with baseUrl
  type: http
  seq: 2
}

get {
  url: {{baseUrl}}/echo?a=1
  body: none
  auth: apikey
}

auth:apikey {
  key: key
  value: {{apiKey}}
  placement: queryparams
}

3.bru is the same as 2.bru with url: http://localhost:4599/echo?a=1.

Screenshots/Live demo link

CLI output (stack traces trimmed):

Invalid URL: {{baseUrl}}/echo?a=1 TypeError: Invalid URL
  code: 'ERR_INVALID_URL',
  input: '{{baseUrl}}/echo?a=1'
1 inherited key, url with baseUrl (200 OK) - 14 ms
Invalid URL: {{baseUrl}}/echo?a=1 TypeError: Invalid URL
2 request key, url with baseUrl (200 OK) - 1 ms
3 request key, literal url (200 OK) - 1 ms
4 request key literal value, literal url (200 OK) - 0 ms
5 header placement, url with baseUrl (200 OK) - 1 ms
│ Status        │    ✓ PASS    │

Server log:

/echo?a=1
/echo?a=1
/echo?a=1&key=%7B%7BapiKey%7D%7D
/echo?a=1&key=secret123
/echo?a=1  x-api-key: secret123