Skip to content

azapptoolkit

Native desktop app for managing Microsoft Entra ID applications — no PowerShell modules, no scripting, no service principal of its own.

License: MIT OR Apache-2.0 Platform Rust Status: pre-release

Let's face it: managing Azure app registration and service principal permissions is painful. Exchange Graph API application permissions default to org-wide access across every single mailbox, and scoping them down is needlessly hard. SharePoint is no better — you grant Sites.FullControl.All, scope to Sites.Selected, then revoke Sites.FullControl.All. We built azapptoolkit to make this work the way it should have from the start.

azapptoolkit signs in to Entra ID directly from your workstation and talks to Microsoft Graph with your delegated permissions. The only thing you install on the machine is the installer itself — no Az PowerShell, no Microsoft Graph PowerShell SDK, no Azure CLI, and no toolkit-owned service principal storing tokens you cannot audit.

🔎 Try the live demo → The full UI with sample data, right in your browser — no install, no sign-in. (Read-only: live Graph queries, mutations, and exports are disabled in the hosted demo.)

Table of contents

Features

App registrations

  • Browse every app registration in the tenant in a virtualized list with debounced search.
  • Create, edit, delete app registrations — sign-in audience, description, owners, and required permissions.
  • Authentication settings — redirect URIs per platform, public-client flows, and implicit-grant toggles, mirroring the portal's Authentication blade.
  • Expose an API — manage the Application ID URI, the OAuth2 scopes an app exposes (add / edit / disable-then-delete), and its pre-authorized client applications.
  • Per-app sign-in activity and a tenant-wide inventory export (CSV / JSON) of every app registration.

Credentials & secrets

  • Rotate credentials — add or remove client secrets, upload certificate credentials (drag-drop PEM or paste base64), and bulk-sweep every expired secret across the tenant in one pass.
  • Credential-expiry dashboard — a tenant-wide view of every app registration's client secrets and certificates sorted soonest-to-expire, with status filters, an expiring-soon banner, CSV export, and a one-click jump into each app's credentials to rotate.
  • Federated identity credentials — manage workload identity federation (GitHub Actions, Kubernetes, …) per app registration: list, add (with issuer/subject templates), and remove the OIDC trust relationships that let an external workload authenticate as the app with no client secret.
  • Key Vault integration — store a newly minted client secret directly into any Azure Key Vault you have RBAC on, and browse existing secret values on demand.

Permissions, consent & scoping

  • API permissions and admin consent — pick delegated and application permissions from a bundled catalog (with Graph fallback for unknown resources) and grant admin consent in one click, with a diff view before writing.
  • SharePoint site access (Sites.Selected) — list, grant, and revoke a site's per-app permissions, and convert an org-wide Sites.* grant to site-scoped access.
  • Exchange mailbox scoping (RBAC for Applications) — restrict an app's mailbox access to specific groups via Exchange Online's RBAC for Applications (the supported replacement for the deprecated Application Access Policies), and migrate an existing policy to RBAC in one click with a dry-run preview.
  • Works for foreign-tenant apps too — an enterprise application whose registration lives in another tenant (a consented multi-tenant/OIDC app) has no local manifest, but its granted permissions can still be scoped: the Enterprise Application detail's Permissions tab carries the same Grant-access wizard, and an inline callout flags held org-wide mail/SharePoint access with a one-click path into scoping.

Enterprise apps, service principals & managed identities

  • Enterprise applications — inspect any service principal (credentials, exposed roles & scopes, owners, SAML signing-cert health), see who has access, grant/revoke access for users and groups, view SCIM provisioning status, and toggle My Apps visibility.
  • Group memberships — list, add, and remove a service principal's security-group memberships (the access model for group-gated APIs such as Power BI / Fabric admin settings).
  • SAML single sign-on — a guided wizard to configure SAML-based SSO and customize the attribute & claim mapping (claims-mapping policies).
  • Managed identities — discover system- and user-assigned identities, grant Graph application permissions, see over-privilege at a glance, and view their Azure RBAC role assignments across subscriptions (via Azure Resource Manager).

