Search code examples
djangoauthenticationoauth-2.0azure-active-directoryazure-ad-msal

Azure AD redirect URI changes from https to http


Overview

I have an app registered at Azure AD portal. The redirect mechanism has been working great in development, but there is a strange conversion going on Oauth redirect URIs.

Client application is built with Django framework and using MSAL for Python library.

Problem specifically

Suppose I have redirect URI specified as follows in the Azure AD app registration: https://myapp.com/auth/redirect

I get an error AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application: '<application ID>'

Diving into the requests sent, I can see, that the redirect URI gets somehow manipulated somewhere in the process.
(Note the conversion from https -> http)
...redirect_uri=http%3A%2F%2Fmyapp.com%2Fauth%2Fredirect&scope=User.Read.basic....

But the Azure AD actually doesn't even accept URL's with plain http.

I have tried to produce the same error with just localhost, (since localhost URL is exception to the rule, that only https URL's are allowed) and with redirect URL http://localhost:8000/auth/redirect the authentication process works and with https://localhost:8000/auth/redirect it produces the same result described above.


Solution

  • The actual problem came out was...

    The error was related more to Django internals in combination with the MSAL library.

    Azure AD MSAL library for Python uses reverse(redirect_uri) method internally to build the redirect uri somewhere inside and since Django requests use HTTP internally, the redirect uri, that gets added to the request, is the HTTP one.

    Solution

    Adding SECURE_SSL_REDIRECT = True to settings.py fixed the problem.

    Although the ordinary ./manage.py runserver command does not support HTTPS, so

    1. pip install werkzeug django-extensions pyOpenSSL
    2. Add django_extensions under setting.py INSTALLED_APPS
    3. Run server with ./manage.py runserver_plus --cert /tmp/cert localhost:8000

    When the program runs in a web server with front proxy, add this line as well, to not change the original request returned by backend:
    In settings.py -> SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')