Authorization middleware needs to know who's making the request before it can decide what they're allowed to do — so authentication must run first, in every one of these frameworks, for exactly the same reason. This is the single most common middleware-ordering bug across all three ecosystems, and it's the same bug wearing three different syntaxes.
A second, equally common ordering bug: response-modifying middleware must be registered before the thing whose response it modifies, because of the down-then-up shape. Compression middleware, for instance, needs to run its "after" logic on the final response body — so it needs to be near the top of the list, wrapping everything below it (including the route handler), not near the bottom:
MIDDLEWARE = [
"django.middleware.gzip.GZipMiddleware", # wraps everything below — compresses the final response
"myapp.middleware.LoggingMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
]
If GZipMiddleware were listed after AuthenticationMiddleware instead, it would still work in this particular case (compression doesn't depend on auth having run), but the general principle holds across all three frameworks: "runs on the way out" middleware needs to be registered early enough to actually wrap the code whose output it's modifying.