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

managed-identity.mddocs/

Azure Managed Identity

Azure managed identities provide automatically managed credentials for applications running on Azure services. MSAL Python's managed identity support eliminates the need for storing credentials in code or configuration, providing secure authentication for Azure resources including virtual machines, container instances, function apps, and other Azure services.

Capabilities

ManagedIdentityClient

Primary client for acquiring tokens using managed identities with automatic credential discovery and token caching.

class ManagedIdentityClient:
    def __init__(
        self,
        managed_identity: Union[dict, ManagedIdentity, SystemAssignedManagedIdentity, UserAssignedManagedIdentity],
        *,
        http_client,  # Required
        token_cache=None,
        http_cache=None,
        client_capabilities: Optional[List[str]] = None
    ):
        """
        Create managed identity client.

        Parameters:
        - managed_identity: SystemAssignedManagedIdentity, UserAssignedManagedIdentity, or dict instance
        - http_client: HTTP client instance (required)
        - token_cache: Custom token cache (default: in-memory cache)
        - http_cache: HTTP cache configuration
        - client_capabilities: List of client capabilities
        """

    def acquire_token_for_client(
        self,
        resource: str,
        claims_challenge=None
    ):
        """
        Acquire token for managed identity.

        Parameters:
        - resource: Target resource URL (e.g., "https://graph.microsoft.com/")
        - claims_challenge: Additional claims from resource provider

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

System-Assigned Managed Identity

System-assigned identities are automatically created with the Azure resource and deleted when the resource is deleted. Each resource can have only one system-assigned identity.

class SystemAssignedManagedIdentity:
    def __init__(self):
        """Create system-assigned managed identity configuration."""

Usage example:

import msal

# Create system-assigned managed identity
managed_identity = msal.SystemAssignedManagedIdentity()

# Create client
client = msal.ManagedIdentityClient(managed_identity)

# Acquire token for Microsoft Graph
result = client.acquire_token_for_client(
    resource="https://graph.microsoft.com/"
)

if "access_token" in result:
    print("Managed identity authentication successful!")
    access_token = result["access_token"]
    
    # Use token to call Microsoft Graph
    import requests
    headers = {"Authorization": f"Bearer {access_token}"}
    response = requests.get("https://graph.microsoft.com/v1.0/me", headers=headers)
    
    if response.status_code == 200:
        user_info = response.json()
        print(f"Authenticated as: {user_info.get('displayName')}")
else:
    print(f"Authentication failed: {result.get('error_description')}")

User-Assigned Managed Identity

User-assigned identities are standalone Azure resources that can be assigned to multiple Azure resources. They have independent lifecycles from the resources they're assigned to.

class UserAssignedManagedIdentity:
    def __init__(
        self,
        client_id=None,
        object_id=None,
        resource_id=None
    ):
        """
        Create user-assigned managed identity configuration.

        Parameters (specify exactly one):
        - client_id: Client ID of user-assigned managed identity
        - object_id: Object ID of user-assigned managed identity  
        - resource_id: Azure resource ID of user-assigned managed identity
        """

Usage examples:

import msal

# Using client ID
managed_identity = msal.UserAssignedManagedIdentity(
    client_id="12345678-1234-1234-1234-123456789012"
)

# Using object ID
managed_identity = msal.UserAssignedManagedIdentity(
    object_id="abcdef12-3456-7890-abcd-123456789012"
)

# Using resource ID
managed_identity = msal.UserAssignedManagedIdentity(
    resource_id="/subscriptions/sub-id/resourcegroups/rg-name/providers/Microsoft.ManagedIdentity/userAssignedIdentities/identity-name"
)

# Create client and acquire token
client = msal.ManagedIdentityClient(managed_identity)

result = client.acquire_token_for_client(
    resource="https://management.azure.com/"
)

if "access_token" in result:
    print("User-assigned managed identity authentication successful!")
    access_token = result["access_token"]
else:
    print(f"Authentication failed: {result.get('error_description')}")

ManagedIdentity Base Class

Base class providing utility methods for managed identity type checking and configuration validation.

class ManagedIdentity:
    # Configuration keys
    ID_TYPE = "ManagedIdentityIdType"
    ID = "Id"
    
    # Identity type constants
    CLIENT_ID = "ClientId"
    RESOURCE_ID = "ResourceId"
    OBJECT_ID = "ObjectId"
    SYSTEM_ASSIGNED = "SystemAssigned"

    @classmethod
    def is_managed_identity(cls, unknown) -> bool:
        """Check if object is a managed identity instance."""

    @classmethod
    def is_system_assigned(cls, unknown) -> bool:
        """Check if object is system-assigned managed identity."""

    @classmethod
    def is_user_assigned(cls, unknown) -> bool:
        """Check if object is user-assigned managed identity."""

Usage example:

import msal

# Check identity types
system_identity = msal.SystemAssignedManagedIdentity()
user_identity = msal.UserAssignedManagedIdentity(client_id="...")

print(f"Is system identity: {msal.ManagedIdentity.is_system_assigned(system_identity)}")
print(f"Is user identity: {msal.ManagedIdentity.is_user_assigned(user_identity)}")
print(f"Is managed identity: {msal.ManagedIdentity.is_managed_identity(system_identity)}")

Supported Azure Services

Managed identities work on various Azure services:

Azure Virtual Machines

import msal

# Works automatically on VM with managed identity enabled
managed_identity = msal.SystemAssignedManagedIdentity()
client = msal.ManagedIdentityClient(managed_identity)

result = client.acquire_token_for_client(
    resource="https://vault.azure.net/"  # Azure Key Vault
)

Azure Container Instances

import msal
import os

# Container instance with user-assigned identity
client_id = os.environ.get("AZURE_CLIENT_ID")
managed_identity = msal.UserAssignedManagedIdentity(client_id=client_id)
client = msal.ManagedIdentityClient(managed_identity)

result = client.acquire_token_for_client(
    resource="https://storage.azure.com/"  # Azure Storage
)

Azure Functions

import msal
import azure.functions as func

def main(req: func.HttpRequest) -> func.HttpResponse:
    # Function app with system-assigned identity
    managed_identity = msal.SystemAssignedManagedIdentity()
    client = msal.ManagedIdentityClient(managed_identity)
    
    result = client.acquire_token_for_client(
        resource="https://database.windows.net/"  # Azure SQL
    )
    
    if "access_token" in result:
        # Use token to access Azure SQL
        access_token = result["access_token"]
        return func.HttpResponse("Authentication successful")
    else:
        return func.HttpResponse("Authentication failed", status_code=401)

Azure App Service

import msal
from flask import Flask

app = Flask(__name__)

@app.route('/api/data')
def get_data():
    # App Service with managed identity
    managed_identity = msal.SystemAssignedManagedIdentity()
    client = msal.ManagedIdentityClient(managed_identity)
    
    result = client.acquire_token_for_client(
        resource="https://cognitiveservices.azure.com/"  # Cognitive Services
    )
    
    if "access_token" in result:
        # Call Cognitive Services API
        import requests
        headers = {"Authorization": f"Bearer {result['access_token']}"}
        # Make API call...
        return {"status": "success"}
    else:
        return {"status": "error", "message": result.get("error_description")}

Token Caching with Managed Identity

Managed identity tokens are automatically cached to improve performance:

import msal

# Custom cache for managed identity tokens
cache = msal.TokenCache()

managed_identity = msal.SystemAssignedManagedIdentity()
client = msal.ManagedIdentityClient(
    managed_identity=managed_identity,
    token_cache=cache
)

# First call - acquires token from Azure Instance Metadata Service (IMDS)
result1 = client.acquire_token_for_client(
    resource="https://graph.microsoft.com/"
)

# Second call - uses cached token if still valid
result2 = client.acquire_token_for_client(
    resource="https://graph.microsoft.com/"
)

print(f"First call successful: {'access_token' in result1}")
print(f"Second call successful: {'access_token' in result2}")

Multiple Resource Access

Single managed identity can access multiple Azure resources:

import msal

managed_identity = msal.SystemAssignedManagedIdentity()
client = msal.ManagedIdentityClient(managed_identity)

# Access different Azure resources
resources = [
    "https://graph.microsoft.com/",      # Microsoft Graph
    "https://management.azure.com/",     # Azure Resource Manager
    "https://vault.azure.net/",          # Azure Key Vault
    "https://storage.azure.com/",        # Azure Storage
    "https://database.windows.net/",     # Azure SQL Database
]

tokens = {}
for resource in resources:
    result = client.acquire_token_for_client(resource=resource)
    
    if "access_token" in result:
        tokens[resource] = result["access_token"]
        print(f"Successfully acquired token for {resource}")
    else:
        print(f"Failed to acquire token for {resource}: {result.get('error_description')}")

print(f"Acquired tokens for {len(tokens)} resources")

Environment Detection

Managed identity authentication automatically detects the Azure environment:

import msal

managed_identity = msal.SystemAssignedManagedIdentity()
client = msal.ManagedIdentityClient(managed_identity)

# Works across different Azure environments:
# - Azure Virtual Machines (IMDS endpoint)
# - Azure Container Instances (IMDS endpoint)  
# - Azure Functions (MSI_ENDPOINT environment variable)
# - Azure App Service (MSI_ENDPOINT environment variable)
# - Azure Arc (Azure Arc metadata service)
# - Azure Cloud Shell (Azure Cloud Shell service)

result = client.acquire_token_for_client(
    resource="https://graph.microsoft.com/"
)

# The client automatically detects and uses the appropriate endpoint
if "access_token" in result:
    print("Managed identity authentication successful")
    print(f"Token source: {result.get('token_source', 'unknown')}")

Error Handling

Common error scenarios and handling patterns for managed identity authentication:

import msal

managed_identity = msal.SystemAssignedManagedIdentity()
client = msal.ManagedIdentityClient(managed_identity)

try:
    result = client.acquire_token_for_client(
        resource="https://graph.microsoft.com/"
    )
    
    if "access_token" in result:
        access_token = result["access_token"]
        print("Authentication successful")
    else:
        error = result.get("error")
        error_description = result.get("error_description", "")
        
        if error == "managed_identity_not_available":
            print("Managed identity not available on this resource")
            print("Ensure managed identity is enabled on the Azure resource")
        elif error == "invalid_resource":
            print(f"Invalid resource specified: {error_description}")
        elif error == "forbidden":
            print("Managed identity doesn't have permission for this resource")
            print("Check Azure role assignments for the managed identity")
        elif error == "arc_platform_not_supported":
            print("Azure Arc managed identity not supported on this platform")
        else:
            print(f"Authentication failed: {error} - {error_description}")

except msal.ManagedIdentityError as e:
    print(f"Managed identity error: {e}")
except msal.ArcPlatformNotSupportedError as e:
    print(f"Azure Arc platform not supported: {e}")
except Exception as e:
    print(f"Unexpected error: {e}")

# User-assigned identity error handling
try:
    user_identity = msal.UserAssignedManagedIdentity(
        client_id="invalid-client-id"
    )
    client = msal.ManagedIdentityClient(user_identity)
    
    result = client.acquire_token_for_client(
        resource="https://graph.microsoft.com/"
    )
    
    if "access_token" not in result:
        error = result.get("error")
        
        if error == "identity_not_found":
            print("User-assigned managed identity not found")
            print("Verify the client_id/object_id/resource_id is correct")
            print("Ensure the identity is assigned to this resource")
        elif error == "multiple_identities_found":
            print("Multiple user-assigned identities found")
            print("Specify client_id, object_id, or resource_id to disambiguate")

except ValueError as e:
    print(f"Invalid managed identity configuration: {e}")

Best Practices

Security Considerations

  • Use least-privilege principle when assigning roles to managed identities
  • Regularly review and audit managed identity role assignments
  • Use user-assigned identities for better lifecycle management in complex scenarios
  • Monitor managed identity usage through Azure Activity Logs

Performance Optimization

  • Leverage automatic token caching to minimize authentication requests
  • Use appropriate token lifetimes for your application's needs
  • Consider connection pooling for HTTP clients in high-throughput scenarios

Deployment Patterns

import msal
import os

def create_managed_identity_client():
    """Factory function for managed identity client creation."""
    
    # Check for user-assigned identity configuration
    client_id = os.environ.get("AZURE_CLIENT_ID")
    
    if client_id:
        # Use user-assigned identity
        managed_identity = msal.UserAssignedManagedIdentity(client_id=client_id)
    else:
        # Use system-assigned identity
        managed_identity = msal.SystemAssignedManagedIdentity()
    
    return msal.ManagedIdentityClient(managed_identity)

# Usage in application
def authenticate_and_call_api():
    client = create_managed_identity_client()
    
    result = client.acquire_token_for_client(
        resource="https://graph.microsoft.com/"
    )
    
    if "access_token" in result:
        return result["access_token"]
    else:
        raise Exception(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