Send sensor telemetry

Send sensor telemetry

Keep the IdP and the backend running, and in a fourth terminal:

$ cd bikeshare-security/sensor
$ python3 send_telemetry.py

Every 5 seconds, you should see a line like:

Sent {'batteryLevel': 58, 'latitude': 45.44, 'longitude': 4.38, 'motorRpm': 108}, backend responded 204

There is no library to install: send_telemetry.py uses only Python’s standard library, so there is nothing to configure beyond the constants at the top of the file.

Reading the script

  • fetch_access_token() sends client_id/client_secret as HTTP Basic credentials and grant_type=client_credentials, exactly the curl -u bike-sensor:sensor-secret command from Run the IdP.

  • It is called again on every iteration of the loop: a client-credentials token is cheap to obtain and, here, deliberately short-lived (60 seconds, see idp/src/main/resources/application.yaml), so there is no refresh token to cache or renew, unlike the frontend's session.

  • send_telemetry() posts the random reading as JSON, with the fresh token as a Bearer header, to the same /api/bikes/{id}/telemetry endpoint you called by hand in Secure the backend.

Watch it alongside the frontend

With the sensor script still running, open the frontend, log in, and click Refresh bike list a few times. `bike-1’s battery level keeps changing underneath you: two completely different clients, authenticated two completely different ways, are both legitimately calling the same backend, each restricted to its own scope.

Predict, then try

  1. Change CLIENT_SECRET to a wrong value and rerun. fetch_access_token() raises HTTPError: HTTP Error 401, caught by main()’s `try/except, printed, and the loop continues: a wrong credential never gets anywhere near the backend. Restore the correct secret afterward.

  2. In fetch_access_token(), remove "scope": "telemetry:write" from the request body entirely, and rerun. Following what you observed earlier, a token is still issued, but with no scope claim at all, so send_telemetry() now gets 403 Forbidden instead of 204. Restore the scope afterward.

This closes the loop promised at the very start of this chapter: the same two grant types, the same scope-based checks, now driving a real human-facing frontend and a real machine-to-machine sender against one shared backend.