CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-msal

Microsoft Authentication Library for Python enabling OAuth2/OIDC authentication with Microsoft identity platform

Pending
Overview
Eval results
Files

public-client.mddocs/

Public Client Applications

Public client applications are designed for desktop and mobile applications where the client cannot securely store credentials. MSAL Python's PublicClientApplication supports interactive authentication through web browsers, device code flow for browserless environments, and optional broker integration for enhanced security.

Capabilities

Application Initialization

Creates a public client application instance with optional broker support for enhanced security through device identity and single sign-on capabilities.

class PublicClientApplication(ClientApplication):
    def __init__(
        self,
        client_id: str,
        client_credential=None,  # Must remain None for public clients
        *,
        enable_broker_on_windows=None,
        enable_broker_on_mac=None,
        enable_broker_on_linux=None,
        enable_broker_on_wsl=None,
        authority=None,
        validate_authority=True,
        token_cache=None,
        http_client=None,
        verify=True,
        proxies=None,
        timeout=None,
        client_claims=None,
        app_name=None,
        app_version=None,
        client_capabilities=None,
        exclude_scopes=None,
        http_cache=None,
        instance_discovery=None,
        allow_broker=None,
        enable_pii_log=None,
        oidc_authority=None,
        **kwargs
    ):
        """
        Create a public client application.

        Parameters:
        - client_id: Your app's client ID from Azure portal
        - enable_broker_on_windows: Enable broker on Windows 10+ (requires redirect URI)
        - enable_broker_on_mac: Enable broker on macOS with Company Portal
        - enable_broker_on_linux: Enable broker on Linux
        - enable_broker_on_wsl: Enable broker on Windows Subsystem for Linux
        - authority: Authority URL (default: https://login.microsoftonline.com/common)
        - token_cache: Custom token cache instance
        - http_client: Custom HTTP client
        - proxies: HTTP proxy configuration
        - timeout: HTTP timeout in seconds
        """

Usage example:

import msal

# Basic public client
app = msal.PublicClientApplication(
    client_id="12345678-1234-1234-1234-123456789012",
    authority="https://login.microsoftonline.com/common"
)

# With broker support (requires appropriate redirect URI registration)
app_with_broker = msal.PublicClientApplication(
    client_id="12345678-1234-1234-1234-123456789012",
    authority="https://login.microsoftonline.com/your-tenant-id",
    enable_broker_on_windows=True,
    enable_broker_on_mac=True
)

Interactive Authentication

Performs interactive authentication by opening a web browser for user sign-in. Supports various prompt behaviors, login hints, and additional consent scopes.

def acquire_token_interactive(
    self,
    scopes: list,
    prompt=None,
    login_hint=None,
    domain_hint=None,
    claims_challenge=None,
    timeout=None,
    port=None,
    extra_scopes_to_consent=None,
    max_age=None,
    parent_window_handle=None,
    on_before_launching_ui=None,
    auth_scheme=None,
    **kwargs
):
    """
    Acquire token interactively via web browser.

    Parameters:
    - scopes: List of scopes to request (e.g., ["User.Read", "Mail.Send"])
    - prompt: Prompt behavior (msal.Prompt.NONE, LOGIN, CONSENT, SELECT_ACCOUNT)
    - login_hint: Email address to pre-populate sign-in form
    - domain_hint: Domain hint to skip domain selection
    - claims_challenge: Additional claims from resource provider
    - timeout: Browser interaction timeout in seconds
    - port: Local server port for auth response (default: random)
    - extra_scopes_to_consent: Additional scopes for upfront consent
    - max_age: Maximum authentication age in seconds
    - parent_window_handle: Handle to parent window (Windows only)
    - on_before_launching_ui: Callback before launching browser
    - auth_scheme: Authentication scheme (e.g., PopAuthScheme for PoP tokens)

    Returns:
    Dictionary with 'access_token' on success, 'error' on failure
    """

Usage example:

import msal

app = msal.PublicClientApplication(
    client_id="your-client-id",
    authority="https://login.microsoftonline.com/common"
)

