gorilla/mux · warning

Forbidden

Error message

Forbidden

What it means

Not an error thrown by gorilla/mux. README.md:571 is the README copy of the same authentication-middleware example shown in doc.go (error 24): when X-Session-Token isn't found in tokenUsers, the example writes http.Error(w, "Forbidden", http.StatusForbidden). Documented separately because it is the more commonly copied source (README > godoc).

Source

Thrown at README.md:571

	amw.tokenUsers["00000000"] = "user0"
	amw.tokenUsers["aaaaaaaa"] = "userA"
	amw.tokenUsers["05f717e5"] = "randomUser"
	amw.tokenUsers["deadbeef"] = "user0"
}

// Middleware function, which will be called for each request
func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := r.Header.Get("X-Session-Token")

        if user, found := amw.tokenUsers[token]; found {
        	// We found the token in our map
        	log.Printf("Authenticated user %s\n", user)
        	// Pass down the request to the next middleware (or final handler)
        	next.ServeHTTP(w, r)
        } else {
        	// Write an error and stop the handler chain
        	http.Error(w, "Forbidden", http.StatusForbidden)
        }
    })
}
```

```go
r := mux.NewRouter()
r.HandleFunc("/", handler)

amw := authenticationMiddleware{tokenUsers: make(map[string]string)}
amw.Populate()

r.Use(amw.Middleware)
```

Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. Middlewares _should_ write to `ResponseWriter` if they _are_ going to terminate the request, and they _should not_ write to `ResponseWriter` if they _are not_ going to terminate it.

### Handling CORS Requests

View on GitHub (pinned to db9d1d0073)

Solutions

  1. Send X-Session-Token set to a token that Populate() registered.
  2. Verify Populate() runs before r.Use(amw.Middleware) and that tokenUsers is populated from your real user store, not the example's hardcoded literals.
  3. Swap the in-memory map for a real authn backend (signed cookie / JWT / database lookup) before exposing the service.
  4. Use 401 for missing credentials and reserve 403 for authenticated-but-unauthorized, so clients can react correctly.

Example fix

// before (README.md:571)
http.Error(w, "Forbidden", http.StatusForbidden)

// after
if token == "" {
    w.Header().Set("WWW-Authenticate", "Bearer realm=""mux""")
    http.Error(w, "unauthorized", http.StatusUnauthorized)
    return
}
user, ok := userStore.BySessionToken(token)
if !ok {
    http.Error(w, "forbidden", http.StatusForbidden)
    return
}
Defensive patterns

Strategy: validation

Validate before calling

// Validate session token at the boundary; reject empty/malformed before lookup.
func validSessionToken(t string) bool {
    t = strings.TrimSpace(t)
    if t == "" { return false }
    // shape check appropriate to your tokens, e.g. opaque >= 16 hex bytes
    if len(t) < 16 { return false }
    for _, c := range t {
        if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
            return false
        }
    }
    return true
}

// in the middleware
token := r.Header.Get("X-Session-Token")
if !validSessionToken(token) {
    w.Header().Set("WWW-Authenticate", "Bearer realm=\"mux\"")
    http.Error(w, "unauthorized", http.StatusUnauthorized)
    return
}
user, ok := store.BySessionToken(token)

Try / catch

// Treat the example's 403 as a fallback; classify failures explicitly.
func authmw(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        user, status := authenticate(r.Header.Get("X-Session-Token"))
        if status != 0 {
            // status is 401 for missing/invalid, 403 for known-but-unauthorized
            if status == 401 {
                w.Header().Set("WWW-Authenticate", "Bearer")
            }
            http.Error(w, http.StatusText(status), status)
            return
        }
        next.ServeHTTP(w, r.WithContext(withUser(r.Context(), user)))
    })
}

Prevention

When it happens

Trigger: A request reaches a handler guarded by the README's authenticationMiddleware without an X-Session-Token header, with an unknown token, or before Populate() has seeded tokenUsers; the middleware short-circuits the chain with 403 "Forbidden".

Common situations: Front-end not yet sending the auth header; token list out of sync with the client; Populate() skipped during wiring; header name mismatch (e.g. Authorization Bearer vs X-Session-Token); the example pasted as-is into production code paths.

Related errors


AI-assisted analysis of gorilla/mux@db9d1d0073 (2026-08-04). Data as JSON: /data/errors/a9e1611435cdbba1.json. Report an issue: GitHub.