______ __ __ __ _ ___
/_ __/___ / /_____ ____ / /_____ ______/ /_(_)_________ _ __ |__ \
/ / / __ \/ //_/ _ \/ __ \ / __/ __ `/ ___/ __/ / ___/ ___/ | | / / __/ /
/ / / /_/ / ,< / __/ / / / / /_/ /_/ / /__/ /_/ / /__(__ ) | |/ / / __/
/_/ \____/_/|_|\___/_/ /_/ \__/\__,_/\___/\__/_/\___/____/ |___(_)____/
This is an updated version of TokenTactics originally written by Stephan Borosh @rvrsh3ll & Bobby Cooke @0xBoku.
Azure access tokens allow you to authenticate to certain endpoints as a user who signs in with a device code. If you are in possesion of a FOCI (Family of Client IDs) capable refresh token you can use it to get access tokens to all known FOCI capable endpoints. Since the refresh-token also contains the information if the user has done multi-factor authentication you can use this. Once you have a user's access token, it may be possible to access certain apps such as Outlook, SharePoint, OneDrive, MSTeams and more.
For instance, if you have a Graph or MSGraph refresh token, you can then connect to Azure and dump users, groups, etc. You could then, depending on conditional access policies, switch to an Azure Core Management token and run AzureHound. Then, get an Outlook access token and read/send emails or MS Teams and read/send teams messages!
For more on Azure token types Microsoft identity platform access tokens
There are some example requests to endpoints in the resources folder. There is also an example phishing template for device code phishing.
You may also use these tokens with AAD Internals as well. We strongly recommended to check this amazing tool out.
Import-Module .\TokenTactics.psd1
Get-Help Get-EntraIDToken
Invoke-RefreshToSubstrateToken -Domain "myclient.org"Get-EntraIDToken -Client MSGraphOnce the user has logged in, you'll be presented with the JWT and it will be saved in the $response variable. To access the access token use $response.access_token from your PowerShell window to display the token. You may also display the refresh token with $response.refresh_token. Hint: You'll want the refresh token to keep refreshing to new tokens!
Get-EntraIDToken -Client DODMSGraphImportant
This feature was introduced in v0.2.20 and required PowerShell 7.0
If you have created a passkey in a third party provider like KeePassXC, Bitwarden, 1Password, or similar you can export the private key material.
Caution
Exporting you private key material is extremely dangerous. Make sure you understand the risk before your move on.
The KeePassXC passkey file format is natively supported and you can point the cmdlet to the file directly. The initial sign-in procedure will only get the required ESTSAUTH cookie and you have to use Get-EntraIDTokenFromESTSCookie to exchange this cookie for a bearer token (access token, refresh token, and id token).
# Retrieve the ESTSAUTH cookie value
Invoke-EntraIDPasskeyLogin -Verbose -KeyFilePath "C:\Users\Fabian\Microsoft.passkey"
# Exchange the ESTSAUTH cookie for bearer tokens
Get-EntraIDTokenFromESTSCookie -CookieValue $Global:ESTSAUTHIf you have an unsupported file format you can specify the required values manually and achieve the same goal.
Invoke-EntraIDPasskeyLogin -Verbose -UserPrincipalName "myUserName@example.com" -UserHandle "XYZ" -CredentialId "9e9c8297-0cde-4726-8852-16c141e15bd3" -PrivateKey $PrivateKey
Get-EntraIDTokenFromESTSCookie -CookieValue $Global:ESTSAUTHGet-EntraIDTokenFromESTSCookie -ESTSAuthCookie "0.AbcApTk..."This module uses authorization code flow to obtain an access token and refresh token using ESTSAuth (or ESTSAuthPersistent) cookie. Useful if you have phished a session via Evilginx or have otherwise obtained this cookie.
Be sure to use the right cookie! ESTSAuthPersistent is only useful when a CA policy actually grants a persistent session. Otherwise, you should use ESTSAuth. You can usually tell which one to use based on length, the longer cookie is the one you want to use :)
Note: This may not work in all cases as it may require user interaction. If this is the case, either use the Device Code flow above, or try roadtx interactiveauth --estscookie
This feature was backported from the pull request by rotarydrone in the original repo.
One of the most prominent example for this oauth2 flow (at least at the beginning on 2025) is the Intune Company Portal which allows, for some resources, to bypass device compliance requirements.
This intel was first published by @dirkjan and then released at Black Hat Europe to a wider audience by @TEMP43487580
JumpsecLabs published a blog article and a POC in form of TokenSmith shortly after.
Now the same capabilities are available in TokenTacticsV2.
Get-AzureAuthorizationCode will create a URL you can then use to authenticate to.
Get-EntraIDTokenFromAuthorizationCode uses wither the full URL or can be used with the parameters AuthorizationCode and RedirectUrl to exchange the auth code to an access and refresh token. After that you can try to get access to other resources as always.
If you do not specify a refresh token the cmdlets will use $response.refresh_token as a default.
Invoke-RefreshToOutlookToken -domain "myclient.org"
$OutlookToken.access_tokenConnect-AzureAD -AadAccessToken $response.access_token -AccountId user@myclient.orgInvoke-RefreshToMSGraphToken -Domain "myclient.org"
Connect-MgGraph -AccessToken $MSGraphToken.access_token -Scopes "User.Read.All","Group.ReadWrite.All"This will remove any token variables.
Clear-Token -Token AllWith continuous access evaluation Microsoft implements additional security measures, but also extend the maximum lifetime of an access token to 24 hours. Certain CAE capable service like MSGraph, Exchange, Teams and SharePoint can blocke access tokens based on certain events triggered by Azure AD. Currently those critical events are:
- User Account is deleted or disabled
- Password for a user is changed or reset
- Multi-factor authentication is enabled for the user
- Administrator explicitly revokes all refresh tokens for a user
- High user risk detected by Azure AD Identity Protection (not in Teams and SharePoint Online)
Invoke-RefreshToMSGraphToken -Domain "myclient.org" -UseCAE
if ((Parse-JWTtoken $MSGraphToken.access_token).ValidForHours -gt 23) { "MSGraph token is CAE capable" }If you have AADInternals installed as well you can use the created access tokens.
Invoke-RefreshToMSTeamsToken -UseCAE -Domain "myclient.org"
Set-AADIntTeamsStatusMessage -Message "My cool status message" -AccessToken $MSTeamsToken.access_token -VerboseGet-Command -Module TokenTactics
CommandType Name Version Source
----------- ---- ------- ------
Alias Forge-UserAgent 0.2.20 TokenTactics
Alias Get-AzureAuthorizationCode 0.2.20 TokenTactics
Alias Get-AzureToken 0.2.20 TokenTactics
Alias Get-AzureTokenFromAuthorizationCode 0.2.20 TokenTactics
Alias Get-AzureTokenFromCookie 0.2.20 TokenTactics
Alias Get-AzureTokenFromESTSCookie 0.2.20 TokenTactics
Alias Get-AzureTokenFromRefreshTokenCredentialCookie 0.2.20 TokenTactics
Alias Parse-JWTtoken 0.2.20 TokenTactics
Alias RefreshTo-AzureCoreManagementToken 0.2.20 TokenTactics
Alias RefreshTo-AzureKeyVaultToken 0.2.20 TokenTactics
Alias RefreshTo-AzureManagementToken 0.2.20 TokenTactics
Alias RefreshTo-AzureStorageToken 0.2.20 TokenTactics
Alias RefreshTo-DeviceRegistrationToken 0.2.20 TokenTactics
Alias RefreshTo-DODMSGraphToken 0.2.20 TokenTactics
Alias RefreshTo-GraphToken 0.2.20 TokenTactics
Alias RefreshTo-MAMToken 0.2.20 TokenTactics
Alias RefreshTo-MSGraphToken 0.2.20 TokenTactics
Alias RefreshTo-MSManageToken 0.2.20 TokenTactics
Alias RefreshTo-MSTeamsToken 0.2.20 TokenTactics
Alias RefreshTo-OfficeAppsToken 0.2.20 TokenTactics
Alias RefreshTo-OfficeManagementToken 0.2.20 TokenTactics
Alias RefreshTo-OneDriveToken 0.2.20 TokenTactics
Alias RefreshTo-OutlookToken 0.2.20 TokenTactics
Alias RefreshTo-SharePointToken 0.2.20 TokenTactics
Alias RefreshTo-SubstrateToken 0.2.20 TokenTactics
Alias RefreshTo-YammerToken 0.2.20 TokenTactics
Function Clear-Token 0.2.20 TokenTactics
Function ConvertFrom-JWTtoken 0.2.20 TokenTactics
Function ConvertTo-Base64Url 0.2.20 TokenTactics
Function ConvertTo-PEMPrivateKey 0.2.20 TokenTactics
Function ConvertTo-URLParameters 0.2.20 TokenTactics
Function Get-EntraIDAuthorizationCode 0.2.20 TokenTactics
Function Get-EntraIDToken 0.2.20 TokenTactics
Function Get-EntraIDTokenFromAuthorizationCode 0.2.20 TokenTactics
Function Get-EntraIDTokenFromCookie 0.2.20 TokenTactics
Function Get-EntraIDTokenFromESTSCookie 0.2.20 TokenTactics
Function Get-EntraIDTokenFromRefreshTokenCredentialCookie 0.2.20 TokenTactics
Function Get-ForgedUserAgent 0.2.20 TokenTactics
Function Get-TenantID 0.2.20 TokenTactics
Function Get-TTCodeChallenge 0.2.20 TokenTactics
Function Get-TTCodeVerifier 0.2.20 TokenTactics
Function Invoke-EntraErrorHandling 0.2.20 TokenTactics
Function Invoke-EntraIDPasskeyLogin 0.2.20 TokenTactics
Function Invoke-RefreshToAzureCoreManagementToken 0.2.20 TokenTactics
Function Invoke-RefreshToAzureKeyVaultToken 0.2.20 TokenTactics
Function Invoke-RefreshToAzureManagementToken 0.2.20 TokenTactics
Function Invoke-RefreshToAzureStorageToken 0.2.20 TokenTactics
Function Invoke-RefreshToDeviceRegistrationToken 0.2.20 TokenTactics
Function Invoke-RefreshToDODMSGraphToken 0.2.20 TokenTactics
Function Invoke-RefreshToGraphToken 0.2.20 TokenTactics
Function Invoke-RefreshToMAMToken 0.2.20 TokenTactics
Function Invoke-RefreshToMSGraphToken 0.2.20 TokenTactics
Function Invoke-RefreshToMSManageToken 0.2.20 TokenTactics
Function Invoke-RefreshToMSTeamsToken 0.2.20 TokenTactics
Function Invoke-RefreshToOfficeAppsToken 0.2.20 TokenTactics
Function Invoke-RefreshToOfficeManagementToken 0.2.20 TokenTactics
Function Invoke-RefreshToOneDriveToken 0.2.20 TokenTactics
Function Invoke-RefreshToOutlookToken 0.2.20 TokenTactics
Function Invoke-RefreshToSharePointToken 0.2.20 TokenTactics
Function Invoke-RefreshToSubstrateToken 0.2.20 TokenTactics
Function Invoke-RefreshToToken 0.2.20 TokenTactics
Function Invoke-RefreshToYammerToken 0.2.20 TokenTactics
Function New-FidoAuthenticatorData 0.2.20 TokenTactics
Function New-FidoSignature 0.2.20 TokenTactics- @rvrsh3ll Author of TokenTactics (original)
- @0xBoku co-author of TokenTactics (original) and researcher.
- @f-bader updated TokenTactics to support V2 endpoint and additional features like CAE. Maintainer of TokenTacticsV2
- @Pri3st added functions to fetch Storage and Key Vault access tokens and a custom user agent
TokenTactic's methods are highly influenced by the great research of Dr Nestori Syynimaa at https://o365blog.com/.
- Renamed all
Get-Azurecmdlets toGet-EntraID - Add aliases for backwards compatibility
- Add improved error handling for ConvergedSignIn interrupts
- Add
Invoke-EntraIDPasskeyLoginto automate Passkey sign-in flows. This will save the ESTSAUTH cookie and websession as global variables for reuse in other cmdlets likeGet-EntraIDTokenFromESTSCookie - Add proxy support for
Invoke-EntraIDPasskeyLogin,Get-EntraIDTokenFromCookie,Get-EntraIDTokenFromRefreshTokenCredentialCookieandGet-EntraIDTokenFromESTSCookie
- Add parameter
-Usernameto prefill the login_hint parameter in cmdletGet-AzureAuthorizationCode - Add parameter
-CopyToClipboardin cmdletGet-AzureAuthorizationCode
- Fix for Custom User Agent parameter
- Add awareness for current runspace and minimize output if run as PSTask (e.g. if run in
Foreach-Object -parallel)
- Add the ability to freely define any UserAgent using the new
-CustomUserAgentproperty. Thanks to Pri3st
- Bugfix: Wrong type initialization
- Add
ResourceTenantforGet-EntraIDTokento support B2B device code phishing - Switch out Azure Management client id
- Add
UseCodeVerifierto support Proof Key for Code Exchange (PKCE) - Add
UseV1Endpointto some functions to support a broader variety of endpoint tests
- Add
Get-AzureTokenFromRefreshTokenCredentialCookie("x-ms-RefreshTokenCredential") and add modularizedGet-AzureTokenFromCookie - Add parameter to choose cookie type (ESTSAuth, ESTSAUTHPERSISTENT) to
Get-AzureTokenFromESTSCookie - Add sample output for
Get-AzureTokenFromAuthorizationCodetoGet-AzureAuthorizationCodeoutput - Improved output and more verbose error handling
- Expand
Get-AzureTokenFromESTSCookieto support the appverify endpoint - Improve cookie management of
Get-AzureTokenFromESTSCookie
- Fix bug custom scopes in
Get-AzureAuthorizationCodeandGet-AzureTokenFromAuthorizationCode - Change default redirect Uri for
Get-AzureAuthorizationCode
- Added new cmdlets
Get-AzureAuthorizationCodeandGet-AzureTokenFromAuthorizationCode
Those cmdlets are heavily inspired by TokenSmith maintained by @gladstomych - Added new cmdlet
Invoke-RefreshToDeviceRegistrationTokenwhich is a TokenTactics version of the AADInternals cmdletGet-AccessTokenForAADJoin - Added v1 endpoint support for
Invoke-RefreshToTokenwith theUseV1Endpoint. This was required to addInvoke-RefreshToDeviceRegistrationToken - Added pipeline support for
ConvertFrom-JWTtoken - Add default values to
Get-ForgedUserAgent
- Support for Linux as a device platform
- Support for OS/2 as a device platform 😁
- Backported Yammer token support
- Backported switch to allowed PowerShell verbs, added alias for backward compatibility
- Backported pull request by rotarydrone to convert ESTSAuth to access token
- Switched to
v2.0of the Azure AD OAuth2 endpoint - Support for continuous access evaluation using the new
-UseCAEswitch - Made
ClientIda parameter - Changed
client_idfor MSTeams - Added support for OneDrive and SharePoint
- Added
IssuedAt,NotBefore,ExpirationDateandValidForHoursinConvertFrom-JWTtokenoutput in human readable format - Passkey sign-in support
- Refactored the codebase to for easier maintenance
