0Pricing
Go Academy · Lesson

Auth and Rate Limiting Middleware

JWT validation and token bucket rate limiting

Auth and Rate Limiting Middleware is a free Go Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Go Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

JWT auth middleware

Extract, parse, and validate a JWT from the Authorization header:

func JWTAuth(secret []byte) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            header := r.Header.Get("Authorization")
            if !strings.HasPrefix(header, "Bearer ") {
                http.Error(w, "missing token", 401); return
            }
            token := strings.TrimPrefix(header, "Bearer ")
            claims, err := parseJWT(token, secret)
            if err != nil {
                http.Error(w, "invalid token", 401); return
            }
            ctx := context.WithValue(r.Context(), claimsKey{}, claims)
            next.ServeHTTP(w, r.WithContext(ctx))
        })
    }
}

API key auth

Validate an API key from a header against a database or in-memory set:

func APIKeyAuth(validKeys map[string]bool) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            key := r.Header.Get("X-API-Key")
            if !validKeys[key] {
                http.Error(w, "forbidden", 403); return
            }
            next.ServeHTTP(w, r)
        })
    }
}

Token bucket rate limiter

Use golang.org/x/time/rate with a per-IP limiter map:

var limiters sync.Map

func getLimiter(ip string) *rate.Limiter {
    v, _ := limiters.LoadOrStore(ip, rate.NewLimiter(rate.Every(time.Second), 10))
    return v.(*rate.Limiter)
}

Rate limiting middleware

Check the limiter in middleware and return 429 if the limit is exceeded:

func RateLimit(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        ip, _, _ := net.SplitHostPort(r.RemoteAddr)
        if !getLimiter(ip).Allow() {
            http.Error(w, "rate limit exceeded", 429); return
        }
        next.ServeHTTP(w, r)
    })
}

Retry-After header

Include a Retry-After header with the seconds the client should wait before retrying:

w.Header().Set("Retry-After", "1")
http.Error(w, "rate limit exceeded", 429)

Role-based access control

After auth, check the user's roles from the context claims before calling Next:

func RequireRole(role string) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            claims := claimsFromContext(r.Context())
            if !claims.HasRole(role) {
                http.Error(w, "forbidden", 403); return
            }
            next.ServeHTTP(w, r)
        })
    }
}

Limiter cleanup

Old per-IP limiters accumulate in memory. Clean them up with a background goroutine that deletes entries not accessed in the last N minutes.

Distributed rate limiting

In-process limiters do not work across multiple instances. Use Redis + a sliding window or token bucket script for distributed rate limiting.

429 vs 503

Return 429 Too Many Requests when the individual client is rate-limited. Return 503 Service Unavailable when the entire service is overloaded and shedding load.

Combining auth and rate limit

Apply them as separate middleware in the chain. Auth first: rate-limit only authenticated users to differentiate by user ID rather than IP.

Testing auth middleware

Use httptest to pass valid and invalid tokens and assert the correct status codes and context values are set.

Quick Check

Which HTTP status code should a rate-limiting middleware return when a client exceeds its limit?

Recap: Auth and Rate Limiting

Key points:

  • JWT middleware: extract Bearer token → parse → attach claims to context
  • Rate limit with golang.org/x/time/rate per IP or user
  • Return 429 + Retry-After header when limit exceeded
  • Distributed: use Redis for multi-instance rate limiting

Frequently asked questions

Is the “Auth and Rate Limiting Middleware” lesson free?

Yes — the full text of “Auth and Rate Limiting Middleware” is free to read here on the web, and the Go Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Go Academy course, upgrade to CoddyKit PRO.

What will I learn in “Auth and Rate Limiting Middleware”?

JWT validation and token bucket rate limiting You practise Go Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Go Academy?

No prior experience is required. Go Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Auth and Rate Limiting Middleware” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Go Academy lesson?

Yes. Every Go Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. HTTP Middleware Chain Fundamentals
  2. Logging and Request ID Middleware
  3. Auth and Rate Limiting Middleware
  4. CORS and Panic Recovery Middleware
← Back to Go Academy