NetAuto Academy

APIs and REST for Network Engineers

Authentication and the Read/Write Safety Boundary

Intermediate13 min read

What you'll learn

  • How token-based authentication headers work, conceptually
  • Why credentials never belong in source code, the same rule as every prior module
  • What POST/PUT/PATCH/DELETE are for, and why they need explicit review
  • How this maps directly onto dry_run=True and --check from earlier modules
🎓 Teach This Lesson

Listen to a guided explanation of this lesson.

Spoken narration isn't supported in this browser.

Token-based authentication

Most real APIs require proving who's asking, usually via a header carrying a token:

authenticated_request.py
import requests

headers = {"Authorization": "Bearer demo-token"}
response = requests.get("http://127.0.0.1:8765/devices/SW1/vlans", headers=headers)
print(response.status_code)

headers={} attaches extra metadata to the request — Authorization: Bearer <token> is the most common convention for API tokens. This module's mock API doesn't require this header for GET requests; it's shown here because POST requests below do.

Never hardcoded — the same rule since Netmiko Fundamentals

A token is a credential, exactly like the username/password Netmiko Fundamentals taught to source only from getpass()/input()/environment variables — never typed directly into a script. Every example in this lesson uses an obvious placeholder token ("demo-token") against a safe local mock, precisely the same discipline "Connecting to a Device with Netmiko" established for SSH credentials.

Quick checkConcept check
Where should a real API token come from in a script?

GET is safe; everything else needs a second thought

GET
  1. Read-only, by conventionnever changes anything
  2. Safe to call freelythe default posture
POST / PUT / PATCH / DELETE
  1. Creates, replaces, updates, or removes something
  2. Requires the same explicit review as send_config_set() / ios_config
Quick checkConcept check
Which HTTP methods require the same explicit-review discipline this curriculum already applies to send_config_set() and ios_config?

A POST request, against the safe local mock only

create_vlan.py
new_vlan = {"id": 40, "name": "GUEST"}
headers = {"Authorization": "Bearer demo-token"}

response = requests.post(
  "http://127.0.0.1:8765/devices/SW1/vlans",
  json=new_vlan,
  headers=headers,
)
print(response.status_code)
print(response.json())

json=new_vlan does two things: sets the Content-Type header to application/json, and serializes the dict into the request body — the POST equivalent of a Jinja2-rendered config block, sent as structured data instead of CLI text.

output
201
{'hostname': 'SW1', 'created': {'id': 40, 'name': 'GUEST'}}

Real, verified output — 201 Created (not 200) is the conventional status code for a successful POST that created something new. Run only against this module's safe local mock, never against a real controller by default.

Quick checkIdentify the correct code
Which line correctly sends a JSON body with a POST request using the requests library?

What happens without the right credentials

missing_auth.py
response = requests.post(
  "http://127.0.0.1:8765/devices/SW1/vlans",
  json={"id": 40, "name": "GUEST"},
  # no Authorization header this time
)
print(response.status_code)
print(response.json())

The exact same request as before, minus the Authorization header.

output
401
{'error': 'authentication required'}

Real, verified output. Exactly the response this module's mock API is built to give for any POST without valid credentials — mutation requires proving who's asking, GET does not.

Quick checkPredict output
A POST request is sent with a correct Authorization header, but the JSON body is missing the required "name" field. Based on how this lesson's mock API is built, what status code comes back?

The direct mapping to what this curriculum already taught

Same principle, new vocabulary

dry_run=True (Reliable Automation) and --check (Ansible) both exist so a mutating action can be previewed before it's real. This module's version of that same principle is simpler: GET first, always, to see current state, before ever constructing a POST/PUT/PATCH/DELETE — and never send one against a real controller without knowing exactly what it will do.

Quick checkMyth check
Does completing this module require sending a real POST/PUT/PATCH/DELETE request against a real network controller?

Key takeaways

  • Authorization: Bearer <token> is the common convention for API authentication — a real credential, sourced the same way every credential has been since Netmiko Fundamentals: never hardcoded.
  • GET stays the safe default; POST/PUT/PATCH/DELETE require the same explicit-review discipline as send_config_set()/ios_config.
  • requests.post(url, json=data, headers=...) sends a JSON body with authentication — verified directly, including what a missing header (401) and a malformed body (400) each look like.
  • This module's mutation examples run only against the safe local mock — the same dry_run=True/--check principle from earlier modules, applied to HTTP.