Shared secret or key pair
Two families of algorithm dominate, and choosing between them looks like a cryptography detail while actually being an architecture decision.
One uses a single shared secret that both signs and verifies. The other is asymmetric: a private key signs, and anyone holding the matching public key can verify but never forge.
See what the shared secret costs you. Every service that verifies tokens holds it, and anything that can verify can also mint. One leaked environment variable anywhere in your fleet lets an attacker issue themselves admin tokens.
With the asymmetric family, your private key lives only in the auth service and everything else holds a key that is public by definition.
Distribute those public keys the solved way. Your auth server publishes its current keys at a well-known address, each tagged with an identifier that tokens reference in their header.
Verifiers fetch and cache the set, and rotation becomes routine. Publish the new key, start signing with it, and retire the old one once the last tokens signed with it have expired. Large identity providers rotate on the order of days and no client notices.
The checks people skip
Do the verification locally, because that is the entire point. Check the signature, then check the claims.
Watch the second half, because that is where implementations get lazy. Enforce the expiry, with a minute or two of tolerance for clocks that disagree. Check that the audience is your service, or a token legitimately minted for some other API replays cleanly against yours. Check the issuer is one you actually trust.
Hold onto why this became the default for APIs. No session store in the request path, any stateless replica can authenticate any request, and your auth service going down stops new logins without touching traffic already in flight.
Worked example
Lena joins a logistics company running 14 microservices that all verify HS256 tokens with one shared secret. During onboarding she finds that secret in three places: a Kubernetes secret, a CI variable, and, unpleasantly, a docker-compose.yml in a repo that had been public on GitHub for six months. Anyone who cloned it could mint a token with role admin and every service would accept it. Rotating an HMAC secret across 14 services without downtime turns out to be a coordinated dance nobody wants to repeat, so the team migrates to RS256: the auth service keeps its private key in KMS, and services fetch public keys from a JWKS endpoint with a 10-minute cache. The emergency rotation took 45 tense minutes; the next one, a year later under RS256, was a non-event nobody outside the auth team noticed.