4

I have spent a good part of the last 3 days trying every solution that is on the internet and feeling desperate. Here's the problem statement:

I have a Dockerized app with three services:

  • A django application with gunicorn (web)
  • A Nginx server (nginx)
  • PostgreSQL (db)

My web application requires user to log in with their GitHub account through a fairly standard OAuth process. This has always worked without nginx. User clicks on the "log in with github" button, sent them to GitHub to authorize the application, and redirects it back to a completion page.

enter image description here

I have "Authorization callback URL" filled in as http://localhost:8000. Without Nginx I can navigate to the app on localhost, click on the button, and upon authorization, get redirected back to my app on localhost.

With Nginx, I would always fail with the error (nginx in console):

GET /auth/complete/github/?error=redirect_uri_mismatch&error_description=The+redirect_uri+MUST+match+the+registered+callback+URL+for+this+application.&error_uri=https%3A%2F%2Fdeveloper.github.com%2Fapps%2Fmanaging-oauth-apps%2Ftroubleshooting-authorization-request-errors%2F%23redirect-uri-mismatch&state=nmegLb41b959su31nRU4ugFOzAqE8Cbl HTTP/1.1

This is my Nginx configuration:

upstream webserver {
    # docker will automatically resolve this to the correct address
    # because we use the same name as the service: "web"
    server web:8000;
}

# now we declare our main server
server {

    listen 80;
    server_name localhost;

    location / {
        # everything is passed to Gunicorn
        proxy_pass http://webserver;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_redirect off;
    }

    location /static {
        autoindex off;
        alias /static_files/;
    }

    location /media {
        alias /opt/services/starport/media;
    }
}

This is my Dockerfile:

version: '3.7'
services:
  web:
    build: .
    command: sh -c "cd starport && gunicorn starport.wsgi:application --bind 0.0.0.0:8000"
    volumes:
      - static_files:/static_files # <-- bind the static volume
    networks:
      - nginx_network
  nginx:
    image: nginx
    ports:
      - 8000:80
    volumes:
      - ./config/nginx/conf.d:/etc/nginx/conf.d
      - static_files:/static_files # <-- bind the static volume
    depends_on:
      - web
    networks:
      - nginx_network

networks:
  nginx_network:
    driver: bridge

volumes:
  static_files:

My hunch was that the reason it worked without Nginx but doesn't with the Nginx http server has got to do with the redirection since Nginx is listening to a port and then forwarding it to a different port. GitHub's doc specifically said that the redirect URI needs to be exactly the same as the registered callback url. I've also used the inspector tools and these are my Request headers:

GET /accounts/login/ HTTP/1.1
Cookie: ...
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Upgrade-Insecure-Requests: 1
Host: localhost:8000
User-Agent: Mozilla/5.0
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: keep-alive

The error message I get with Nginx (again, stressing that it works like a charm without error without nginx 10 out of 10 times) is:

http://localhost:8000/auth/complete/github/?error=redirect_uri_mismatch&error_description=The+redirect_uri+MUST+match+the+registered+callback+URL+for+this+application.&error_uri=https%3A%2F%2Fdeveloper.github.com%2Fapps%2Fmanaging-oauth-apps%2Ftroubleshooting-authorization-request-errors%2F%23redirect-uri-mismatch

As an additional detail, I'm using the social-auth-app-django package but this should not matter.

Further troubleshooting

After countless hours of probing, I run this in local on debug mode and this time closely monitored my Request information. When use hits the link to authorize with GitHub via OAuth, this is the Request along with all the header information:

CSRF_COOKIE             'abc'
HTTP_ACCEPT             'text/html,application/xhtml+xml'
HTTP_ACCEPT_ENCODING    'gzip, deflate'
HTTP_ACCEPT_LANGUAGE    'en-us'
HTTP_CONNECTION         'close'
HTTP_COOKIE             ('csrftoken=...; ')
HTTP_HOST               'localhost'
HTTP_REFERER            'http://localhost:8000/accounts/login/?next=/'
HTTP_USER_AGENT         ('Mozilla/5.0')
HTTP_X_FORWARDED_FOR    '172.26.0.1'
HTTP_X_FORWARDED_PROTO  'http'
PATH_INFO               '/auth/complete/github/'
SERVER_NAME             '0.0.0.0'
SERVER_PORT             '8000'

