django
elastic beanstalk
oauth
authorization
security

Authorization Credentials Stripped --- django, elastic beanstalk, oauth

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

If a Django app works locally but OAuth bearer tokens disappear after deployment to Elastic Beanstalk, the problem is usually not Django itself. In most cases the Authorization header is being dropped or not forwarded correctly by the proxy layer that sits in front of the application process.

Why the Header Disappears

OAuth access tokens are commonly sent in the Authorization request header, for example Bearer token-value. Django does not receive that header magically. It must first survive the entire request path:

  1. client
  2. load balancer
  3. reverse proxy such as Nginx or Apache
  4. WSGI server
  5. Django

If any layer fails to pass it through, authentication code inside Django sees an anonymous request.

In Django, forwarded headers usually appear in request.META. The authorization header is typically exposed as HTTP_AUTHORIZATION.

python
def debug_headers(request):
    auth = request.META.get("HTTP_AUTHORIZATION")
    return JsonResponse({"authorization": auth})

If that returns null in Elastic Beanstalk but works locally, the proxy configuration is the first place to investigate.

Elastic Beanstalk and Reverse Proxies

Elastic Beanstalk commonly runs your application behind Nginx. Nginx proxies the request to Gunicorn or another app server. Unless the configuration explicitly preserves the header, downstream code may never see it.

A common fix is to forward the header in Nginx:

nginx
1location / {
2    proxy_pass http://127.0.0.1:8000;
3    proxy_set_header Host $host;
4    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
5    proxy_set_header X-Forwarded-Proto $scheme;
6    proxy_set_header Authorization $http_authorization;
7}

On Elastic Beanstalk, custom Nginx snippets are usually placed under .platform/nginx/conf.d/. For example:

text
.platform/nginx/conf.d/authorization.conf

That file can contain the relevant proxy_set_header directive for the route being proxied.

Django-Side Verification

Before changing authentication code, verify whether the header reaches Django at all. A tiny authenticated endpoint or debug view is enough.

python
1from django.http import JsonResponse
2
3def who_am_i(request):
4    return JsonResponse(
5        {
6            "user": str(request.user),
7            "auth_header": request.META.get("HTTP_AUTHORIZATION"),
8        }
9    )

If request.user is anonymous and auth_header is empty, the application is not receiving the token. That narrows the issue down quickly.

If the header is present but auth still fails, then the next suspects are:

  • token format
  • OAuth middleware order
  • DRF authentication classes
  • clock skew or token expiry

Apache and WSGI Cases

Some Elastic Beanstalk stacks or older deployments may involve Apache or mod_wsgi rather than Nginx. In that case, a classic fix is:

apache
WSGIPassAuthorization On

Without that setting, Apache can consume the header before the WSGI app sees it. The symptom looks similar: local development succeeds, deployed OAuth fails.

So the exact fix depends on the stack:

  • Nginx: forward Authorization
  • Apache with mod_wsgi: enable WSGIPassAuthorization On

Django REST Framework Example

If you are using Django REST Framework with token-style authentication, keep the application setup simple and confirm the infrastructure first.

python
1REST_FRAMEWORK = {
2    "DEFAULT_AUTHENTICATION_CLASSES": [
3        "rest_framework.authentication.TokenAuthentication",
4    ],
5}

Or for bearer-style OAuth:

python
1REST_FRAMEWORK = {
2    "DEFAULT_AUTHENTICATION_CLASSES": [
3        "oauth2_provider.contrib.rest_framework.OAuth2Authentication",
4    ],
5}

These settings are correct only if the header actually arrives. Misdiagnosis happens when developers repeatedly change Django authentication classes even though the proxy has already stripped the credentials.

A Practical Debug Flow

Use a short, deterministic checklist:

  1. Send a request with a known Authorization header.
  2. Inspect the load balancer and Nginx logs if available.
  3. Confirm whether Django sees HTTP_AUTHORIZATION.
  4. If it does not, fix the proxy forwarding.
  5. If it does, inspect OAuth library settings and token validity.

A reproducible curl command helps:

bash
curl -H "Authorization: Bearer test-token" https://example.com/api/whoami/

That test is much easier to reason about than debugging from a browser or mobile client.

Common Pitfalls

One common mistake is assuming HTTPS termination at the load balancer automatically preserves all headers. It does not. The reverse proxy still needs to forward what the app depends on.

Another mistake is logging entire tokens while debugging. Log whether the header exists, but do not dump secrets into application logs. A safer pattern is to log only that the header was present and maybe its auth scheme.

It is also easy to chase the wrong layer. If Django never receives HTTP_AUTHORIZATION, changing middleware order or token parsing code will not solve the problem.

Summary

  • OAuth failures on Elastic Beanstalk often come from a missing forwarded Authorization header.
  • In Django, the header usually appears as request.META["HTTP_AUTHORIZATION"].
  • On Nginx, forward it explicitly with proxy_set_header Authorization $http_authorization;.
  • On Apache with mod_wsgi, WSGIPassAuthorization On is often required.
  • Verify header presence first, then debug Django or OAuth configuration second.

Course illustration
Course illustration

All Rights Reserved.