pynetbox icon indicating copy to clipboard operation
pynetbox copied to clipboard

`nb.version` causes 403 with a valid token

Open markkuleinio opened this issue 3 weeks ago • 6 comments

pynetbox version

v7.5.0

NetBox version

v4.4.7

Python version

3.11

Steps to Reproduce

On NetBox server:

sudo tail -f /var/log/nginx/access.log | grep /api/

Then:

import pynetbox

nb = pynetbox.api(NETBOX_URL, NETBOX_TOKEN)
nb.version

Expected Behavior

Request handled with status 200, and no errors in Django logs.

Observed Behavior

Request handled with status 403:

xxx.xxx.xxx.xxx - - [03/Dec/2025:15:39:34 +0200] "GET /api/ HTTP/1.1" 403 58 "-" "python-requests/2.32.5"

There is also error in Django logs (when logging has been enabled):

2025-12-03 15:39:34,257 django.request WARNING: Forbidden: /api/

The reason seems to be that Request.get_version() does not set the token in the request header:

https://github.com/netbox-community/pynetbox/blob/a2853726b5495e22cd16fcfec04efef2c7f5b2f2/pynetbox/core/query.py#L262-L264

markkuleinio avatar Dec 03 '25 13:12 markkuleinio

If accepted, I can send PR for this.

markkuleinio avatar Dec 03 '25 13:12 markkuleinio

Request.get_openapi() doesn't supply the token either, but apparently NetBox allows the /api/schema/ call without token, while /api/ call (used by Request.get_version()) requires the auth token.

markkuleinio avatar Dec 03 '25 18:12 markkuleinio

See also #641 where the intent of using token when getting version was presented.

markkuleinio avatar Dec 04 '25 17:12 markkuleinio

@markkuleinio The nb.version call is working fine for me, there is no 403 error shown. I'm not sure from your bug report if you are passing a valid token and you you are getting this error. I am passing a valid token when I setup pynetbox and the subsequent nb.version call is working fine and returns the correct version number.

arthanson avatar Dec 08 '25 16:12 arthanson

Here I get 403 in all these three cases:

>>> nb = pynetbox.api("http://netbox-test.lein.io/")
>>> nb.version
'4.4'
>>> nb = pynetbox.api("http://netbox-test.lein.io/", token="invalidtoken")
>>> nb.version
'4.4'
>>> # This is a correct token:
>>> nb = pynetbox.api("http://netbox-test.lein.io/", token="3db66aecdeb0e6613cb17e4cbdb1939b34dca416")
>>> nb.version
'4.4'
>>>

Corresponding logs:

$ sudo tail -f /var/log/nginx/access.log | grep /api/
x.x.x.x - - [08/Dec/2025:18:45:42 +0200] "GET /api/ HTTP/1.1" 403 58 "-" "python-requests/2.32.3"
x.x.x.x - - [08/Dec/2025:18:45:58 +0200] "GET /api/ HTTP/1.1" 403 58 "-" "python-requests/2.32.3"
x.x.x.x - - [08/Dec/2025:18:46:06 +0200] "GET /api/ HTTP/1.1" 403 58 "-" "python-requests/2.32.3"
$ sudo grep LOGIN_REQUIRED /opt/netbox/netbox/netbox/configuration.py
LOGIN_REQUIRED = True

(If I set LOGIN_REQUIRED = False, then I get all 200's.)

If I add the token in the Request.get_version() call (as drafted in https://github.com/markkuleinio/pynetbox/commit/f865ccd90087bcbdad7275d5502fb34a52b2abce), then I get these with the same commands above:

x.x.x.x - - [08/Dec/2025:18:57:01 +0200] "GET /api/ HTTP/1.1" 403 58 "-" "python-requests/2.32.5"
x.x.x.x - - [08/Dec/2025:18:57:07 +0200] "GET /api/ HTTP/1.1" 403 26 "-" "python-requests/2.32.5"
x.x.x.x - - [08/Dec/2025:18:57:11 +0200] "GET /api/ HTTP/1.1" 200 609 "-" "python-requests/2.32.5"

= the last one with the correct token gets a 200, as expected.

markkuleinio avatar Dec 08 '25 16:12 markkuleinio

Thanks for following up, @markkuleinio. I can reproduce what you're seeing. When using a valid token to instantiate a pynetbox.api object, the token is not actually being passed to the API call that is made via <api obj>.version. The feature continues to work, however, since the version is read from the API response headers, which is present even on 403 responses.

I'm assigning to you. Thanks for volunteering.

jnovinger avatar Dec 15 '25 19:12 jnovinger