QUERY_STRING    
'error=redirect_uri_mismatch&error_description=The+redirect_uri+MUST+match+the+registered+callback+URL+for+this+application.&error_uri=https%3A%2F%2Fdeveloper.github.com%2Fapps%2Fmanaging-oauth-apps%2Ftroubleshooting-authorization-request-errors%2F%23redirect-uri-mismatch&state=NwUhVqfOCNb51zpvoFbXVvm1Cr7k3Fda'

RAW_URI 
'/auth/complete/github/?error=redirect_uri_mismatch&error_description=The+redirect_uri+MUST+match+the+registered+callback+URL+for+this+application.&error_uri=https%3A%2F%2Fdeveloper.github.com%2Fapps%2Fmanaging-oauth-apps%2Ftroubleshooting-authorization-request-errors%2F%23redirect-uri-mismatch&state=NwUhVqfOCNb51zpvoFbXVvm1Cr7k3Fda'

What immediately stood out to me was the value of HTTP_HOST, HTTP_REFERRER and SERVER_NAME. What's also interesting to me was the error message says:

http://localhost/auth/complete/github/?error=redirect_uri_mismatch&error_description=The+redirect_uri+MUST+match+the+registered+callback+URL+for+this+application.&error_uri=https%3A%2F%2Fdeveloper.github.com%2Fapps%2Fmanaging-oauth-apps%2Ftroubleshooting-authorization-request-errors%2F%23redirect-uri-mismatch&state=NwUhVqfOCNb51zpvoFbXVvm1Cr7k3Fda

Where instead of http://localhost:8000 it only has http://localhost, which looks like a big hint that I am not configuring things correctly. Any leads or assistance would help!

Resources I've tried

StackOverflow threads like this seems promising but similar questions like this receive no meaningful response except to explain the error.

onlyphantom
  • 8,606
  • 4
  • 44
  • 58
  • In your question you state "With Nginx, I would always fail with the error:" I think you missed the error message. – Matt Seymour Aug 21 '19 at 10:45
  • Thank you for catching that Matt. Plenty of sleepless nights :( Fixed. – onlyphantom Aug 21 '19 at 10:47
  • My initial thought was a trailing slash issue, with nginx redirecting. This was the first link I found which might confirm this. "Authorized redirect URIs needs to have the slash, i.e. http://localhost:8080/ this fixes the issue. Source https://github.com/MrSwitch/hello.js/issues/347#issuecomment-168413303" This might make sense as django loves its trailing slashes so if the API is redirecting to a non / url some craziness might be happening with redirects – Matt Seymour Aug 21 '19 at 10:48
  • It does have a slash, in my screenshot you can see my redirect URI would be `http://localhost:8000/auth/complete/github/` – onlyphantom Aug 21 '19 at 10:51
  • :+1:, okay what port number is nginx running on locally on your machine? Is it port 8000 or something different? Wonder if you have a port number mismatch. – Matt Seymour Aug 21 '19 at 10:52
  • in nginx it is listening to port 80, and I have an upstream (full nginx config in the post above) but I do use proxy_pass to make sure is upstreams to my django app container / service at port 8000 (full code up in the post too). I think your lead is interesting, and may be onto something regarding the ports :/ – onlyphantom Aug 21 '19 at 10:55
  • Some libraries will use the url that it discovers, which is `http://webserver` in your nginx config. If your django is served on https://myapp.com, then hopefully there's a way to tell the library to use https://myapp.com as base_url and not http://webserver. What is the library are you using to integrate login with Github? – Son Aug 21 '19 at 10:55
  • @Son I'm using the social-auth-app-django package and yes I've seen that suggestion somewhere too. What would you recommend I do instead? – onlyphantom Aug 21 '19 at 10:57
  • @onlyphantom you can set the `SOCIAL_AUTH_LOGIN_REDIRECT_URL` to something like `https://myapp.com/callback`. More info can be found on https://stackoverflow.com/questions/19684715/python-social-auth-using-django-server-hostname-and-listening-port-as-redirect-u – Son Aug 21 '19 at 15:48

0 Answers0