Search code examples
pythonazuremicrosoft-graph-apiazure-web-app-serviceazure-ad-msal

MSAL Authorization in Linux Azure Web App "Found no browser in current environment"


I currently have a solution where a user presses a button using a Gradio frontend and using Azure Authentication and MSAL it will prompt the user to login and using the token from that it will use GraphAPI to get the authenticated users Azure email. This is the code below:

def get_username():
    # Your existing code
    credential = DefaultAzureCredential()
    key_vault_url = "https://XXXXX.vault.azure.net/"
    client = SecretClient(vault_url=key_vault_url, credential=credential)

    secret_name = "subid"
    subid = client.get_secret(secret_name).value

    secret_name = "client-secret"
    client_secret = client.get_secret(secret_name).value

    secret_name = "client-id"
    client_id = client.get_secret(secret_name).value

    print("Secrets read from KV")

    authority = f'https://login.microsoftonline.com/{subid}'
    scope = ["https://graph.microsoft.com/.default"]

    app = msal.PublicClientApplication(
            client_id,
            authority=authority,
    )

    token_response = app.acquire_token_interactive(scopes=scope)
    access_token = token_response['access_token']

    headers = {
            'Authorization': f'Bearer {access_token}'
    }

    response = requests.get('https://graph.microsoft.com/v1.0/me', headers=headers)
    user_data = response.json()

    email = user_data["mail"]

    return f"Username: {email}"

This works locally and when Dockerized, but when I run it on Azure Web apps I get the following error:

Found no browser in current environment. If this program is being run inside a container which has access to host network (i.e. started by `docker run --net=host -it ...`), you can use browser on host to visit the following link. Otherwise, this auth attempt would either timeout (current timeout setting is None) or be aborted by CTRL+C. Auth URI: https://login.microsoftonline.com/93f33571-550f-43cf-b09f-cd331338d086/oauth2/v2.0/authorize?client_id=c717af3f-df2d-4790-8c5f-d3829d34991a&response_type=code&redirect_uri=http%3A%2F%2Flocalhost%3A35479&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default+offline_access+openid+profile&state=RsIQdlWULnvGrqPe&code_challenge=C0uwlEVEkKqr76_h9kHjRTsLavlXHija4WG2DQlp4B4&code_challenge_method=S256&nonce=32b2eac9decbaeea457ce0effcee125e8336eca3db81ebda868598b72c7e3853&client_info=1

From the research i have done I don't think there is a way to change the Azure Web Apps docker run command so I cannot include -net=host but could be wrong.

Does anyone know a way to fix this issue?


Solution

  • Azure Web App environment doesn't have a direct browser access, and the MSAL library is trying to launch a browser for interactive authentication, which is not possible in this scenario.

    • Here, I Switched from interactive authentication to device code flow.

    auth_.py:

    import requests
    import msal
    
    def get_username():
        # Your existing code
        credential = DefaultAzureCredential()
        key_vault_url = "https://XXXXX.vault.azure.net/"
        client = SecretClient(vault_url=key_vault_url, credential=credential)
    
        secret_name = "subid"
        subid = client.get_secret(secret_name).value
    
        secret_name = "client-secret"
        client_secret = client.get_secret(secret_name).value
    
        secret_name = "client-id"
        client_id = client.get_secret(secret_name).value
    
        print("Secrets read from KV")
    
        authority = f'https://login.microsoftonline.com/{subid}'
        scope = ["https://graph.microsoft.com/.default"]
    
        app = msal.ConfidentialClientApplication(
            client_id,
            authority=authority,
            client_credential=client_secret,
        )
    
        # Using device code flow
        token_response = app.acquire_token_for_client(scopes=scope)
    
        headers = {
            'Authorization': f'Bearer {token_response["access_token"]}'
        }
    
        response = requests.get('https://graph.microsoft.com/v1.0/me', headers=headers)
        user_data = response.json()
    
        email = user_data["mail"]
    
        return f"Username: {email}"
    
    # Call the function
    print(get_username())
    

    Secrets: enter image description here

    enter image description here

    Device code Authorization: enter image description here

    enter image description here