Standalone directory integration service providing MicroSIP JSON and Yealink XML phone directory feeds from Azure AD employee data.
- Azure AD sync – fetch employees directly from Microsoft Graph (same client-credentials flow as Simple-Org-Chart)
- MicroSIP JSON directory – softphone-compatible contact feed
- Yealink XML phonebook – remote phonebook for Yealink desk phones (T31P, T33G, T46U, etc.)
- Custom contacts – append extra contacts not in Azure AD via the configure page
- Number swaps – find/replace rules applied to phone numbers before export (e.g. strip country prefix, remap extensions)
- Azure AD SSO – optional single sign-on via MSAL with password fallback
- Docker-ready – multi-stage Dockerfile with Gunicorn
cp .env.template .env # edit APP_PASSWORD & SECRET_KEY
docker compose up -d --buildThe app will be available at http://localhost:5000.
python -m venv .venv
.venv/Scripts/activate # Windows
# source .venv/bin/activate # macOS/Linux
pip install -r requirements.txt
cp .env.template .env
python -m simple_contacts.app_main| Variable | Default | Description |
|---|---|---|
SECRET_KEY |
change-me-in-production |
Flask session secret |
APP_PASSWORD |
admin |
Login password (fallback when SSO is off) |
PORT |
5000 |
Server port |
GUNICORN_WORKERS |
2 |
Gunicorn worker count |
AZURE_TENANT_ID |
(none) | Azure AD tenant ID (optional – Graph sync) |
AZURE_CLIENT_ID |
(none) | App registration client ID (optional) |
AZURE_CLIENT_SECRET |
(none) | App registration client secret (optional) |
GRAPH_API_ENDPOINT |
https://graph.microsoft.com/v1.0 |
Graph API base URL (optional) |
SSO_TENANT_ID |
(none) | Azure AD tenant for SSO (optional) |
SSO_CLIENT_ID |
(none) | SSO app registration client ID (optional) |
SSO_CLIENT_SECRET |
(none) | SSO app registration client secret (optional) |
SSO_REDIRECT_PATH |
/auth/callback |
SSO redirect URI path (optional) |
MAX_CUSTOM_CONTACTS |
200 |
Maximum custom directory contacts |
- Create an App Registration in Azure Portal.
- Grant Application permission
User.Read.Alland admin-consent it. - Create a client secret.
- Set
AZURE_TENANT_ID,AZURE_CLIENT_ID, andAZURE_CLIENT_SECRETin.env. - Use the Sync Now button on the configure page to pull employees.
- Create a separate App Registration for SSO.
- Add a Web redirect URI:
https://your-domain/auth/callback. - Grant Delegated permission
User.Read. - Create a client secret.
- Set
SSO_TENANT_ID,SSO_CLIENT_ID, andSSO_CLIENT_SECRETin.env. - When configured, the password login form is auto-disabled.
| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/health |
No | Health check |
GET/POST |
/api/settings |
Yes | Read / update settings |
GET/DELETE |
/api/employees |
Yes | Read / clear synced employees |
GET |
/api/azure/status |
Yes | Check if Azure AD credentials are set |
POST |
/api/azure/sync |
Yes | Fetch employees from Microsoft Graph |
GET |
/directory/<name>.json |
No | MicroSIP JSON feed |
GET |
/directory/<name>.xml |
No | Yealink XML feed |
pip install pytest
pytestSimple-Contacts/
├── simple_contacts/ # Python package
│ ├── app_main.py # Flask application
│ ├── auth.py # Authentication (SSO + password)
│ ├── config.py # Paths & configuration
│ ├── data_update.py # Azure AD sync helpers
│ ├── exports.py # MicroSIP / Yealink builders
│ ├── msgraph.py # Microsoft Graph API client
│ ├── scheduler.py # Background sync scheduler
│ ├── settings.py # Settings load/save
│ └── utils/
├── static/ # Front-end assets
│ ├── configure.css
│ ├── configure.js
│ ├── i18n.js
│ └── locales/en-US.json
├── templates/ # Jinja2 templates
│ ├── configure.html
│ └── login.html
├── tests/ # Pytest suite
├── deploy/ # Gunicorn config
├── data/ # Runtime data (gitignored)
├── Dockerfile
├── docker-compose.yml
├── docker-compose-dev.yml
├── requirements.txt
└── pyproject.toml
MIT