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 204There 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()sendsclient_id/client_secretas HTTP Basic credentials andgrant_type=client_credentials, exactly thecurl -u bike-sensor:sensor-secretcommand 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 aBearerheader, to the same/api/bikes/{id}/telemetryendpoint 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
-
Change
CLIENT_SECRETto a wrong value and rerun.fetch_access_token()raisesHTTPError: HTTP Error 401, caught bymain()’s `try/except, printed, and the loop continues: a wrong credential never gets anywhere near the backend. Restore the correct secret afterward. -
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 noscopeclaim at all, sosend_telemetry()now gets403 Forbiddeninstead of204. 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.