AzureAD / microsoft-authentication-library-for-python

Microsoft Authentication Library (MSAL) for Python makes it easy to authenticate to Microsoft Entra ID. General docs are available here https://learn.microsoft.com/entra/msal/python/ Stable APIs are documented here https://msal-python.readthedocs.io. Questions can be asked on www.stackoverflow.com with tag "msal" + "python".
https://stackoverflow.com/questions/tagged/azure-ad-msal+python
Other
757 stars 192 forks source link

acquire_token_by_auth_flow fails due to extra symbol in URI #521

Closed szofar closed 1 year ago

szofar commented 1 year ago

Describe the bug acquire_token_by_auth_flow appends "#" to the response URI and attempts to redirect to the invalid URI.

I am calling the "acquire_token_by_auth_flow" method exactly how it is written in the code sample on the Azure Quickstart page for a web Python app: https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/Quickstart/appId/**myID**/isMSAApp~/false

        result = _build_msal_app(cache=cache).acquire_token_by_auth_code_flow(
            session.get("flow", {}), request.args)
        if "error" in result:
            return render_template("auth_error.html", result=result)

On my local machine, it works perfectly, and the URI redirected to by acquire_token_by_auth_flow looks like this:

https://xyzzything.com/get-azure-authentication-token?code=0.AQ&state=x&session_state=977

On the deployed Cloud Foundry app, it fails because "acquire_token_by_auth_flow" is appending a "#" character to the URI before it redirects to the URI.

The error looks like this:

{'error': 'invalid_grant', 'error_description': 'AADSTS501481: The Code_Verifier does not match the code_challenge supplied in the authorization request.\r\nTrace ID: 08ae038b-d78c-46e5-9ce4-5b910e7cb100\r\nCorrelation ID: ec861b3e-30ef-4708-a348-0c7b5fbbda05\r\nTimestamp: 2022-12-12 22:41:58Z', 'error_codes': [501481], 'timestamp': '2022-12-12 22:41:58Z', 'trace_id': '08ae038b-d78c-46e5-9ce4-5b910e7cb100', 'correlation_id': 'ec861b3e-30ef-4708-a348-0c7b5fbbda05'}

And the URI in the address bar has a "#" character appended:

https://xyzzything.com/get-azure-authentication-token?code=0.AQ&state=x&session_state=977#

It does not append this character on my local machine.

When I remove the character from the URI and proceed with the flow by manually running the sans-"#" URI in the address bar, it completes successfully and logs me in.

To Reproduce Steps to reproduce the behavior:

  1. Get the Quickstart sample for a Python web app from the Azure app portal. Replace my ID with your app id. https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/Quickstart/appId/**myID**/isMSAApp~/false
  2. Make sure your app is set up with secrets and stuff
  3. Launch as a WSGI app in Cloud Foundry on Ubuntu 18 using python 3.9.12 with flask-session 0.4.0
    gunicorn==20.1.0
    flask==2.0.2
    pymongo==3.12.1
    openpyxl==3.0.9
    plotly==5.8.0
    Flask-Assets==2.0
    pyscss==1.3.7
    Flask-Bootstrap==3.3.7.1
    distro==1.7.0
    msal==1.20.0
    flask-session==0.4.0

Expected behavior It should complete the request without appending a "#" to the URI and then redirect to the valid URI.

What you see instead It appends "#" to the response URI and attempts to redirect to the invalid URI.

The MSAL Python version you are using 1.20.0

Additional context Again, if I remove the "#" and run the edited URI directly, it resumes the flow correctly.

I've tried to use 'response_mode="query"' in the initiate_auth_code_flow method. It adds "&response=query" to the URI, but doesn't solve the issue.

'print(session.get("flow", {}))' doesn't have the "#" appended, so I know Azure isn't adding that bit. image

You can see the result of that print here, where redirect_uri doesn't have the "#":

{'state': 'emr_a0', 'redirect_uri': 'http://xyzzything.com/get-azure-authentication-token', 'scope': ['profile', 'offline_access', 'openid'], 'auth_uri': 'https://login.microsoftonline.com/.../oauth2/v2.0/authorize?client_id=...&response_type=code&redirect_uri=...get-azure-authentication-token&scope=offline_access+openid+profile&state=x&code_challenge=...&code_challenge_method=S256&nonce=...&client_info=1&response_mode=query', 'code_verifier': '...', 'nonce': '...', 'claims_challenge': None}

szofar commented 1 year ago

I think it involves the session "state" override I was including

szofar commented 1 year ago

I had messed with the example app more than I thought. All good here...