Search code examples
pythonazureazure-active-directorytokenmsal

Python: MSAL --> Getting token with username and password


I am following the Microsoft documentation for aquiring an MSAL token by username and password.

For understanding how MSAL works I try something very simple: Aquiring a token using a username and password. Curly brackets ({}) in the below example represent IDs or credentials I have copied there.

authority_url = 'https://login.microsoftonline.com/{Tenant}’
app = msal.PublicClientApplication(
    authority=authority_url
    , client_id={client_id}'
    , client_credential=None
)

app.acquire_token_by_username_password(
    '{mail_of_windows_user}'
    , ‘{password_of_windows_user}’
    , scopes = ["User.Read"])

When I run the code I get an error with ID 7000218:

The request body must contain the following parameter: 'client_assertion' or 'client_secret'.

This error is unexpected because a PublicClientApplication should work without a client secret. In the documentation for the parameter client_credential, one can read:

For PublicClientApplication, you simply use None here.

Why do I need a client secret even though the documentation states I need none?


Solution

  • The error usually occurs if you missed enabling public-client flows option while generating token using username password flow, which is required to recognize app registration as public client application.

    Initially, I too got same error when I ran below code to generate access token without enabling public-client flows option:

    import msal
    
    authority_url ='https://login.microsoftonline.com/{Tenant}’
    app = msal.PublicClientApplication(
        authority=authority_url,
        client_id={client_id},
        client_credential=None
    )
    result = app.acquire_token_by_username_password(
        '{mail_of_windows_user}'
        , '{password_of_windows_user}'
        , scopes = ["User.Read"])
    
    if "access_token" in result:
        access_token = result["access_token"]
        print(f"Access Token: {access_token}")
    else:
        print(result.get('error_description'))
    

    Response:

    enter image description here

    To resolve the error, make sure to enable public-client flows option in your app registration like this:

    enter image description here

    When I ran code again after enabling public-client flows without passing client secret, I got access token successfully in response:

    import msal
    
    authority_url ='https://login.microsoftonline.com/{Tenant}’
    app = msal.PublicClientApplication(
        authority=authority_url,
        client_id={client_id},
        client_credential=None
    )
    result = app.acquire_token_by_username_password(
        '{mail_of_windows_user}'
        , '{password_of_windows_user}'
        , scopes = ["User.Read"])
    
    if "access_token" in result:
        access_token = result["access_token"]
        print(f"Access Token: {access_token}")
    else:
        print(result.get('error_description'))
    

    Response:

    enter image description here

    You can decode the above token in jwt.ms and check whether the claims are valid or not like this:

    enter image description here

    Reference: Microsoft identity platform and OAuth 2.0 Resource Owner Password Credentials