Antonio Braccolino, Identity & Access, home

Lab · 07 / 16

When there is no user.

A nightly job needs data from another service. Nobody types a password: the service proves its own identity and gets a narrowly scoped token.

You completed every lab

All 16 labs, from the map of IAM to the reference architectures. Identity has no secrets left for you.

See your achievements

Share your badge

Instagram: download the image and post it as a post or story. LinkedIn: the text is copied when you open it, paste it and attach the image.

OAuth 2.0 · M2M · Basics · 5 steps

What you will learn

  • How a service authenticates without a user
  • Client secret versus signed assertion
  • How an API validates a token offline
How the service proves itself

The service sends a shared secret: whoever copies it can pose as the service.The service signs a short assertion with its private key: the key never leaves the service.

Service
a backend job, no user involved
IdP
issues tokens to clients
API
the protected resource
  1. POST /token

    Step 1 of 5

    Token request with a secretToken request with a signed assertion

    In plain words The service shows a password of its own, like a staff code at the door.The service signs a short note with its private key: nothing reusable travels on the wire.

    The service authenticates with client_id and client_secret over TLS. Simple, but the secret must be stored, rotated and never logged.The service signs a short-lived JWT with its private key. The IdP verifies it with the registered public key. No shared secret to leak.

    POST https://idp.example.com/token
    Content-Type: application/x-www-form-urlencoded
    
    grant_type=client_credentials
    &scope=invoices:read
    &client_id=billing-job
    &client_secret=••••••••••••&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
    &client_assertion=eyJhbGciOiJQUzI1NiJ9.eyJpc3MiOiJiaWxsaW5nLWpvYiIsImF1ZCI6Imh0dHBzOi8vaWRwLmV4YW1wbGUuY29tL3Rva2VuIn0.…
  2. access_token

    Step 2 of 5

    A token for the service

    In plain words The service gets a temporary pass that opens one door only.

    Only an access token comes back: no ID token, because there is no user, and usually no refresh token, because the service can just ask again.

    eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCIsImtpZCI6IjIwMjYtMTAifQ.eyJpc3MiOiJodHRwczovL2lkcC5leGFtcGxlLmNvbSIsInN1YiI6ImJpbGxpbmctam9iIiwiY2xpZW50X2lkIjoiYmlsbGluZy1qb2IiLCJhdWQiOiJodHRwczovL2FwaS5leGFtcGxlLmNvbSIsInNjb3BlIjoiaW52b2ljZXM6cmVhZCIsImV4cCI6MTc2MDAwMDkwMCwiaWF0IjoxNzYwMDAwMDAwfQ.c2lnbmF0dXJlLW9mLWV4YW1wbGU

    Access token claims

    • iss"https://idp.example.com"

      The IdP that issued it.

    • sub"billing-job"

      For client credentials, the subject is the service itself, not a person.

    • client_id"billing-job"

      Which registered client asked for the token.

    • aud"https://api.example.com"

      The API this token is valid for. Other APIs must reject it.

    • scope"invoices:read"

      Only what the job needs: read invoices, nothing else.

    • exp1760000900

      Short lifetime: 15 minutes. The job simply asks again.

    • iat1760000000

      When it was issued.

  3. GET /invoices · Bearer

    Step 3 of 5

    Calling the API

    In plain words The service shows the pass at the door of the API.

    The token travels in the Authorization header. It is a bearer token: whoever holds it can use it, so it must never end up in logs or URLs.

    GET https://api.example.com/invoices?since=2026-10-01
    Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5cCI6ImF0K2p3dCJ9.…
  4. GET /jwks (cache)

    Step 4 of 5

    The API fetches the public keys

    In plain words The door keeps a copy of the official stamp to compare passes against.

    To check the signature, the API downloads the IdP’s public keys once and caches them, picking the key by kid. After that, validation happens locally without calling the IdP on every request.

    { "keys": [ { "kty": "RSA", "kid": "2026-10", "use": "sig", "alg": "RS256", "n": "0vx7agoebGcQSuu…", "e": "AQAB" } ] }
  5. 200 OK

    Step 5 of 5

    Access granted, within scope

    In plain words The pass is genuine and valid for this door, so it opens.

    Signature, iss, aud, exp and scope all check out. A request to write invoices with the same token would get 403: the scope only allows reading.

Example domains and values. Nothing leaves your browser.