Security & auditing

  • Security audit — risk-scored dashboard of every app registration with per-rule findings (high-risk app/delegated permissions, ownerless/single-owner apps, unused apps via sign-in activity, expiring credentials, and more), one-click fixes for safely remediable findings (remove expired credentials, scope mailbox/SharePoint access, remove redundant permissions), scope-aware risk (a mail permission confined via Exchange RBAC scores below an org-wide one), facet filters, CSV/JSON/HTML export, adaptive throttling on 429s, and cancellable scans. Also covers principals without a local app registration — foreign-tenant enterprise apps and managed identities holding Graph application grants — with fixes that route to the SP-native scoping paths.
  • Consent & application-permission audits — tenant-wide views of every delegated (OAuth2) consent grant and every application permission apps hold on Microsoft Graph / Exchange / SharePoint, with high-risk highlighting, filters, CSV export, and a jump to the granting app.
  • Observed Graph activity — compare an app's granted permissions with the Graph calls it actually makes (MicrosoftGraphActivityLogs via Azure Monitor Log Analytics) to spot grants that nothing uses.
  • Conditional Access visibility — see which Conditional Access policies target an application (on-demand, via Policy.Read.All).
  • Activity log — recent directory activity / change log for an app, from the Entra audit logs (on-demand, via AuditLog.Read.All).

