Authentication and Cryptography
A visual guide to cryptographic signatures, OpenID Connect, JWT verification, and application sessions.
Trust Is Hard on the Internet
Alice and Bob are never actually in the same room. Every message between them crosses a public network — wires, routers, and servers that neither of them controls.
Anyone on that network can read a message, copy it, or quietly change it before it arrives. So when Bob receives "Hi Bob, it's Alice," he's left holding two unanswered questions.
Who actually sent this? And did it arrive exactly as sent? This talk is about how cryptography lets Bob answer both, without ever trusting the network in between.
Three Cryptographic Jobs
Cryptography gives software three distinct capabilities. Authentication relies primarily on signatures.
- Hashing creates a tamper-evident fingerprint.
- Encryption keeps data secret.
- Signatures prove an issuer approved unchanged data.
Hashing Detects Changes
A cryptographic hash converts arbitrary data into a fixed-size fingerprint. Each character added to this JSON produces a dramatically different result.
Hashes do not hide their input. For passwords, use a dedicated slow password-hashing algorithm such as Argon2id, bcrypt, or scrypt.
Shared Secrets Authenticate a Payload
Alice and Bob already share a secret. Alice builds the payload and signs it by running it through a keyed hash together with the secret — an HMAC — then sends Bob the payload plus that signature.
Bob runs the payload he received through the same HMAC using the same secret. If his result matches the signature Alice sent, he knows it came from someone who knew the secret and wasn't changed along the way.
This is a message authentication code, not a public-key signature: both parties hold the same secret.
A Man in the Middle Is Detected
An intermediary sitting on the public network can read and rewrite Alice's payload. But it doesn't know the shared secret, so it can't produce a new signature to match its edit — it can only forward the old one.
Bob recomputes the HMAC on the payload he actually received. Since that payload was changed, his result no longer matches the signature Alice sent, and he rejects it.
Public and Private Keys
Asymmetric cryptography uses a matched pair of keys, but the two halves are treated very differently. Alice's private key stays behind her wall and never travels anywhere.
Alice's public key lives out in the open, on the other side of that same wall. Alice doesn't send it to anyone; Bob (or anyone else) simply fetches a copy whenever he needs it. That's fine, because a public key can't do anything a private key can undo.
Encryption: Public Locks, Private Unlocks
Bob first fetches Alice's public key from the public space, same as before. Then he uses it to lock up a message meant only for her.
Once locked, only Alice's private key, still safe behind her wall, can open it back up. Unlike HMAC, the two sides never share a secret — Bob only ever holds the public half.
Signing: Private Signs, Public Verifies
Bob fetches Alice's public key the same way as before. Alice signs her message with her private key, and Bob verifies it with the public key he fetched — no shared secret involved.
Compare that to the HMAC slide: there, verifying required holding the same secret Alice used, so anyone who could check a signature could also forge one. Here, signing and verifying use different keys, so anyone with Alice's public key can verify her signature — and doing so gives them no power to produce a valid one themselves.
A forger sitting out in the public space never touches Alice's wall. Whatever they sign, Bob's verification fails: that's the source of trust.
Signatures Bind Data to an Issuer
This is the exact mechanism you just watched Alice and Bob use, generalized: the signer is now called an issuer (an identity provider, for example), and the verifier is your application. Private key signs, public key verifies — nothing else changes.
The signed data is just a claims payload: who it's about (sub), who issued it (iss). Change a single byte after it's signed, and verification fails.
JWT: A Signed Envelope
A JSON Web Token has three Base64url-encoded parts — header, payload, signature — joined with dots into one string.
Base64url is an encoding, not encryption: fully reversible, no key required. Decode the header or payload yourself with nothing but a text editor. The signature is what can't be faked, because producing it required the issuer's private key.
Claims Need Context
A valid signature only proves who signed the token. Your application still has to confirm the token was made for this app, for this login, and is still valid right now — the signature alone checks none of that.
For identity, store the provider's stable iss and sub pair, not an email address alone.
issexpected issueraudthis applicationexpnot expirednbfvalid nownoncematches login requestsubstable provider user IDFinding the Right Public Key
OpenID Connect providers publish discovery metadata at a standard well-known URL. That metadata points to a JSON Web Key Set (JWKS) — a small list of the provider's current public keys.
The token header's kid selects which key in that set to verify against. Providers rotate keys by adding a new one before retiring the old kid — no coordinated application release required.
jwks_uri — a set of public keys.kid: key-2026 — match it to one JWK.The OpenID Connect Flow
The browser redirects the person to the identity provider. After login, the provider returns a short-lived authorization code to the application.
The application backend exchanges that code, verifies the resulting ID token using the preceding process, and only then treats the identity as trusted.
Issue Your Own Session
After verification, the application maps (iss, sub) to its own user record and creates a local session. A short-lived opaque session cookie gives the application straightforward logout, revocation, and fresh authorization checks.
JWTs are useful assertions. They are not automatically the best browser session format.
Appendix: RSA Math
RSA is one possible asymmetric scheme. It uses three numbers: a public exponent e, a shared modulus n, and a private exponent d. The same modular exponentiation operation runs in either direction, just with different exponents.
Real systems also apply carefully specified padding and hash constructions. Use maintained cryptography and OpenID Connect libraries rather than implementing this yourself.