401 vs 403, JWT, OAuth, PKCE: Security and Sign-In Words Explained (Spring + Entra ID)

October 1, 2026 · How It Actually Works: Real Systems as State Machines (part 10)

▶ Watch on YouTube & subscribe to The Stack Underflow

An online bookstore. A customer signs in with Microsoft, the Spring Boot app remembers them and calls an orders API for them, and every night a job with no user calls that API too. The two deep-dives after this video trace all of that as state machines, and they use a lot of words that sound alike: filter chain, 401, CSRF, JWT, OAuth, PKCE. This page explains them first.

The one-line version: authentication asks who are you?, authorization asks may you do this?, and every token, cookie and status code below exists to carry or check one of those two answers.

Last verified against the Spring Security 7.1.1 reference, the Microsoft identity platform docs and the OAuth, JWT, PKCE, HTTP and OpenID Connect specifications: 1 October 2026. Targets, as in the video: Spring Security 7.1.1 on Spring Boot 4.1.1, and Microsoft Entra ID (v2.0 endpoints).

One picture: the building’s security desk

Every word gets a peg from one analogy: an office building’s security desk. You pass the security checkpoints, show your ID at the desk, and get a visitor badge that decides which doors open. Sometimes head office’s security team checks you instead and hands out key cards. The pegs are memory aids, not facts; the tables say where each one stops matching.

Who are you, and what may you do?

WordMemory pegWhat it actually is
Authenticationchecking your ID at the desk”how we verify the identity of who is trying to access a particular resource” (Spring Security). In the bookstore the ID is checked at head office (Entra), not by the app.
Authorizationwhich doors your badge opens”determining who is allowed to access a particular resource”. Checked on every request, not once at a front door.
Principalthe name on the badgeThe part of Spring’s Authentication object that identifies the user.
Credentialsthe ID you showThe proof, often a password; in many cases cleared after authentication. With Entra sign-in the password is typed on Microsoft’s page and never reaches the app.
Password hashkeep a fingerprint, not a copyApps that keep their own passwords store a one-way hash. Spring’s default DelegatingPasswordEncoder encodes with BCrypt (prefix {bcrypt}), which the docs call “deliberately slow”. Stolen hashes still allow offline guessing; slowness makes each guess costly.

Remembering you between requests

WordMemory pegWhat it actually is
Cookiethe numbered slip you carrySmall data a server sends; the browser sends it back on later requests. A stolen slip works for anyone, so send it only over HTTPS.
Sessionthe visitor list at the deskData the server keeps for one visitor; the browser holds only its ID, in a cookie usually named JSESSIONID.
SecurityContextthe visitor badge you wearHolds the current Authentication for this request, in a ThreadLocal by default, cleared by FilterChainProxy when the request ends. After sign-in, the bookstore app saves it in the session and loads it again on the next request.
Stateful vs statelessthe visitor list vs a signed badge you carryA session can be ended at the server at once. A token the API checks by itself is normally accepted until it expires, so keep it short-lived; but any number of servers can check it without shared memory.

The checkpoints

WordMemory pegWhat it actually is
Filter chainthe security checkpointsServlet filters that run before your controller in a fixed order (CORS, CSRF, login, authorization and more). An app can have several SecurityFilterChains; only the first that matches runs. A checkpoint can also act, like sending you off to sign in.
Authority (role, scope)the clearances on your badgeGranted permissions. hasRole('ADMIN') is “a shortcut for hasAuthority that prefixes ROLE_”, so it checks ROLE_ADMIN. A JWT scope like Orders.Read becomes SCOPE_Orders.Read. So hasRole never matches a scope; use hasAuthority.
401who are you? Go to the deskRFC 9110: “the request lacks valid authentication credentials for the target resource.” A browser on a chain with a login page gets a redirect to sign in instead.
403your badge doesn’t open this doorRFC 9110: “the server understood the request but refuses to fulfill it.”
CSRF tokenthe desk’s stamp on the formAnother site makes your browser post a form to the bookstore; if your session cookie comes along, it looks like you. Chrome usually holds that cookie back on cross-site posts; not every browser does. The fix is a random token your pages include and the other site can’t read. Spring checks it on unsafe methods like POST; missing or wrong gets 403. Bearer-token API calls skip it.
CORSa note for the courierThe browser’s same-origin policy stops a script from one origin reading another’s responses. CORS lets a server tell the browser which other origins’ scripts may read its responses, sometimes after a preflight. curl ignores the note: CORS doesn’t protect your API, and it isn’t CSRF protection.

Who decides 401 or 403? Spring’s ExceptionTranslationFilter. If access is denied while you are anonymous, it starts authentication through the AuthenticationEntryPoint (a 401, or a redirect to the login page). If you are signed in, it calls the AccessDeniedHandler: 403.

Head office and its tokens