Access testing & resource lookups

  • Permission tester — answer "can this identity reach that resource": pick any service principal (app registration, enterprise app, or managed identity) and test whether it actually reaches a specific Exchange mailbox or SharePoint site, exercising the same live primitives the grant flows use.
  • Resource Access reverse lookups — pick a resource and see which applications can reach it: a tenant-wide site sweep indexes every per-site Sites.Selected grant (filter by app for "which sites can this app reach?" — the lookup Graph doesn't offer), and a mailbox check probes every mail-capable app against one mailbox via Exchange's authoritative authorization test. Coverage is reported honestly — a partial scan says so.

App experience & operator tools

  • Command bar & home dashboard — the top-bar search bar jumps to any app or GUID and runs any tool (Cmd/Ctrl-K focuses it); a sign-in landing page summarizing credential health and security posture. Saved filter views pin your favorite facet+search combinations.
  • Readiness checklist — a live page showing which directory / Azure / Exchange roles and delegated consents the signed-in operator holds versus what each feature needs, with in-context "requires role" labels and actionable 403 hints throughout the app.
  • Cache diagnostics — inspect hit/miss counters per cache, clear individual caches, or disable caching entirely for debugging.

Quick start

  1. Download the latest Windows installer from the Releases page. Most users want the NSIS -setup.exe — see Install for when to choose the MSI instead.
  2. Create a single-tenant app registration in your directory. On first launch azapptoolkit prompts for its Application (client) ID and Tenant ID and saves them locally (or set AZAPPTOOLKIT_CLIENT_ID + AZAPPTOOLKIT_TENANT_ID as user environment variables instead). See First-run configuration for the exact permissions to consent.
  3. Launch azapptoolkit. The first run opens your browser for the Entra sign-in once; after that, the OS keyring stores your refresh token and the app reconnects silently.

Install

Download the latest package for your platform from the Releases page. Builds are published for Windows, macOS, and Linux.

Windows

Two formats are published, for two different audiences. Pick one and stick with it — installing one type and later updating with the other leaves two conflicting entries in Windows (see Updates):

  • azapptoolkit_<version>_x64-setup.exe — lightweight NSIS installer. Per-user install, no admin rights, and updates in place (on your confirmation — see Updates). The right choice for individual users and testers — pick this one unless you specifically need the MSI.
  • azapptoolkit_<version>_x64_en-US.msi — classic Windows Installer for enterprise rollout via SCCM, Intune, or Group Policy. The in-app auto-updater does not manage MSI installs (it ships only the NSIS payload); deploy new versions through your management tooling and disable auto-update on these installs (see Opting out).

The Edge WebView2 runtime is the only external dependency, and it ships with current Windows 10/11 — so on those machines installation and first launch need no internet. On an older machine that lacks it, the installer downloads WebView2 from Microsoft during setup. After install, the only runtime azapptoolkit depends on is Windows itself plus that WebView2 runtime.

macOS (Apple Silicon)

Download azapptoolkit_<version>_aarch64.dmg, open it, and drag the app to Applications. The builds are not yet notarized by Apple, so on first launch Gatekeeper blocks the app ("can't be opened because Apple cannot check it for malicious software"). Clear it once, either way:

  • Right-click → Open in Finder, then confirm Open in the dialog; or
  • run xattr -dr com.apple.quarantine "/Applications/azapptoolkit.app".

After that it launches normally and updates in place like the Windows NSIS build. Apple Silicon (M-series) only for now; Intel builds aren't published yet.

Linux (x86_64)

Two formats:

  • azapptoolkit_<version>_amd64.AppImage — portable, runs on most distributions; chmod +x it and run. This is the format the in-app auto-updater manages.
  • azapptoolkit_<version>_amd64.deb — for Debian/Ubuntu and derivatives (sudo apt install ./azapptoolkit_<version>_amd64.deb).

Needs a WebKitGTK runtime (libwebkit2gtk-4.1), present on most modern desktops and pulled in automatically by the .deb.

Updates

The in-app updater manages the NSIS (-setup.exe) install on Windows, the .app on macOS, and the .AppImage on Linux (the MSI and .deb are not auto-updated — manage those through your packaging tooling). On launch, azapptoolkit checks the configured release endpoint for a newer signed build for your platform.

Updating is always your choice — nothing installs in the background. If an update is available you get a notification; opening it shows the new version's changelog, and the update downloads and installs only when you select Update & restart. The app then relaunches into the new version. You can also check on demand from the account menu ("Check for updates"), which shows the same changelog screen — or tells you you're already current.

Update payloads are verified against a public key baked into the build at release time — a payload that fails signature verification is rejected before any bytes touch disk. A failed update check or install never blocks the app; it is logged (see Logs) and retried on a later launch.

MSI installs: the updater only ever ships the NSIS payload, so letting it run against an MSI install creates a second, conflicting installation. If you deployed the .msi, disable auto-update (see Opting out) and push new versions through your management tooling instead.

Opting out

Update checking is on by default (installing always needs your confirmation). To stop the checks entirely, there are two ways:

  • Environment variable — set AZAPPTOOLKIT_AUTO_UPDATE=0 (also accepts false / off / no) in the user or machine environment before launching the app. Useful for CI runners and for MDM/Group Policy deployments that wrap the launcher.

  • Settings file — drop a JSON file at the platform's app-data folder:

    • Windows: %APPDATA%\azapptoolkit\settings.json
    • macOS: ~/Library/Application Support/azapptoolkit/settings.json
    • Linux: ~/.local/share/azapptoolkit/settings.json
    { "auto_update": false }

The env var takes precedence over the settings file when both are present. With auto-update disabled the app makes no network calls to the updater endpoint at any point in the session.

Requirements

  • Windows 10 or newer (primary target), macOS on Apple Silicon, or a modern x86_64 Linux desktop with WebKitGTK — installers for all three are on the Releases page.
  • A Microsoft Entra ID account with at least the Application Administrator role, or the equivalent delegated consent for the permissions listed below.
  • Outbound network access (at runtime) to login.microsoftonline.com, graph.microsoft.com, and — only when you use those features — *.vault.azure.net for Key Vault, outlook.office365.com for Exchange mailbox scoping, management.azure.com for a managed identity's Azure RBAC roles, and api.loganalytics.azure.com for observed Graph activity (usage analysis).

First-run configuration

azapptoolkit talks to Microsoft Graph as a public client scoped to one Entra tenant. It needs a single-tenant app registration in your own directory to drive the PKCE sign-in; sign-in attempts from accounts outside that tenant are rejected at the Entra endpoint. Your tenant's Entra admin creates the registration once and every workstation reuses the same client id and tenant id.

  1. In the Azure portal, create a new App Registration:
    • Supported account types: Accounts in this organizational directory only (Single tenant).
    • Redirect URI: Public client / nativehttp://127.0.0.1. (The app binds a loopback listener on 127.0.0.1 with an OS-assigned port; Entra matches the loopback host and ignores the port.)
  2. On the Authentication blade, set Allow public client flows to Yes.
  3. Under API permissions → Add a permission, add the delegated permissions from the Permissions table below, then have an admin click Grant admin consent for the tenant.
  4. Copy the Application (client) ID and Tenant ID and hand them to azapptoolkit — see Providing the client and tenant IDs.

On first launch, azapptoolkit opens a loopback listener, pops your default browser for the Entra sign-in, and persists the resulting refresh token in the OS keyring (Windows Credential Manager / macOS Keychain / libsecret). Access tokens are refreshed lazily and never written to disk.

Permissions

Only Directory.Read.All is requested at sign-in; every other scope is consented incrementally the first time you use the feature that needs it. So a browse-only session never carries write or premium scopes, and a tenant that hasn't consented to an optional permission can still sign in and use everything else — that feature just shows an "unavailable" notice with a one-click Grant consent prompt.

Resource Permission What it unlocks Required?
Graph Directory.Read.All Every read in the app — app registrations, enterprise apps, managed identities, owners, app-role & OAuth2 grants, org info, user/group search (the only read-only Graph scope that can read /oauth2PermissionGrants) Required — at sign-in
Graph Application.ReadWrite.All Create / edit / delete app registrations & service principals; manage credentials and owners Required for edits — on first write
Graph AppRoleAssignment.ReadWrite.All Grant / revoke application permissions and user/group access assignments Required for edits — on first write
Graph DelegatedPermissionGrant.ReadWrite.All Grant / revoke delegated (OAuth2) permission grants Required for edits — on first write
Graph AuditLog.Read.All Activity tab (directory change log) and unused-app detection in the security audit (the sign-in report also needs Entra ID P1/P2) Optional
Graph Policy.Read.All Conditional Access tab — which CA policies target an app (an Entra ID P1/P2 feature) Optional
Graph Policy.ReadWrite.ApplicationConfiguration Claims-mapping policies — SAML attribute & claim customization in the SSO wizard Optional
Graph GroupMember.ReadWrite.All Group memberships — add/remove a service principal in security groups (the access model for group-gated APIs like Power BI / Fabric) Optional
Graph Synchronization.Read.All SCIM provisioning job status on enterprise apps (needs Entra ID P1/P2) Optional
Graph Sites.FullControl.All SharePoint Sites.Selected — list / grant / revoke a site's per-app permissions (SharePoint site access section on the Permissions tab) Optional
Office 365 Exchange Online Exchange.Manage Exchange mailbox scoping (RBAC for Applications) — confine an app's mailbox access to specific groups Optional
Azure Key Vault user_impersonation Store a new client secret into, or browse secrets from, an Azure Key Vault Optional
Azure Service Management user_impersonation View a managed identity's Azure RBAC role assignments across subscriptions Optional
Log Analytics API Data.Read Observed Graph activity — granted-vs-used analysis from MicrosoftGraphActivityLogs (also needs Entra diagnostic settings exporting to a Log Analytics workspace, and Log Analytics Reader on it) Optional

Everything marked Optional needs admin consent but is acquired only on first use, never at sign-in. The Key Vault, Azure Service Management, and Log Analytics tokens are requested at runtime as …/.default (whatever delegated permission you've consented to for that resource) — you still add user_impersonation / Data.Read under API permissions.

The sign-in flow also requests the OpenID Connect protocol scopes openid, profile, and offline_access (for the ID token and a refresh token). These are built-in v2.0 endpoint scopes, not resource permissions — you do not need to add them under API permissions, and there's no corresponding configuration on the Enterprise Application side. The admin-consent click on the Graph permissions above covers them automatically.

A few features also need the signed-in user to hold a role — their own rights, separate from the app-registration permissions above:

  • Key VaultKey Vault Secrets User or Key Vault Secrets Officer RBAC on the target vaults (the vaults must be in RBAC permission mode).
  • Exchange mailbox scoping — an Exchange Online Role Management RBAC role (held by the Organization Management role group; the Entra Exchange Administrator role grants it, but only once active — not merely PIM-eligible — and after it propagates to Exchange). A not-yet-effective role shows as a "forbidden (403)" banner or a Scope column stuck on Unknown; see the troubleshooting note in docs/operator-rbac/OPERATOR-ROLES.md.
  • Managed-identity Azure RBAC — at least one readable Azure subscription to view role assignments; assigning a role to a managed identity additionally needs a higher Azure role such as User Access Administrator.

Providing the client and tenant IDs

From the registration's Overview page, copy the Application (client) ID. From Azure → Microsoft Entra ID → Overview, copy the Tenant ID. Then give them to azapptoolkit one of three ways:

  • In-app (simplest — recommended for a downloaded release). Launch azapptoolkit. On first run, before any sign-in, it shows a Configure your tenant screen: paste the two IDs and select Save & restart. They're stored in your per-user settings.json (see Logs for the folder) and reused on every later launch — no environment variables needed.

  • Environment variables. Set both before launching (useful for MDM / automation; these override the saved values):

    [Environment]::SetEnvironmentVariable('AZAPPTOOLKIT_CLIENT_ID','<client-guid>','User')
    [Environment]::SetEnvironmentVariable('AZAPPTOOLKIT_TENANT_ID','<tenant-guid>','User')
  • Baked into a team build. If you're an admin packaging a build for a whole team, copy .env.example to .env at the repo root, fill in the two GUIDs, and run cargo tauri build. The values are baked into the installer at compile time (see apps/desktop/src-tauri/build.rs), so recipients install and launch with no per-workstation configuration (the setup screen is skipped). See docs/DEVELOPMENT.md.

The resolution order is environment variable → in-app settings.json → baked-in value → unset; while unset, sign-in can't succeed and the configuration screen is shown.

Sovereign / national clouds. The app targets the commercial cloud by default. To use a tenant in US Gov (GCC High), US Gov DoD, or Azure China (21Vianet), set AZAPPTOOLKIT_CLOUD to usgov, usgovdod, or china respectively (unset or commercial for the global cloud). This switches the Entra login, Microsoft Graph, Exchange Online, Key Vault, and ARM endpoints to that cloud's hosts. The app registration must be created in the matching national-cloud admin center.

Logs

Rolling daily log files are written to the platform's app-data folder:

  • Windows: %APPDATA%\azapptoolkit\logs\azapptoolkit.log*
  • macOS: ~/Library/Application Support/azapptoolkit/logs/
  • Linux: ~/.local/share/azapptoolkit/logs/

Increase verbosity with RUST_LOG=debug (or the narrower EnvFilter syntax — for example azapptoolkit_graph=trace).

Data and privacy

  • No secret value is ever written to disk by azapptoolkit. Newly created client secrets are shown once, copyable to clipboard, and optionally pushed to Key Vault over TLS.
  • Refresh tokens live in the OS keyring only; access tokens stay in memory and are zeroized on drop.
  • Telemetry: none. azapptoolkit makes no network calls beyond Entra ID, Microsoft Graph, Azure Key Vault, Exchange Online, Azure Resource Manager, Azure Monitor Log Analytics, and the configured updater endpoint (the sovereign-cloud equivalents of those hosts when AZAPPTOOLKIT_CLOUD is set).

Security

If you find a vulnerability, please do not open a public issue. Instead, email the maintainer or use GitHub's private security advisory flow so a fix can ship before the issue is disclosed.

Defensive choices worth knowing:

  • OAuth uses PKCE plus a state CSRF parameter, on a loopback redirect bound to 127.0.0.1.
  • Bearer tokens are scoped to the resource (Graph / Key Vault / Exchange) and never sent to a nextLink that points at a different origin.
  • Write scopes are consented incrementally — a session that only reads never holds tokens that can mutate.
  • cargo-audit runs on every PR and on a weekly schedule.

Built with

Contributing

See CONTRIBUTING.md for how to get set up, the working agreements, and the pre-PR checklist; build, testing, packaging, and release-signing details are in docs/DEVELOPMENT.md. Issues and pull requests are welcome — please open an issue first to discuss non-trivial changes. By participating you agree to the Code of Conduct.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

© TiredITHumans

About

Native desktop app for managing/auditing Azure App Registrations, Enterprise Applications, and Managed-Identities.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages