Security & data handling
What Tenant Hawk can see, what it stores, and how you shut it off
You are being asked to consent an app into your tenant, so this page skips the marketing. Everything below is verifiable: the permission list matches what Microsoft shows you on the admin consent screen, and after connecting you can audit it any time under Entra ID → Enterprise applications → Tenant Hawk → Permissions.
The access model
Application permissions, admin consent, read-only
Access is granted through Microsoft's standard admin-consent flow — the same one you use for any multi-tenant app. Every scope we request is a read-only (.Read) permission. There is no write permission in the manifest, so Tenant Hawk cannot change users, licenses, policies, or settings even if it wanted to.
No credentials touch our systems
Consent happens on login.microsoftonline.com, so no one ever types a Microsoft password into Tenant Hawk. Scans authenticate with short-lived app-only tokens acquired from Microsoft at runtime via the client-credentials flow. No access tokens, refresh tokens, or secrets for your tenant are written to our database.
Findings, not content
Scan results store what you see in the dashboard: check outcomes, severity, affected object names, and license counts. We do not store email bodies, files, or Teams message content — the checks that touch those surfaces read timestamps and settings only, as documented per permission below.
Deletion is real deletion
Disconnecting a tenant deletes its connection row, and every scan, finding, and configuration snapshot cascades with it at the database level. Deleting your account removes everything.
Every permission we request, and why
15 Microsoft Graph application permissions power all 70 checks. This table is generated from the same registry the scan engine runs on, so it cannot drift from what the app actually uses. If a future check needs a new scope, it will appear here — and on your consent screen — before it ships.
Application.Read.All7 checksGrants: App registrations and enterprise apps (service principals), including credential metadata.
We use it for: Finding client secrets and certificates about to expire, ownerless or unused apps, and enterprise apps holding more permissions than they use. We read credential expiry dates — never the secret values themselves, which Microsoft does not expose.
Powers: Expiring app secrets and certs · Expiring enterprise app secrets · Over-permissioned enterprise apps · Unused enterprise apps · Ownerless app registrations · Ownerless enterprise apps · Multi-tenant apps with credentials
AuditLog.Read.All1 checkGrants: Entra sign-in and audit log entries.
We use it for: Sign-in activity for enterprise apps, so unused apps are flagged from real usage rather than guesswork.
Powers: Unused enterprise apps
Channel.ReadBasic.All1 checkGrants: Teams channel names and metadata.
We use it for: Detecting private channels whose owners have all left or been disabled.
Powers: Ownerless private channels
ChannelMessage.Read.All2 checksGrants: Messages in Teams channels.
We use it for: Channel activity only: during a deep scan we request the single most recent message per channel and keep its timestamp to detect inactive and never-used channels. Message content is not stored and does not appear in any finding.
Powers: Inactive Teams channels · Empty Teams channels
Device.Read.All3 checksGrants: Entra device records.
We use it for: Comparing Entra device records against Intune enrollment to catch drift, and flagging devices with stale sign-ins.
Powers: Entra devices not in Intune · Intune enrollments without Entra device · Stale Entra device sign-ins
DeviceManagementManagedDevices.Read.All5 checksGrants: Intune managed device inventory.
We use it for: Stale device sync, compliance state, personally owned enrollments, and the Entra-vs-Intune reconciliation above.
Powers: Stale Intune device sync · Non-compliant Intune devices · Entra devices not in Intune · Intune enrollments without Entra device · Personally owned Intune enrollments
Directory.Read.All10 checksGrants: Directory objects: groups, role assignments, organizational relationships.
We use it for: Privileged role assignments, empty and ownerless groups, and Teams whose owners are gone.
Powers: Privileged role assignments · Disabled users outside offboarding groups · Empty groups · Ownerless groups · Ownerless Microsoft Teams · Empty Microsoft Teams · Groups with risky naming patterns · Over-permissioned enterprise apps · Apps with Global Administrator role · Privileged users without MFA
Mail.ReadBasic.All3 checksGrants: Mailbox metadata — not message bodies or attachments.
We use it for: Mailbox settings only: external forwarding addresses and stale automatic replies. We never read, store, or index email content.
Powers: External mailbox forwarding · Mailbox forwarding enabled · Stale mailbox auto-replies
Organization.Read.All9 checksGrants: Tenant subscription and SKU information.
We use it for: License seat counts against assignments — the source for dollar figures on unused, disabled-user, and expiring licenses.
Powers: Licenses on disabled accounts · Unused license seats · Subscription status warnings · Unused Copilot license seats · Licensed inactive Copilot users · Copilot on disabled accounts · Low Copilot adoption · Copilot users without MFA · Licensed inactive mailboxes
Policy.Read.All2 checksGrants: Conditional Access and authentication policies.
We use it for: Conditional Access coverage gaps (including policies stuck in report-only) and legacy authentication exposure.
Powers: Conditional Access coverage · Legacy authentication
Reports.Read.All28 checksGrants: Microsoft 365 usage reports (aggregated activity per user, site, mailbox, and team).
We use it for: The activity backbone for most hygiene checks: MFA registration, inactive users, stale SharePoint sites, mailbox and Teams activity. These are the same reports in your admin center — pre-aggregated by Microsoft, no message or file content.
Powers: MFA registration gaps · Sites with external sharing · Stale SharePoint sites · High-storage SharePoint sites · Empty SharePoint sites · Ownerless SharePoint sites · Sites with inactive files · Stale Microsoft Teams · Teams with no active channels · Guest-heavy Teams · Licensed inactive Copilot users · Low Copilot adoption · Copilot Chat-only users · Copilot users without MFA · Copilot Chat-only usage pattern · Inactive mailboxes · High-storage mailboxes · Licensed inactive mailboxes · Privileged users without MFA · SharePoint sites with unused pages · Stale SharePoint site pages · SharePoint anonymous links · Stale OneDrive accounts · High-storage OneDrive accounts · High-storage stale team sites · Shared mailboxes without delegates · Inactive shared mailboxes · Unused resource mailboxes
RoleManagement.Read.All1 checkGrants: Role management and PIM configuration.
We use it for: Detecting standing (always-on) privileged access that should be eligible-only.
Powers: Standing privileged role access
SharePointTenantSettings.Read.All1 checkGrants: Tenant-level SharePoint settings.
We use it for: The org-wide external sharing posture check.
Powers: Org-wide SharePoint sharing policy
Team.ReadBasic.All6 checksGrants: Team names and basic metadata.
We use it for: Team-level checks: disabled owners, outdated or unverified Teams apps.
Powers: Inactive Teams channels · Empty Teams channels · Ownerless private channels · Teams with disabled owners · Outdated Teams apps · Unverified Teams apps
User.Read.All15 checksGrants: User profiles, account status, license assignments, and sign-in activity timestamps.
We use it for: The core of licensing and lifecycle checks: disabled accounts still holding licenses, inactive users (interactive and non-interactive sign-ins both considered), and guest sprawl.
Powers: Guest account sprawl · Licenses on disabled accounts · Inactive user accounts · Disabled users outside offboarding groups · Licensed inactive Copilot users · Copilot on disabled accounts · Low Copilot adoption · Copilot users without MFA · External mailbox forwarding · Mailbox forwarding enabled · Licensed inactive mailboxes · Stale guest accounts · Guest invitation spike · Users without a manager · Teams with disabled owners
What we store, and for how long
A scan produces findings — check outcomes with severity, the display names of affected objects (a user, group, site, or app name), and aggregate numbers like seat counts and estimated monthly waste. That is what we retain, because it is what renders your dashboard, trends, and reports.
We keep scan history while the tenant stays connected so you can track your score over time. Disconnect the tenant and that history is deleted — not archived, deleted, enforced by cascading foreign keys in our schema. Account deletion removes your user record and everything attached to it.
Tenant Hawk runs on Amazon Web Services. All traffic is encrypted in transit with TLS, and the database is encrypted at rest. Payments are handled by Stripe; we never see card numbers. The full subprocessor list is in the privacy policy.
Revoking access
Two independent kill switches, in either order:
- 1
In Tenant Hawk
Settings → Connections → Disconnect. This deletes the connection and all scan history for that tenant from our database immediately.
- 2
In Microsoft Entra
Entra ID → Enterprise applications → Tenant Hawk → Delete. This revokes consent on Microsoft's side; our tokens stop working within minutes and no future scan can run.
- 3
Both work independently
You don't need our cooperation to lock us out — revoking in Entra cuts access even if you never touch Tenant Hawk again. We recommend doing both so stored results are deleted too.
Don't take our word for it
The admin consent screen Microsoft shows you lists every permission above — compare them before you approve. After connecting, the app appears under Enterprise applications in your Entra portal with the same read-only scopes, and your audit log records exactly what it reads. If your security review needs more than this page, email support@tenanthawk.io and a human will answer the questionnaire.