Most Spring Boot authentication tutorials on YouTube will get you hacked. Hardcoded secrets. Passwords stored in plain text. Tokens that never expire. People copy that code, ship it to production, and then wonder why they end up in a breach report.
This series is the opposite of that. Over ten episodes, we build the authentication backend that real apps — apps like Instagram — actually run on: Spring Boot 4, Spring Security 7, JWT with refresh-token rotation, Redis, and PostgreSQL. Production-grade, from the first commit. Episode 1 is the blueprint: the full architecture and the six decisions behind the stack, before we write a single line of code.
What you’ll learn in Episode 1
This is a whiteboard episode — no coding yet, on purpose. Before you write auth code, you need to understand why each piece exists, otherwise you end up copy-pasting patterns you can’t defend in a code review. By the end you’ll understand:
- Why the most popular Spring Boot auth tutorials teach insecure patterns
- The nine endpoints we’re building and how they group into two flows
- The full request-to-token architecture at a glance
- The six stack decisions — and the reasoning behind each one
- The 10-episode roadmap, so you know exactly where this is going
- What to install before Episode 2, where the code starts
Chapters
(Timings match the video — scrub and nudge if your final edit shifted.)
- 0:00 — Why most auth tutorials get you hacked
- 1:13 — What we’re building: nine endpoints
- 2:34 — The full architecture
- 4:37 — Spring Security 7 + JWT rotation
- 5:54 — PostgreSQL, Flyway & Redis
- 6:59 — Bucket4j & Docker Compose
- 8:09 — Project layout
- 8:57 — The 10-episode roadmap
- 9:36 — Install these before Episode 2
- 11:12 — What’s next
Why most Spring Boot auth tutorials get you hacked
Search “Spring Boot JWT authentication” and you’ll find hundreds of tutorials. A worrying number of them share the same production-killing mistakes:
- Hardcoded signing secrets committed straight into the repo, so anyone who reads your GitHub can forge a valid token.
- Tokens that never expire — one leaked token is a permanent backdoor.
- No refresh strategy, so developers set absurdly long access-token lifetimes just to avoid re-logins.
- No way to revoke a token after logout or a compromise.
- Passwords hashed weakly — or, astonishingly often, stored in plain text.
- No rate limiting, leaving login and password-reset endpoints wide open to brute force.
None of that survives contact with a real production environment. This series treats security as the default, not an afterthought — which is exactly why we spend Episode 1 on the architecture instead of racing to a @RestController.
What we’re building: nine endpoints, two flows
The whole backend lives under /api/auth and splits cleanly into two groups.
1. Auth & token flow
Everything to do with getting in, staying in, and getting out safely: registration, login, silently refreshing an access token using a rotating refresh token, and logout that actually invalidates the token server-side.
2. Account & password flow
Everything to do with account recovery and verification: forgot-password, reset-password, and OTP-based verification, with sensitive steps guarded by rate limiting so they can’t be brute-forced.
insta-auth-service on GitHub.
The architecture at a glance
Here’s the path a single authenticated request takes, which is the mental model the rest of the series builds on:
- A request hits Spring Security’s filter chain before it ever reaches a controller.
- A rate-limit filter (Bucket4j) checks the sensitive endpoints — login and forgot-password — and rejects abuse early.
- A JWT filter validates the access token’s signature and expiry, then checks Redis to make sure the token hasn’t been blacklisted (e.g. after logout).
- If everything checks out, Spring Security populates the security context and the request proceeds to the controller.
- User records, credentials, and lockout state live in PostgreSQL; short-lived state — blacklisted tokens and OTPs — lives in Redis with a TTL so it expires on its own.
That separation — durable data in Postgres, ephemeral data in Redis — is one of the decisions we unpack next.
The six decisions behind the stack
A stack is only as good as the reasoning behind it. Here are the six choices that define this backend, all of them reflected in the actual codebase.
1. JWT with refresh-token rotation — not server sessions
Access tokens are short-lived (15 minutes). Refresh tokens last 7 days and rotate on every use — each refresh issues a brand-new refresh token and invalidates the old one. Crucially, we add reuse detection: if an already-used refresh token shows up again, we treat it as a stolen-token event and invalidate the whole chain. That’s the difference between “JWT tutorial” and “JWT you can defend in production.”
2. Redis for the token blacklist and OTP storage
Pure JWT can’t be revoked — that’s the classic trade-off. We solve it with a Redis blacklist: on logout, the token’s ID goes into Redis with a TTL matching its remaining lifetime, so it’s rejected instantly and then cleans itself up. OTPs for verification and password reset also live in Redis with a short TTL. Ephemeral data belongs in an ephemeral store.
3. PostgreSQL + Flyway for a versioned schema
User accounts, hashed credentials, and lockout state are durable data, so they belong in a relational database. We use Flyway so the schema is versioned and migrations are repeatable — no “works on my machine” database drift between you and production.
4. BCrypt (strength 12) for password hashing
Passwords are hashed with BCrypt at strength 12 — deliberately slow, salted per-password, and tuned so brute-forcing the hash is economically pointless. No plain text, no fast hashes, no shortcuts.
5. Bucket4j rate limiting on the endpoints that matter
Rate limiting isn’t global — blanket limits hurt real users. We guard the two endpoints attackers actually target: login and forgot-password. Bucket4j’s token-bucket algorithm makes this clean and predictable.
6. Account lockout with escalating cooldowns
Repeated failed logins trigger a temporary lockout that escalates from 5 minutes up to 30 minutes, tracked in Postgres. It stops brute-force attempts without permanently locking out a user who simply fat-fingered their password.
The 10-episode roadmap
Here’s where the series is headed, so you always know what’s coming next. New episodes drop every Monday and Thursday.
- Episode 1 — Architecture & decisions (this one)
- Episodes 2–10 — building it for real, class by class: project scaffolding, the entity and persistence layer, registration and login, JWT issuance and validation, refresh-token rotation with reuse detection, Redis blacklisting and OTP, password reset, Bucket4j rate limiting and account lockout, and finally Docker Compose to run the whole thing.
The build is incremental — each episode adds working, tested code on top of the last, so by the end you have a complete, runnable authentication service.
Install these before Episode 2
Episode 2 is where we start writing code, so get your environment ready now:
- Java 21 (JDK) — the series targets Java 21.
- Your IDE of choice — IntelliJ IDEA (Community is fine) or VS Code with the Java extensions.
- Docker Desktop — we’ll run PostgreSQL and Redis in containers later in the series.
- Git — and go ahead and clone the repo so you’re ready.
⭐ Star and clone insta-auth-service on GitHub — you’ll build alongside it from Episode 2.
Frequently asked questions
Do I need to be a Spring Boot expert to follow this series?
No, but it’s not a beginner “hello world” either. If you’ve built a couple of Spring Boot apps and you’re comfortable with @RestController, dependency injection, and the service layer, you’re in exactly the right place. Brand new to Spring Boot? Watch a basics playlist first, then come back.
Why JWT with refresh tokens instead of server-side sessions?
Sessions require sticky server state, which is harder to scale horizontally. JWTs are stateless and scale cleanly — but they can’t be revoked on their own, which is why we pair them with refresh-token rotation and a Redis blacklist. You get the scalability of JWT and the ability to revoke access.
Why Redis if we already have PostgreSQL?
They do different jobs. PostgreSQL stores durable data — user accounts, credentials, lockout state. Redis stores short-lived data — blacklisted tokens and OTPs — that should expire automatically via TTL. Using the right store for each keeps both fast and clean.
Is this a real Instagram clone?
It’s an educational project that builds the kind of authentication backend a large social app runs on — the patterns, not any proprietary code. The goal is to teach production-grade auth using a familiar reference point.
What version of Spring Boot and Spring Security does this use?
Spring Boot 4 and Spring Security 7 on Java 21 — the current generation, not the outdated Security 5/6 patterns most tutorials still teach.
Watch Episode 1 and build along
Episode 1 gives you the blueprint. Episode 2 starts the build. If you want to follow along properly:
- ▶️ Watch the full episode above and subscribe so you don’t miss the Monday/Thursday drops.
- ⭐ Star the GitHub repo — you’ll need it from Episode 2.
- 💬 Want a 1:1 code review, architecture help, or career guidance? Book a session on Topmate.
Drop a comment on the video telling me where you’re watching from — I reply to every comment in the first 48 hours. See you in Episode 2.
Comments
Post a Comment