graph_signins_abuseip.py python script
Overview
Microsoft Graph Sign-in Audit & AbuseIPDB Threat Intel goes one step further than the plain sign-in audit: it pulls the sign-in logs of an account from Microsoft Graph (/auditLogs/signIns) and enriches every unique source IP with real-time reputation data from the AbuseIPDB API v2. Results land in a CSV file and an interactive HTML dashboard.
Key features
- No app registration needed: public Azure CLI client ID with interactive PKCE login and forced account picker.
- AbuseIPDB enrichment: abuse confidence score, total reports, ISP and attack categories (Brute-Force, SSH, Web App Attack…).
- In-memory IP cache & private IP filter: each IP is checked once per run and RFC 1918 / loopback addresses never hit the API.
- API key rotation pool: moves to the next AbuseIPDB key automatically on HTTP 429.
- Error code translation for common Entra ID failures (
50126,50053,53003…). - Quiet or verbose console (
-v) and a custom time window with-d. - HTML dashboard with live search and filters: All / Success / Failure / Malicious / Suspicious / Clean.
- Corporate proxy ready: works behind SSL/TLS inspection.
How it works
- Authentication with MSAL and the delegated scope
AuditLog.Read.All(browser login + MFA). - OData query built from a UTC cutoff and the target user.
- Retrieval of every page of
https://graph.microsoft.com/v1.0/auditLogs/signIns. - Threat intel: private IPs are tagged as internal; new public IPs are sent to the AbuseIPDB
/checkendpoint and cached; keys rotate on rate limits. - Reports: console summary,
signins_intel_<user>_<days>d_<timestamp>.csvand the matching.htmldashboard.
Requirements
- Python 3.8+ (standard Python or Anaconda).
- Libraries:
msal,requests,urllib3. - Microsoft Entra ID P1 or P2 (or Microsoft 365 E3/E5).
- Delegated permission:
AuditLog.Read.All. - One or more free or paid API keys from AbuseIPDB.
The analyst account must have one of these roles:
- Security Reader (recommended for SOC analysts)
- Reports Reader
- Global Reader
- Security Administrator
- Global Administrator
Installation
bash
pip install msal requests urllib3Configuration
Open graph_signins_abuseip.py and paste your keys in the ABUSEIPDB_API_KEYS list near the top of the file:
python
ABUSEIPDB_API_KEYS = [
"YOUR_ABUSEIPDB_KEY_1",
"YOUR_ABUSEIPDB_KEY_2"
]Usage
bash
# Default: last 15 days, quiet progress mode
python graph_signins_abuseip.py -u user@company.com
# Custom time window
python graph_signins_abuseip.py -u user@company.com -d 30
# Verbose, full metadata per event
python graph_signins_abuseip.py -u user@company.com -d 30 -v| Argument | Default | Required | Description |
|---|---|---|---|
-u, --user | — | Yes | Target UserPrincipalName or email. |
-d, --days | 15 | No | Number of past days to inspect. |
-v, --verbose | False | No | Event-by-event output in the terminal. |
Outputs
signins_intel_<user>_<days>d_<timestamp>.csv— every sign-in plus its threat intelligence rating.signins_intel_<user>_<days>d_<timestamp>.html— dashboard with metric cards, search and reputation filters.
Corporate proxy & SSL
Behind a corporate proxy doing SSL/TLS inspection, Python HTTPS calls can fail with CERTIFICATE_VERIFY_FAILED. The script handles it by silencing urllib3 warnings and using verify=False on outbound requests:
python
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
requests.get(url, headers=headers, verify=False)