🔍 Code Extractor

class AzureSSO_v2

Maturity: 51

A class that handles Azure Active Directory (Azure AD) Single Sign-On (SSO) authentication using OAuth 2.0 authorization code flow.

File:
/tf/active/vicechatdev/CDocs/auth/azure_auth.py
Lines:
18 - 125
Complexity:
moderate

Purpose

This class provides a complete implementation for Azure AD SSO authentication. It manages the OAuth 2.0 authorization code flow, including generating authorization URLs for user login redirection and exchanging authorization codes for access tokens. It uses the Microsoft Authentication Library (MSAL) for secure token acquisition and handles scope filtering to comply with Azure AD requirements. The class is designed for web applications that need to authenticate users through Azure AD and obtain access tokens for Microsoft Graph or other Azure resources.

Source Code

class AzureSSO:
    """Class to handle Azure Active Directory SSO authentication."""
    
    def __init__(self, client_id, tenant_id, client_secret, redirect_uri, scope):
        """
        Initialize Azure SSO with the required configuration.
        
        Args:
            client_id: Azure AD application client ID
            tenant_id: Azure AD tenant ID
            client_secret: Azure AD application client secret
            redirect_uri: Callback URL after authentication
            scope: OAuth scopes to request
        """
        self.client_id = client_id
        self.tenant_id = tenant_id
        self.client_secret = client_secret
        self.redirect_uri = redirect_uri
        self.scope = scope
        self.authority = f"https://login.microsoftonline.com/{tenant_id}"
        self.authorize_endpoint = f"{self.authority}/oauth2/v2.0/authorize"
        self.token_endpoint = f"{self.authority}/oauth2/v2.0/token"
        
        # Fix the URL creation in the get_auth_url method
    
    def get_auth_url(self, response_mode='query'):
        """
        Generate the authorization URL for redirecting users to Azure login.
        
        Parameters
        ----------
        response_mode : str, optional
            How Azure should return the response ('query' or 'fragment')
            
        Returns
        -------
        str
            The authorization URL
        """
        # Create URL parameters
        params = {
            'client_id': self.client_id,
            'response_type': 'code',
            'redirect_uri': self.redirect_uri,
            'scope': self.scope,
            'response_mode': response_mode,  # Allow customizing this
            'state': str(uuid.uuid4()),  # CSRF protection
        }
        
        # Use urllib.parse to properly encode parameters
        auth_url = f"{self.authorize_endpoint}?{urllib.parse.urlencode(params)}"
        
        return auth_url
        
    def get_token_from_code(self, auth_code: str) -> dict:
        """
        Exchange authorization code for access and ID tokens.
        
        Args:
            auth_code: Authorization code received from Azure AD
            
        Returns:
            dict: Token response containing access_token, id_token, etc.
        """
        try:
            logger.info(f"Creating MSAL application with client_id: {self.client_id}")
            logger.info(f"Authority: {self.authority}")
            logger.info(f"Redirect URI for token exchange: {self.redirect_uri}")
            
            # Use MSAL library to handle token exchange
            app = msal.ConfidentialClientApplication(
                self.client_id,
                authority=self.authority,
                client_credential=self.client_secret
            )
            
            # Filter out reserved scopes for token exchange
            reserved_scopes = {'profile', 'openid', 'offline_access'}
            requested_scopes = self.scope.split()
            
            # Remove reserved scopes for token exchange
            filtered_scopes = [scope for scope in requested_scopes if scope not in reserved_scopes]
            
            # If all scopes were reserved (e.g., only 'openid profile'), use at least one non-reserved scope
            if not filtered_scopes:
                filtered_scopes = ['User.Read']  # A common Microsoft Graph scope
                
            logger.info(f"Original scopes: {requested_scopes}")
            logger.info(f"Filtered scopes for token exchange: {filtered_scopes}")
            
            # Get token using authorization code with filtered scopes
            result = app.acquire_token_by_authorization_code(
                auth_code,
                scopes=filtered_scopes,  # Use filtered scopes here
                redirect_uri=self.redirect_uri
            )
            
            if "error" in result:
                logger.error(f"Error acquiring token: {result.get('error')}")
                logger.error(f"Error description: {result.get('error_description')}")
                return {}
                
            logger.info(f"Token acquired successfully with keys: {result.keys()}")
            return result
            
        except Exception as e:
            logger.error(f"Exception in get_token_from_code: {e}", exc_info=True)
            return {}

Parameters

Name Type Default Kind
bases - -

Parameter Details

client_id: The Azure AD application (client) ID obtained from Azure Portal when registering your application. This uniquely identifies your application to Azure AD.

tenant_id: The Azure AD tenant ID (directory ID) that identifies your organization's Azure AD instance. Can be a GUID or a domain name. Use 'common' for multi-tenant applications.

client_secret: The client secret (application password) generated in Azure Portal for your application. This is used to authenticate your application when exchanging authorization codes for tokens. Must be kept secure.

redirect_uri: The callback URL where Azure AD will redirect users after authentication. This must exactly match one of the redirect URIs configured in your Azure AD application registration.

scope: Space-separated string of OAuth scopes to request. Common scopes include 'openid', 'profile', 'offline_access', 'User.Read'. Determines what permissions and data your application can access.

Return Value

The constructor returns an instance of AzureSSO configured with the provided credentials. The get_auth_url() method returns a string containing the full authorization URL. The get_token_from_code() method returns a dictionary containing token information (access_token, id_token, token_type, expires_in, etc.) on success, or an empty dictionary on failure.

