Tech With Htunn
  • Blog Content
  • ๐Ÿค–Artificial Intelligence
    • ๐Ÿง Building an Intelligent Agent with Local LLMs and Azure OpenAI
    • ๐Ÿ“ŠRevolutionizing IoT Monitoring: My Personal Journey with LLM-Powered Observability
  • ๐Ÿ“˜Core Concepts
    • ๐Ÿ”„Understanding DevSecOps
    • โฌ…๏ธShifting Left in DevSecOps
    • ๐Ÿ“ฆUnderstanding Containerization
    • โš™๏ธWhat is Site Reliability Engineering?
    • โฑ๏ธUnderstanding Toil in SRE
    • ๐Ÿ”What is Identity and Access Management?
    • ๐Ÿ“ŠMicrosoft Graph API: An Overview
    • ๐Ÿ”„Understanding Identity Brokers
  • ๐Ÿ”ŽSecurity Testing
    • ๐Ÿ”SAST vs DAST: Understanding the Differences
    • ๐ŸงฉSoftware Composition Analysis (SCA)
    • ๐Ÿ“‹Software Bill of Materials (SBOM)
    • ๐ŸงชDependency Scanning in DevSecOps
    • ๐ŸณContainer Scanning in DevSecOps
  • ๐Ÿ”„CI/CD Pipeline
    • ๐Ÿ”My Journey with Continuous Integration in DevOps
    • ๐Ÿš€My Journey with Continuous Delivery and Deployment in DevOps
  • ๐ŸงฎFundamentals
    • ๐Ÿ’พWhat is Data Engineering?
    • ๐Ÿ”„Understanding DataOps
    • ๐Ÿ‘ทThe Role of a Cloud Architect
    • ๐Ÿ›๏ธCloud Native Architecture
    • ๐Ÿ’ปCloud Native Applications
  • ๐Ÿ›๏ธArchitecture & Patterns
    • ๐Ÿ…Medallion Architecture in Data Engineering
    • ๐Ÿ”„ETL vs ELT Pipeline: Understanding the Differences
  • ๐Ÿ”’Authentication & Authorization
    • ๐Ÿ”‘OAuth 2.0 vs OIDC: Key Differences
    • ๐Ÿ”Understanding PKCE in OAuth 2.0
    • ๐Ÿ”„Service Provider vs Identity Provider Initiated SAML Flows
  • ๐Ÿ“‹Provisioning Standards
    • ๐Ÿ“ŠSCIM in Identity and Access Management
    • ๐Ÿ“กUnderstanding SCIM Streaming
  • ๐Ÿ—๏ธDesign Patterns
    • โšกEvent-Driven Architecture
    • ๐Ÿ”’Web Application Firewalls
  • ๐Ÿ“ŠReliability Metrics
    • ๐Ÿ’ฐError Budgets in SRE
    • ๐Ÿ“SLA vs SLO vs SLI: Understanding the Differences
    • โฑ๏ธMean Time to Recovery (MTTR)
Powered by GitBook
On this page
  • What is Microsoft Graph API?
  • My Recent Challenge: Automating MFA Management
  • Automating MFA Unlinking with Python and Microsoft Graph API
  • How This Script Works
  • Permissions Required
  • What I've Learned
  • Conclusion
  1. Core Concepts

Microsoft Graph API: An Overview

As an Identity and Access Management professional, I've found Microsoft Graph API to be an incredibly powerful tool in my daily work. It's become my go-to solution for automating many Microsoft 365 and Entra ID (formerly Azure AD) tasks. Let me share what I've learned and how you might benefit from it too.

What is Microsoft Graph API?

Microsoft Graph API is a unified gateway to Microsoft's cloud services. Think of it as a single endpoint (https://graph.microsoft.com) that gives you programmatic access to everything from user accounts and groups to emails, calendars, files, and much more across Microsoft 365, Windows, and Enterprise Mobility + Security.

What makes it special is how it connects previously siloed services. Before Graph API, you'd need to learn different APIs for Exchange, SharePoint, Teams, and Azure AD. Now, there's one consistent approach to work with all Microsoft cloud data.

My Recent Challenge: Automating MFA Management

Recently, I faced a challenge at work: we needed to bulk manage MFA methods for users being offboarded or changing roles. Manually unlinking MFA methods through the admin portal was time-consuming and error-prone.

This is where I turned to Microsoft Graph API with Python, and I'd like to share how you can do the same.

Automating MFA Unlinking with Python and Microsoft Graph API

Let me walk you through a practical example I developed. This script allows you to identify and remove MFA methods from user accounts in Microsoft Entra ID:

# mfa_manager.py
import requests
import msal
import json
import logging
from datetime import datetime

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)

