I'm working on a Django project that runs via several Docker containers and the Django site itself is a middleware that an Nginx container forwards requests to. And for testing the port 80 of the Nginx container is mapped to 8080. Thus I go to http://localhost:8080/ and see the Django website.
I'm having the issue that a redirect URL (constructed by social-auth-app-django
package for Google Login) uses http://localhost
as a base rather than http://localhost:8080
.
The setting LOGIN_REDIRECT_URL
isn't what I'm looking for because it occurs after authentication is successful.
I tried SOCIAL_AUTH_LOGIN_REDIRECT_URL
which was mentioned somewhere but that was for an old version and no longer appears to do anything.
Since Django uses build_absolute_uri for all absolute URLs, there must be a way to override the base URL and/or host?
TL;DR = Nginx has no concept of Docker-mapped ports and needs to have them hard-coded.
Similar Issue: https://serverfault.com/questions/577370/how-can-i-use-environment-variables-in-nginx-conf
Django requires that the HTTP request headers contain the information it needs for the host (code snippet below). In this case it needs to be passed in from Nginx:
location / {
proxy_pass http://web:7000;
proxy_set_header Host $host:8080;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
Note the unfortunate hard-coding of the port: $host:8080
. The "outer" problem is that the port of the Nginx container is mapped using Docker to 8080 (-p 80:8080
) and thus it has no idea that it's actually running on port 8080; Nginx detects itself as running on port 80.
There is a Django setting for SOCIAL_AUTH_LOGIN_REDIRECT_URL
but specifying it like so:
SOCIAL_AUTH_LOGIN_REDIRECT_URL = 'http://localhost:8080/complete/google-oauth2/'
Causes this to happen when trying to authenticate through Google:
AuthMissingParameter at /complete/google-oauth2/
Missing needed parameter state
Request Method: GET
Request URL: http://localhost:8080/complete/google-oauth2/
Django Version: 2.1.5
Exception Type: AuthMissingParameter
Exception Value:
Missing needed parameter state
Exception Location: /usr/local/lib/python3.6/site-packages/social_core/backends/oauth.py in validate_state, line 88
Python Executable: /usr/local/bin/python
Python Version: 3.6.10
Thus the only solution I have at this point is to bake the port into the Nginx configuration when building the Docker image.
def _get_raw_host(self):
"""
Return the HTTP host using the environment or request headers. Skip
allowed hosts protection, so may return an insecure host.
"""
# We try three options, in order of decreasing preference.
if settings.USE_X_FORWARDED_HOST and (
'HTTP_X_FORWARDED_HOST' in self.META):
host = self.META['HTTP_X_FORWARDED_HOST']
elif 'HTTP_HOST' in self.META:
host = self.META['HTTP_HOST']
else:
# Reconstruct the host using the algorithm from PEP 333.
host = self.META['SERVER_NAME']
server_port = self.get_port()
if server_port != ('443' if self.is_secure() else '80'):
host = '%s:%s' % (host, server_port)
return host