# Basic interactive authentication
result = app.acquire_token_interactive(
    scopes=["User.Read", "Mail.Read"]
)

# With specific prompt and login hint
result = app.acquire_token_interactive(
    scopes=["User.Read"],
    prompt=msal.Prompt.SELECT_ACCOUNT,
    login_hint="user@example.com",
    timeout=120
)

if "access_token" in result:
    print("Authentication successful!")
    access_token = result["access_token"]
    expires_in = result["expires_in"]
else:
    print(f"Error: {result.get('error')}")
    print(f"Description: {result.get('error_description')}")

Device Code Flow

Initiates and completes device code authentication flow for devices without web browsers or limited input capabilities. Users authenticate on a separate device using a provided code.

def initiate_device_flow(
    self,
    scopes=None,
    **kwargs
):
    """
    Initiate device code flow.

    Parameters:
    - scopes: List of scopes to request

    Returns:
    Dictionary containing device_code, user_code, verification_uri, 
    verification_uri_complete, expires_in, interval, and message
    """

def acquire_token_by_device_flow(
    self,
    flow: dict,
    claims_challenge=None,
    **kwargs
):
    """
    Complete device code flow with polling.

    Parameters:
    - flow: Flow dictionary from initiate_device_flow()
    - claims_challenge: Additional claims from resource provider

    Returns:
    Dictionary with 'access_token' on success, 'error' on failure
    """

Usage example:

import msal
import time

app = msal.PublicClientApplication(
    client_id="your-client-id",
    authority="https://login.microsoftonline.com/common"
)

# Initiate device flow
flow = app.initiate_device_flow(scopes=["User.Read"])

if "user_code" not in flow:
    raise ValueError(f"Failed to create device flow: {flow.get('error_description')}")

# Display instructions to user
print(flow["message"])

# Poll for completion
result = app.acquire_token_by_device_flow(flow)

if "access_token" in result:
    print("Device authentication successful!")
    access_token = result["access_token"]
else:
    print(f"Device authentication failed: {result.get('error_description')}")

Broker Integration

When broker is enabled, authentication goes through the platform's authentication broker (e.g., Web Account Manager on Windows, Company Portal on macOS) for enhanced security and single sign-on capabilities.

Required redirect URIs for broker support:

  • Windows/WSL: ms-appx-web://Microsoft.AAD.BrokerPlugin/your_client_id
  • macOS: msauth.com.msauth.unsignedapp://auth
  • Linux: http://localhost

Usage considerations:

  • Broker provides device identity as an additional authentication factor
  • Enables automatic SSO from previously established sessions
  • May be required by Conditional Access policies
  • Requires appropriate redirect URI registration in Azure portal
# Broker-enabled application
app = msal.PublicClientApplication(
    client_id="your-client-id",
    authority="https://login.microsoftonline.com/your-tenant-id",
    enable_broker_on_windows=True,
    enable_broker_on_mac=True,
    enable_broker_on_linux=True
)

# Interactive auth will use broker when available
result = app.acquire_token_interactive(scopes=["User.Read"])

Error Handling

Common error scenarios and handling patterns:

result = app.acquire_token_interactive(scopes=["User.Read"])

if "access_token" in result:
    # Success
    access_token = result["access_token"]
    expires_in = result["expires_in"]
    token_type = result.get("token_type", "Bearer")
elif result.get("error") == "access_denied":
    # User cancelled or denied consent
    print("User cancelled authentication")
elif result.get("error") == "invalid_scope":
    # Invalid or unauthorized scope requested
    print(f"Invalid scope: {result.get('error_description')}")
elif result.get("error") == "interaction_required":
    # Silent authentication failed, interaction needed
    print("Interactive authentication required")
else:
    # Other error
    print(f"Authentication failed: {result.get('error_description')}")

Install with Tessl CLI

npx tessl i tessl/pypi-msal

docs

common-auth-flows.md

confidential-client.md

index.md

managed-identity.md

public-client.md

security-advanced.md

token-cache.md

tile.json