Skip to content
Chapter 74Lesson 4

Quiz - Rate limiting with Upstash Redis

Quiz progress

0 / 0

Your app is about to launch publicly on a custom domain with the Better Auth email-and-password sign-in form. You already have a Vercel WAF rule capping requests per IP on /api/auth/*. Is that enough?

No. The WAF sees IP, path, and headers but never the email in the request body, so it can’t stop a botnet spread across thousands of IPs from hammering one victim’s email — that per-email check has to run inside the application.
Yes. A per-IP cap at the edge covers credential stuffing — every attacker request still comes from some IP, so the WAF eventually throttles them all.
Yes, as long as the per-IP budget is set aggressively low so even a handful of extra requests gets blocked.

Upstash is down for maintenance and limiter.limit(key) is throwing on every sign-in attempt. What’s the senior default for the auth path, and why?

Fail open — allow the request through and log a loud rate_limit_unavailable error — because fail-closed would turn a limiter outage into a total sign-in outage for every user.
Fail closed — reject the request as if it were over budget — because an unverifiable gate should always deny, the same as a broken authorization check.
Swallow the error quietly and allow the request, so monitoring isn’t flooded with noise during the incident.

A teammate declares new Ratelimit(...) inside the route handler’s POST function instead of at module scope. The counts in Redis still look correct in testing. What’s actually wrong?

A fresh limiter with a cold, empty in-memory cache is built on every request, so every call pays a Redis round-trip — slower and pricier under load, while passing fine in dev where the process stays hot.
The counts will be wrong in production because each request resets the counter to zero.
Nothing — declaring the limiter inside the handler is the correct place for it, since it needs the request to exist first.

You’re rate-limiting an endpoint that calls an LLM: you want to tolerate a short burst of requests but cap sustained spend over time. Which algorithm fits, and why isn’t sliding window the obvious pick here?

Token bucket — the bucket lets a full burst through, then throttles to the steady refill rate, which matches “burst is fine, cap the ongoing rate.”
Sliding window — it’s always the right default, including for bursty workloads.
Fixed window — its boundary spike is exactly the burst behavior you want.

The sign-in action runs two safeLimit calls on the same signInLimiter — one keyed ip:${ip}, one keyed email:${email}. Which statements about this design are correct? Select all that apply.

Both success values must be checked with their own early return; checking only the IP gate leaves the credential-stuffing vector wide open.
The ip: and email: prefixes on the key keep the two budgets in separate Redis counters even though they share one limiter and one prefix.
The per-email budget should be set tighter than the per-IP budget, since the email is what you’re really protecting.

Sign-up is gated per-IP only, while sign-in and password reset are also gated per-email. Why does sign-up skip the per-email gate?

On sign-up the email is the attacker’s own choice — they can cycle a fresh address every request, so a per-email budget never fills and the gate does nothing. The originating IP is the abusable identity there.
Sign-up traffic is too low to bother adding a second gate.
A per-email gate on sign-up would confirm whether an email already exists, leaking account enumeration.

Quiz complete

Score by topic