Three modules on Spring Boot 4.1.1 with Spring Authorization Server 7.1.1: the provider
itself, a relying party, and an API that trusts its tokens. Client registration, PKCE,
a custom consent page and token customisation, with profiles that make each failure
reproducible.
Every claim is backed by captured output in docs/output/as-*.txt, regenerated by
authorization-server/scripts/run-all.sh. Notable findings, verified against the jars:
- OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(HttpSecurity) was deleted
in 7.0, and both configuration classes moved into spring-security-config
- ClientSettings.requireProofKey flipped from false to true, on the authorization server
(1.5.8 -> 7.1.1) and on the OAuth2 client (6.5.1 -> 7.1.1)
- requireProofKey(false) does not make PKCE optional for a public client; the code
verifier is that client's only authentication at the token endpoint
- MediaTypeRequestMatcher(TEXT_HTML) matches Accept: */*, so the token endpoint answers
API callers with 302 -> /login unless setIgnoredMediaTypes(ALL) is called
Also renames the repository to spring-auth-demo and cross-links the new chapter set from
the existing documentation.
2.7 KiB
Should you run one at all
Mostly: no.
What the demo does not have
This project is roughly 700 lines and it is a demo. What it is missing is the actual work:
| missing | what production needs |
|---|---|
| Key management | keys generated per boot; restart invalidates every token. Real deployments need persistent keys, a rotating JWK Set serving current and previous public keys, and an HSM or KMS for the private half |
| Storage | InMemoryOAuth2AuthorizationService / …ConsentService / …RegisteredClientRepository. Two replicas cannot complete each other's code exchanges. The JDBC implementations exist and bring schema migrations with them |
| User management | two hard-coded users. No registration, password reset, lockout, MFA, or audit |
| Operations | no rate limiting on /oauth2/token, no metrics on grant failures, no alerting on a spike in invalid_client |
| Compliance | consent records are the artefact an auditor asks for. In-memory ones do not exist |
| Upgrades | you now own an OAuth2 implementation. The requireProofKey default change in 03 is the kind of thing that will break your clients on a patch upgrade |
When it is the right call
- You need control an off-the-shelf product will not give you — a bespoke consent flow, a token shape a vendor cannot express, an unusual grant.
- The identity source is already yours and adding a second user store is worse than running the protocol.
- Air-gapped or heavily regulated deployment where a hosted IdP is not permitted and a commercial on-prem product is not affordable.
- You want to understand the protocol. This is a real reason. Running one for a week teaches you more about OAuth2 than any amount of integrating with one.
When to use something else
If you want an authorization server because you need “login”, use Keycloak, or your cloud provider's identity service, or a hosted IdP. All of them do key rotation, storage, user management, MFA and audit already, and the reason they look heavy is that those things are heavy.
docs/17-keycloak-setup.md in this repository sets up Keycloak
against the same resource server, so you can compare the two directly.
The middle path
Run Spring Authorization Server as an internal provider for machine-to-machine traffic
— client_credentials only, no users, no consent, no browser flows — and use a
real IdP for humans. That configuration is a fraction of this one, has no session handling,
and removes most of the table above. It is the only version of “write your own”
that I would defend without qualification.