🔍 Code Extractor

class AzureSSO_v1

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/vice_ai/auth/azure_auth.py
Lines:
16 - 175
Complexity:
moderate

Purpose

This class provides a complete implementation for Azure AD SSO authentication, including generating authorization URLs, exchanging authorization codes for access tokens, retrieving user information from Microsoft Graph API, and validating tokens. It uses the MSAL (Microsoft Authentication Library) for secure token management and follows OAuth 2.0 best practices including CSRF protection with state parameters.

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"
    
    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,
            '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]
            
            logger.info(f"Requesting token with scopes: {filtered_scopes}")
            
            # Exchange authorization code for tokens
            result = app.acquire_token_by_authorization_code(
                auth_code,
                scopes=filtered_scopes,
                redirect_uri=self.redirect_uri
            )
            
            if "access_token" in result:
                logger.info("Token exchange successful")
                return result
            else:
                logger.error(f"Token exchange failed: {result.get('error_description', 'Unknown error')}")
                raise Exception(f"Token exchange failed: {result.get('error_description', 'Unknown error')}")
                
        except Exception as e:
            logger.error(f"Error in token exchange: {e}")
            raise e
    
    def get_user_info(self, access_token: str) -> dict:
        """
        Get user information from Microsoft Graph API.
        
        Args:
            access_token: Valid access token
            
        Returns:
            dict: User information
        """
        try:
            headers = {
                'Authorization': f'Bearer {access_token}',
                'Content-Type': 'application/json'
            }
            
            response = requests.get(
                'https://graph.microsoft.com/v1.0/me',
                headers=headers,
                timeout=30
            )
            
            if response.status_code == 200:
                return response.json()
            else:
                logger.error(f"Failed to get user info: {response.status_code} - {response.text}")
                return {}
                
        except Exception as e:
            logger.error(f"Error getting user info: {e}")
            return {}
    
    def validate_token(self, access_token: str) -> bool:
        """
        Validate an access token by making a simple API call.
        
        Args:
            access_token: Token to validate
            
        Returns:
            bool: True if token is valid, False otherwise
        """
        try:
            headers = {
                'Authorization': f'Bearer {access_token}',
                'Content-Type': 'application/json'
            }
            
            response = requests.get(
                'https://graph.microsoft.com/v1.0/me',
                headers=headers,
                timeout=10
            )
            
            return response.status_code == 200
            
        except Exception as e:
            logger.error(f"Token validation error: {e}")
            return False

Parameters

Name Type Default Kind
bases - -

Parameter Details

client_id: Azure AD application (app registration) client ID, a unique identifier for your registered application in Azure AD

tenant_id: Azure AD tenant ID, identifies the specific Azure AD directory/organization where the application is registered

client_secret: Azure AD application client secret, a confidential credential used to authenticate the application when exchanging authorization codes for tokens

redirect_uri: The callback URL where Azure AD will redirect users after authentication, must match the redirect URI configured in Azure AD app registration

scope: Space-separated string of OAuth scopes to request (e.g., 'User.Read openid profile'), defines what permissions the application is requesting

Return Value

Instantiation returns an AzureSSO object configured with Azure AD endpoints. Key method returns: get_auth_url() returns a string URL for user redirection; get_token_from_code() returns a dict with 'access_token', 'id_token', 'token_type', 'expires_in', and other token-related fields; get_user_info() returns a dict with user profile data from Microsoft Graph (e.g., 'id', 'displayName', 'mail', 'userPrincipalName'); validate_token() returns a boolean indicating token validity.

Class Interface

Methods

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

Purpose: Initialize the AzureSSO instance with Azure AD configuration and construct authentication 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: Generate the authorization URL for redirecting users to Azure AD login page

Parameters:

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

Returns: String containing the complete authorization URL with encoded parameters including client_id, response_type, redirect_uri, scope, response_mode, and a randomly generated state for CSRF protection

get_token_from_code(self, auth_code: str) -> dict

Purpose: Exchange an authorization code for access and ID tokens using MSAL library

Parameters:

  • auth_code: Authorization code received from Azure AD after user authentication

Returns: Dictionary containing 'access_token', 'id_token', 'token_type', 'expires_in', 'scope', and other token-related fields. Raises Exception if token exchange fails.

get_user_info(self, access_token: str) -> dict

Purpose: Retrieve user profile information from Microsoft Graph API using a valid access token

Parameters:

  • access_token: Valid access token obtained from get_token_from_code()

Returns: Dictionary containing user information fields such as 'id', 'displayName', 'mail', 'userPrincipalName', 'givenName', 'surname', etc. Returns empty dict if request fails.

validate_token(self, access_token: str) -> bool

Purpose: Validate an access token by making a test API call to Microsoft Graph

Parameters:

  • access_token: Access token to validate

Returns: Boolean: True if the token is valid and can successfully authenticate API requests, False otherwise

Attributes

Name Type Description Scope
client_id str Azure AD application client ID instance
tenant_id str Azure AD tenant ID instance
client_secret str Azure AD application client secret (confidential credential) instance
redirect_uri str Callback URL where Azure AD redirects after authentication instance
scope str Space-separated string of OAuth scopes to request instance
authority str Azure AD authority URL constructed as https://login.microsoftonline.com/{tenant_id} instance
authorize_endpoint str OAuth 2.0 authorization endpoint URL for initiating authentication flow instance
token_endpoint str OAuth 2.0 token endpoint URL for exchanging authorization codes for tokens instance

Dependencies

  • requests
  • msal
  • urllib.parse
  • uuid
  • logging

Required Imports

import requests
import urllib.parse
import uuid
import msal
import logging

Usage Example

import msal
import requests
import urllib.parse
import uuid
import logging

# Setup logger
logger = logging.getLogger(__name__)

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

# 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 parameters
auth_code = 'code-from-callback-url'

# Step 3: Exchange authorization code for tokens
try:
    token_response = azure_sso.get_token_from_code(auth_code)
    access_token = token_response['access_token']
    print(f'Access token obtained: {access_token[:20]}...')
    
    # Step 4: Get user information
    user_info = azure_sso.get_user_info(access_token)
    print(f'User: {user_info.get("displayName")}')
    
    # Step 5: Validate token (optional)
    is_valid = azure_sso.validate_token(access_token)
    print(f'Token valid: {is_valid}')
except Exception as e:
    print(f'Authentication failed: {e}')

Best Practices

  • Always store client_secret securely (use environment variables or secret management services, never hardcode)
  • The redirect_uri must exactly match what is configured in Azure AD app registration
  • Call methods in order: get_auth_url() -> redirect user -> get_token_from_code() -> get_user_info() or validate_token()
  • The state parameter in get_auth_url() provides CSRF protection; validate it matches when receiving the callback
  • Reserved scopes (profile, openid, offline_access) are automatically filtered during token exchange
  • Access tokens expire; check 'expires_in' field in token response and implement token refresh logic if needed
  • Handle exceptions from get_token_from_code() as authentication can fail for various reasons (invalid code, expired code, etc.)
  • The class is stateless after initialization; each instance can be reused for multiple authentication flows
  • Use validate_token() to check token validity before making API calls with cached tokens
  • Ensure the logger is properly configured before using this class as it logs important authentication events

Similar Components

AI-powered semantic similarity - components with related functionality:

  • class AzureSSO_v2 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/CDocs/auth/azure_auth.py
  • class AzureSSO 97.3% 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 SSOCallbackHandler 72.0% 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.9% 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 67.5% 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