CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-adal

Azure Active Directory Authentication Library for Python that provides OAuth2/OpenID Connect authentication flows and token management for accessing Azure AD protected resources

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

device-code-flow.mddocs/

Device Code Flow

Specialized OAuth2 device code flow for applications running on devices without web browsers or with limited input capabilities. This flow is ideal for IoT devices, CLI tools, smart TVs, or other scenarios where traditional web-based authentication is not feasible.

How Device Code Flow Works

  1. Application requests a device code and user code from Azure AD
  2. User is presented with a user code and verification URL
  3. User navigates to the URL on a separate device and enters the code
  4. Application polls Azure AD for token using the device code
  5. Once user completes authentication, Azure AD returns tokens

Capabilities

Initiate Device Code Flow

Requests device and user codes from Azure Active Directory to begin the device authentication process.

def acquire_user_code(self, resource, client_id, language=None):
    """
    Get device code and user code for device flow authentication.
    
    Parameters:
    - resource (str): URI identifying the target resource
    - client_id (str): OAuth2 client ID of the application
    - language (str, optional): Language code for user messages (e.g., 'en-us')
    
    Returns:
    dict: Device code response containing:
        - userCode (str): Code for user to enter at verification URL
        - deviceCode (str): Device code for polling token endpoint
        - verificationUrl (str): URL where user enters the code
        - expiresIn (int): Seconds until codes expire (typically 900)
        - interval (int): Recommended polling interval in seconds
        - message (str): User-friendly instructions
    """

Usage Example:

import adal
import time

context = adal.AuthenticationContext('https://login.microsoftonline.com/tenant-id')

# Get device code
user_code_info = context.acquire_user_code(
    resource='https://management.azure.com/',
    client_id='your-client-id'
)

print(f"Please visit {user_code_info['verificationUrl']}")
print(f"And enter this code: {user_code_info['userCode']}")
print(f"Message: {user_code_info['message']}")

Complete Device Code Authentication

Polls Azure Active Directory for tokens using the device code after the user has completed authentication.

def acquire_token_with_device_code(self, resource, user_code_info, client_id):
    """
    Poll for token using device code after user authentication.
    
    Parameters:
    - resource (str): URI identifying the target resource
    - user_code_info (dict): Device code response from acquire_user_code()
    - client_id (str): OAuth2 client ID of the application
    
    Returns:
    dict: Authentication result with access token, refresh token, and metadata
    
    Raises:
    AdalError: If user denies consent, code expires, or other authentication errors
    """

Usage Example:

# After displaying user code, poll for token
try:
    token = context.acquire_token_with_device_code(
        resource='https://management.azure.com/',
        user_code_info=user_code_info,
        client_id='your-client-id'
    )
    print("Authentication successful!")
    print(f"Access token: {token['accessToken']}")
    
except adal.AdalError as e:
    print(f"Device authentication failed: {e}")

Cancel Device Code Request

Cancels an ongoing device code authentication request, useful when the application needs to abort the flow.

def cancel_request_to_get_token_with_device_code(self, user_code_info):
    """
    Cancel ongoing device code authentication request.
    
    Parameters:
    - user_code_info (dict): Device code response from acquire_user_code()
    
    Returns:
    None
    """

Usage Example:

# Cancel if user requests abort or timeout occurs
context.cancel_request_to_get_token_with_device_code(user_code_info)
print("Device authentication cancelled")

Complete Device Code Flow Example

import adal
import time
import threading

def device_flow_authentication():
    authority_url = 'https://login.microsoftonline.com/your-tenant-id'
    context = adal.AuthenticationContext(authority_url)
    
    resource = 'https://management.azure.com/'
    client_id = 'your-client-id'
    
    try:
        # Step 1: Get device code
        print("Initiating device code flow...")
        user_code_info = context.acquire_user_code(resource, client_id)
        
        # Step 2: Display instructions to user
        print(f"\nTo sign in, use a web browser to open the page:")
        print(f"{user_code_info['verificationUrl']}")
        print(f"\nAnd enter the code: {user_code_info['userCode']}")
        print(f"\nMessage: {user_code_info['message']}")
        print(f"\nWaiting for authentication...")
        
        # Optional: Set up cancellation after timeout
        def cancel_after_timeout():
            time.sleep(user_code_info['expiresIn'])
            try:
                context.cancel_request_to_get_token_with_device_code(user_code_info)
                print("\nDevice code expired, authentication cancelled")
            except:
                pass  # May already be completed
        
        timeout_thread = threading.Thread(target=cancel_after_timeout)
        timeout_thread.daemon = True
        timeout_thread.start()
        
        # Step 3: Poll for token
        token = context.acquire_token_with_device_code(
            resource, user_code_info, client_id
        )
        
        print("\nAuthentication successful!")
        print(f"User: {token.get('userId', 'Unknown')}")
        print(f"Token expires: {token.get('expiresOn', 'Unknown')}")
        
        return token
        
    except adal.AdalError as e:
        print(f"\nDevice authentication failed: {e}")
        return None

# Run the flow
token = device_flow_authentication()

Error Handling

Device code flow can fail for several reasons:

  • User cancellation: User denies consent or closes browser
  • Code expiration: User doesn't complete authentication within time limit
  • Invalid client: Client ID is not configured for device code flow
  • Network issues: Connectivity problems during polling
try:
    token = context.acquire_token_with_device_code(
        resource, user_code_info, client_id
    )
except adal.AdalError as e:
    if "authorization_pending" in str(e):
        # Still waiting for user - continue polling
        pass
    elif "authorization_declined" in str(e):
        print("User declined authorization")
    elif "expired_token" in str(e):
        print("Device code expired")
    else:
        print(f"Other error: {e}")

Best Practices

  1. Display clear instructions: Show both the URL and code prominently
  2. Handle timeouts gracefully: Codes typically expire in 15 minutes
  3. Respect polling intervals: Use the recommended interval from the response
  4. Provide cancellation: Allow users to abort the flow
  5. Cache tokens: Store refresh tokens for future use to avoid repeated device flows

Install with Tessl CLI

npx tessl i tessl/pypi-adal

docs

authentication-flows.md

device-code-flow.md

index.md

logging-error-handling.md

token-caching.md

tile.json