Skip to content

[Bug] auth_flow['state'] getting replaced #838

@timthedevguy-truesec

Description

@timthedevguy-truesec

Describe the bug
Django project with custom auth backend. On login page load, a 'Login with Microsoft' url is generated with the 'construct_msal_login_url()' function, and displayed on the page with a templatetag, this function performs the 'initiate_auth_code_flow' step and stores the resulting auth_flow in session for use on callback.

User clicks Login with Microsoft, SSO is enabled in environment, returns to callback, on inspecting the same auth_flow var (stored in session) the 'state' key has been completely changed to a super long value that almost looks like a token.

To Reproduce

Client app is

client_app = msal.ConfidentialClientApplication(
    client_id=settings.MSAL_AUTH["client_id"],
    client_credential=settings.MSAL_AUTH["client_secret"],
    authority=f"https://login.microsoftonline.com/{settings.MSAL_AUTH['tenant_id'] or 'common'}",
)

Steps to reproduce the behavior:

def construct_msal_login_url(request: HttpRequest):
    """
    Construct the redirect URL for MSAL authentication.

    Args:
        request: Current HTTP request object.

    Returns:
        Auth Flow
    """
    # Get the next url from query string if present
    next_url = request.GET.get("next", "/")

    # Build our callback (redirect) URL that will be used once authenticated
    redirect_url = (
        f"{settings.MSAL_AUTH['scheme']}://{settings.MSAL_AUTH['site_domain']}{reverse('msal_auth:callback')}"
    )

    # Create the full Auth url for Microsoft Authentication
    auth_flow = client_app.initiate_auth_code_flow(scopes=settings.MSAL_AUTH["scopes"], redirect_uri=redirect_url)

    # Save to Session for use with callback getting Access Token
    request.session["auth_flow"] = auth_flow
    request.session["next"] = next_url
    test = request.session["auth_flow"]  # <---------------- STATE LOOKS LIKE: 'HrDRgbTYBLjZfKCq'
    return auth_flow

Template Tag

@register.simple_tag(takes_context=True)
def msal_auth_url(context):
    """
    Returns the MSAL authentication URL for the current request context.

    Args:
        context: The template context containing the request.

    Returns:
        str: The MSAL authentication URL.
    """
    request = context["request"]
    auth_flow = auth.construct_msal_login_url(request)
    return auth_flow["auth_uri"]

Link on login page

<a href="{% msal_auth_url %}"><svg ...../></a>

Callback /microsoft/callback

def from_auth_redirect(request: HttpRequest):
    """
    View that handles the redirect from Microsoft after authentication.
    Args:
        request: Current HTTP request object.

    Returns:
        Redirect to the next URL or login page if authentication fails.
    """
    test = request.session["auth_flow"]    # <--------------------- STATE LOOKS LIKE: 'eyJ0b2tlbiI6IkNBNjZHa21ZNld4MkViQkxVN3pkTDFkSWVCNzBDTHJTYkxRbTFQV0J3akg3QjNZSmtPVmt4U3d4ZXR6cnpYQkoiLCJuZXh0IjoiLyJ9:1ubGgs:kEhcT04HwPHH2v1Kk6-HfpeF_xdqS1I1yYDC4vxlOLg'
    .....

So then there is a state mismatch error, I can't find any code changing the state, that is the entire code flow that I have written, URL is generated, Auth initiated, user clicks, callback shows invalid state in the stored auth_flow, BUT the state on the return params is correct....something is changing the stored state.

Expected behavior
Stored state doesn't change

What you see instead
Stored state changes from
'HrDRgbTYBLjZfKCq'
to
'eyJ0b2tlbiI6IkNBNjZHa21ZNld4MkViQkxVN3pkTDFkSWVCNzBDTHJTYkxRbTFQV0J3akg3QjNZSmtPVmt4U3d4ZXR6cnpYQkoiLCJuZXh0IjoiLyJ9:1ubGgs:kEhcT04HwPHH2v1Kk6-HfpeF_xdqS1I1yYDC4vxlOLg'

The MSAL Python version you are using
Paste the output of this
1.32.3

Additional context

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions