class AzureSSO_v1
A class that handles Azure Active Directory (Azure AD) Single Sign-On (SSO) authentication using OAuth 2.0 authorization code flow.
/tf/active/vicechatdev/vice_ai/auth/azure_auth.py
16 - 175
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 IDtenant_id: Azure AD tenant IDclient_secret: Azure AD application client secretredirect_uri: Callback URL after authenticationscope: 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
requestsmsalurllib.parseuuidlogging
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
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
class AzureSSO_v2 97.4% similar
-
class AzureSSO 97.3% similar
-
class SSOCallbackHandler 72.0% similar
-
function auth_callback 69.9% similar
-
function auth_callback_v1 67.5% similar