class EntraMFAManager:
    def __init__(self, tenant_id, client_id, client_secret):
        self.tenant_id = tenant_id
        self.client_id = client_id
        self.client_secret = client_secret
        self.access_token = None
        self.graph_url = "https://graph.microsoft.com/v1.0"
        
    def authenticate(self):
        """Get access token from Microsoft Entra ID"""
        try:
            # Create MSAL app for authentication
            authority = f"https://login.microsoftonline.com/{self.tenant_id}"
            app = msal.ConfidentialClientApplication(
                client_id=self.client_id,
                client_credential=self.client_secret,
                authority=authority
            )
            
            # Acquire token for Graph API
            result = app.acquire_token_for_client(scopes=["https://graph.microsoft.com/.default"])
            
            if "access_token" in result:
                self.access_token = result["access_token"]
                logger.info("Authentication successful")
                return True
            else:
                logger.error(f"Authentication failed: {result.get('error_description', 'Unknown error')}")
                return False
                
        except Exception as e:
            logger.error(f"Authentication exception: {str(e)}")
            return False
    
    def get_user_mfa_methods(self, user_principal_name):
        """Get a user's MFA methods"""
        if not self.access_token:
            if not self.authenticate():
                return None
        
        headers = {
            "Authorization": f"Bearer {self.access_token}",
            "Content-Type": "application/json"
        }
        
        # Get user's authentication methods
        url = f"{self.graph_url}/users/{user_principal_name}/authentication/methods"
        
        try:
            response = requests.get(url, headers=headers)
            response.raise_for_status()
            
            methods = response.json().get("value", [])
            logger.info(f"Found {len(methods)} authentication methods for user {user_principal_name}")
            return methods
            
        except requests.exceptions.RequestException as e:
            logger.error(f"Error getting MFA methods: {str(e)}")
            if hasattr(e.response, 'text'):
                logger.error(f"Response: {e.response.text}")
            return None
    
    def remove_mfa_method(self, user_principal_name, method_id):
        """Remove a specific MFA method from a user"""
        if not self.access_token:
            if not self.authenticate():
                return False
        
        headers = {
            "Authorization": f"Bearer {self.access_token}",
            "Content-Type": "application/json"
        }
        
        url = f"{self.graph_url}/users/{user_principal_name}/authentication/methods/{method_id}"
        
        try:
            response = requests.delete(url, headers=headers)
            response.raise_for_status()
            logger.info(f"Successfully removed authentication method {method_id} for user {user_principal_name}")
            return True
            
        except requests.exceptions.RequestException as e:
            logger.error(f"Error removing MFA method: {str(e)}")
            if hasattr(e.response, 'text'):
                logger.error(f"Response: {e.response.text}")
            return False

# Example usage
if __name__ == "__main__":
    # Replace with your Entra ID (Azure AD) app registration details
    TENANT_ID = "your-tenant-id"
    CLIENT_ID = "your-client-id"
    CLIENT_SECRET = "your-client-secret"
    
    # Initialize the MFA manager
    mfa_manager = EntraMFAManager(TENANT_ID, CLIENT_ID, CLIENT_SECRET)
    
    # Example: Process a list of users
    users_to_process = ["user1@example.com", "user2@example.com"]
    
    for user in users_to_process:
        print(f"\nProcessing user: {user}")
        
        # Get user's MFA methods
        mfa_methods = mfa_manager.get_user_mfa_methods(user)
        
        if not mfa_methods:
            print(f"No MFA methods found or error occurred for {user}")
            continue
            
        # Print current methods
        print(f"Found {len(mfa_methods)} authentication methods:")
        for method in mfa_methods:
            method_id = method.get("id")
            method_type = method.get("@odata.type", "").replace("#microsoft.graph.", "")
            print(f"- {method_type} (ID: {method_id})")
        
        # Example: Remove phone methods only
        phone_methods = [m for m in mfa_methods if "phone" in m.get("@odata.type", "").lower()]
        
        for method in phone_methods:
            method_id = method.get("id")
            if method_id:
                if mfa_manager.remove_mfa_method(user, method_id):
                    print(f"โœ… Successfully removed phone method {method_id}")
                else:
                    print(f"โŒ Failed to remove phone method {method_id}")

How This Script Works

I built this Python script to solve a real problem we were facing with MFA management. Here's how it works:

  1. Authentication: Uses MSAL (Microsoft Authentication Library) to acquire an access token with the right permissions.

  2. Retrieving MFA Methods: Calls the Graph API endpoint to list all authentication methods for a given user.

  3. Targeted Removal: Can selectively remove specific MFA methods (like phone or authenticator app) based on your needs.

What I love about this approach is that it's flexible enough to handle various scenarios. For example, you could:

  • Bulk unlink MFA methods during offboarding

  • Transfer users from one authentication method to another

  • Generate reports on which authentication methods are being used

  • Automatically remediate security issues with compromised accounts

Permissions Required

To use this script, you'll need an app registration in Entra ID with the following API permissions:

  • UserAuthenticationMethod.ReadWrite.All

These permissions require admin consent, so you'll need to be a Global Administrator or have an admin grant these permissions to your application.

What I've Learned

Working with Microsoft Graph API has taught me several valuable lessons:

  1. It's incredibly versatile - The unified API approach lets me solve problems across Microsoft's entire cloud ecosystem.

  2. Authentication is key - Understanding the OAuth 2.0 flow and proper credential management is essential.

  3. Documentation is your friend - Microsoft's Graph Explorer and API reference have been lifesavers.

  4. Rate limiting matters - Production scripts need to implement backoff strategies and be considerate of API limits.

Conclusion

Microsoft Graph API has transformed how I approach automation in Microsoft's ecosystem. From user management to security controls, it provides a consistent, powerful way to interact with Microsoft services programmatically.

The MFA management example I've shared is just one small application. I encourage you to explore Graph API for your own unique use cases - whether it's reporting, automation, or integration with other systems.

If you're just getting started, I highly recommend checking out Microsoft's Graph Explorer to interactively test API calls before writing code. It's been an invaluable tool in my journey.

PreviousWhat is Identity and Access Management?NextUnderstanding Identity Brokers

Last updated 1 day ago

๐Ÿ“˜
๐Ÿ“Š