Class Interface

Methods

__init__(self, client_id, tenant_id, client_secret, redirect_uri, scope)

Purpose: Initializes the AzureSSO instance with Azure AD configuration and constructs the necessary OAuth endpoints

Parameters:

  • client_id: Azure AD application client ID
  • tenant_id: Azure AD tenant ID
  • client_secret: Azure AD application client secret
  • redirect_uri: Callback URL after authentication
  • scope: OAuth scopes to request (space-separated string)

Returns: None (constructor)

get_auth_url(self, response_mode='query') -> str

Purpose: Generates the authorization URL for redirecting users to Azure AD login page with proper OAuth parameters including CSRF protection

Parameters:

  • response_mode: How Azure should return the response - 'query' (default) returns parameters in query string, 'fragment' returns in URL fragment

Returns: A fully constructed authorization URL string with encoded parameters that can be used to redirect users to Azure AD login

get_token_from_code(self, auth_code: str) -> dict

Purpose: Exchanges an authorization code for access and ID tokens using MSAL library, with automatic scope filtering to remove reserved scopes

Parameters:

  • auth_code: The authorization code received from Azure AD after user authentication (obtained from callback URL)

Returns: Dictionary containing token information on success (keys: access_token, id_token, token_type, expires_in, scope, etc.) or empty dictionary on failure. Check for 'error' key to detect failures.

Attributes

Name Type Description Scope
client_id str Azure AD application client ID used to identify the application instance
tenant_id str Azure AD tenant ID identifying the organization's directory instance
client_secret str Azure AD application client secret for authenticating the application instance
redirect_uri str Callback URL where Azure AD redirects after authentication instance
scope str Space-separated string of OAuth scopes requested for authorization instance
authority str The Azure AD authority URL constructed from tenant_id (e.g., https://login.microsoftonline.com/{tenant_id}) instance
authorize_endpoint str The OAuth 2.0 authorization endpoint URL for initiating user login instance
token_endpoint str The OAuth 2.0 token endpoint URL for exchanging authorization codes for tokens instance

Dependencies

  • msal
  • requests
  • urllib.parse
  • uuid
  • logging
  • json
  • base64
  • traceback

Required Imports

import msal
import urllib.parse
import uuid
import logging

Usage Example

import msal
import urllib.parse
import uuid
import logging

# Configure logging
logger = logging.getLogger(__name__)

# Initialize the Azure SSO handler
azure_sso = AzureSSO(
    client_id='your-client-id-here',
    tenant_id='your-tenant-id-here',
    client_secret='your-client-secret-here',
    redirect_uri='https://yourapp.com/auth/callback',
    scope='openid profile User.Read'
)

# Step 1: Generate authorization URL and redirect user
auth_url = azure_sso.get_auth_url(response_mode='query')
print(f'Redirect user to: {auth_url}')

# Step 2: After user authenticates, Azure redirects back with auth code
# Extract the code from the callback URL query parameters
auth_code = 'code-received-from-azure'

# Step 3: Exchange authorization code for tokens
token_response = azure_sso.get_token_from_code(auth_code)

if token_response:
    access_token = token_response.get('access_token')
    id_token = token_response.get('id_token')
    print(f'Access token obtained: {access_token[:20]}...')
else:
    print('Failed to obtain tokens')

Best Practices

  • Always keep client_secret secure and never expose it in client-side code or version control
  • The redirect_uri must exactly match what is configured in Azure AD application settings
  • Store the 'state' parameter from get_auth_url() in session and validate it when receiving the callback to prevent CSRF attacks
  • Handle token expiration by checking the 'expires_in' field and refreshing tokens as needed
  • Use HTTPS for redirect_uri in production environments
  • The class automatically filters reserved scopes (openid, profile, offline_access) during token exchange as these are handled implicitly by Azure AD
  • Check the returned dictionary from get_token_from_code() for errors before using tokens
  • Ensure a logger instance is configured before using this class as it relies on module-level logger for error tracking
  • The authorization code can only be used once and expires quickly (typically 10 minutes)
  • Consider implementing token caching and refresh token logic for production applications

Similar Components

AI-powered semantic similarity - components with related functionality:

  • class AzureSSO 98.4% similar

    A class that handles Azure Active Directory (Azure AD) Single Sign-On (SSO) authentication using OAuth 2.0 authorization code flow.

    From: /tf/active/vicechatdev/docchat/auth/azure_auth.py
  • class AzureSSO_v1 97.4% similar

    A class that handles Azure Active Directory (Azure AD) Single Sign-On (SSO) authentication using OAuth 2.0 authorization code flow.

    From: /tf/active/vicechatdev/vice_ai/auth/azure_auth.py
  • class SSOCallbackHandler 72.4% similar

    A Tornado RequestHandler that processes OAuth 2.0 callbacks from Azure AD, exchanges authorization codes for access tokens, validates user identity, and sets authentication cookies for SSO integration.

    From: /tf/active/vicechatdev/CDocs/sso_plugin.py
  • function auth_callback 69.8% similar

    OAuth callback handler that processes Azure SSO authentication responses, exchanges authorization codes for access tokens, and establishes user sessions.

    From: /tf/active/vicechatdev/vice_ai/complex_app.py
  • function auth_callback_v1 68.1% similar

    OAuth2 callback handler for Azure SSO authentication that processes authorization codes, exchanges them for access tokens, and establishes user sessions.

    From: /tf/active/vicechatdev/vice_ai/new_app.py
← Back to Browse