WordMemory pegWhat it actually is
JWTa signed badge you carryRFC 7519: “a compact, URL-safe means of representing claims”. Claims include issuer (iss), subject (sub), audience (aud) and expiry (exp). A signed JWT has three parts joined by dots: header, claims, signature. The signature proves origin and integrity, but the parts are only encoded, so the holder can read them. Keep secrets out.
Signing keys, JWKSthe published seal samplesThe issuer signs with a private key and publishes public keys as a JSON Web Key Set. The API picks one by the kid in the token header. Entra “rotates the possible set of keys on a periodic basis”, so fetch keys, never hard-code them.
OAuth 2.0the key-card systemRFC 6749: lets an app “obtain limited access to an HTTP service”. Roles: client (the bookstore app, the front desk), resource server (the orders API, the card reader), authorization server (Entra ID), resource owner (the customer). OAuth hands out key cards; it doesn’t tell the app who you are.
OpenID Connectkey cards plus introductions”a simple identity layer on top of the OAuth 2.0 protocol”. It adds sign-in and the ID token.
Identity providerhead office’s security teamThe service that signs users in and issues tokens, here Microsoft Entra ID, which Microsoft also calls the authorization server.
MFAtwo proofs at head officeTwo or more of: something you know, something you have, something you are. With Entra, prompts are part of Entra’s sign-in, Conditional Access policies (or security defaults) decide when, and “You don’t need to change apps and services”. The app sees only the signed result.

One sign-in, three tokens

WordMemory pegWhat it actually is
Authorization codethe claim ticketSent back through the browser after sign-in. Short-lived (Entra: “Typically, they expire after about 1 minute”) and single-use (RFC 6749: “MUST NOT use the authorization code more than once”). Redeemed at the token endpoint with the app’s own credential.
PKCE (pronounced “pixy”)a secret the desk keepsThe app sends a hash of a random verifier first (S256), then the verifier to redeem, so an intercepted code is useless to anyone else. In Spring Security 7.1.1, requireProofKey defaults to true for the authorization_code grant: on by default.
Redirect URIthe only address for the ticketEntra sends the code only to a registered URI; it “must exactly match one of the redirect URIs you registered”.
State and noncematching stubsState comes back with the code and must match what the app saved (stops forged responses, CSRF on the redirect). Nonce comes back inside the ID token (stops replays). They bind a reply to this sign-in; they don’t identify the customer.
ID tokena signed letter of introductionTells the app who signed in. For the app only: “You shouldn’t use an ID token to call an API.”
Access tokenthe key card for one buildingFor one API, its audience (aud). Clients “should treat them as opaque strings”; the API validates it. Entra’s default lifetime is a random value between 60 and 90 minutes.
Refresh tokenthe renewal slipGets new tokens without a new sign-in. “Only provided if offline_access scope was requested.”
Scope, consentdoors named on the card; your signature on the requestDelegated permissions the app asks for to act for the user. Entra asks the user to consent unless an admin consented for the organization. Granted scopes appear in the scp claim; Spring turns them into SCOPE_ authorities.
Client credentialsthe desk’s own key cardThe app gets a token as itself, “instead of impersonating a user”, asking for {resource}/.default. Permissions are app roles an admin grants. “Refresh tokens will never be granted with this flow.” Guard the credential; Microsoft recommends certificates over secrets.
On-behalf-ofswap cards for the next buildingAn API that must call another API as the same user exchanges its token at Entra (jwt-bearer grant, requested_token_use=on_behalf_of). It never forwards it.
SAML 2.0the XML letter of introduction”A mature, XML-based standard used widely in enterprises.” Entra posts a signed XML assertion to the app, not OAuth tokens. For new apps, “OIDC is usually simpler to build with modern frameworks.”

Pause & Prove

The pinned question

A signed-in customer opens a page their account isn’t allowed to see. 401 or 403? And what happens to an anonymous visitor who is denied on a chain with a login page?

  • Signed in and refused: 403. The server knows who they are and refuses: your badge doesn’t open this door.
  • Anonymous and denied: “we don’t know who you are.” ExceptionTranslationFilter starts authentication. On a chain with a login page, the browser is redirected to sign in; without one, the entry point answers 401.

The Community poll: in Spring Security, hasRole('ADMIN') checks which authority?

  • ADMIN. The tempting answer. That is what hasAuthority('ADMIN') would check.
  • ROLE_ADMIN. ✓ hasRole adds the ROLE_ prefix.
  • SCOPE_ADMIN. That is how a JWT scope named ADMIN would be mapped. hasRole never matches a scope; use hasAuthority('SCOPE_…') for scopes.
  • Any of them. No: the check is one exact authority string.

The peg drill

Authentication: checking your ID at the desk. SecurityContext: the visitor badge you wear. JWT: a signed badge you carry. Authorization code: the claim ticket. Access token: the key card for one building.

Before and after this video

Sources

All pages were read on 1 October 2026; Spring pages show “Spring Security 7.1.1”.

Change notes

  • 1 Oct 2026: first published.

Not affiliated with or endorsed by Microsoft or VMware Broadcom (Spring). Found a mistake? Tell us in the video’s comments and we’ll correct this page.

Found this useful? The deep version lives on YouTube — new breakdowns of how AI dev tools actually work, weekly.

Subscribe on YouTube →

Prefer email? Get the free newsletter: one failure, traced step by step, about once a week.