Skip to content

AADSTS50173: Grant expired because it was revoked

Short answer: AADSTS50173 means a refresh token was rejected because it was issued before the user's TokensValidFrom date, usually after a password change, reset or admin session revocation. After an incident it is the row you want: each client still holding an old token, attacker included, fails with 50173 in AADNonInteractiveUserSignInLogs, exposing its IP and device.

At a glance
CodeAADSTS50173
Microsoft nameGrant expired due to revocation
CategoryTokens and sessions
TypeFailure
Attack signalMedium: worth a look in context
MITRE ATT&CKT1550.001 Use Alternate Authentication Material: Application Access Token
Where to lookAADNonInteractiveUserSignInLogs, SigninLogs
Microsoft lookuplogin.microsoftonline.com/error?code=50173

The provided grant has expired due to it being revoked, a fresh auth token is needed. The user might have changed or reset their password. The grant was issued on ‘{authTime}’ and the TokensValidFrom date (before which tokens are not valid) for this user is ‘{validDate}’.

Microsoft’s troubleshooting article lists three causes: “The user changes or resets their password. The refresh token expires. An administrator revokes the refresh token.”

The client tried to redeem a refresh token that was issued before the user’s TokensValidFrom date. The token is dead. The client has to send the user through an interactive sign-in again.

Usually not. A password change makes every device the user owns hit 50173 once, and then the user signs in again. That is normal.

The security value is during incident response. When you revoke a compromised user’s sessions with Revoke-MgUserSignInSession or Revoke sessions in the admin center, the Graph call “Invalidates all the refresh tokens issued to applications for a user (and session cookies in a user’s browser), by resetting the signInSessionsValidFromDateTime user property to the current date-time”, with “a small delay of a few minutes” possible. Microsoft’s revoke-access procedure (disable the account, reset the password, revoke, disable devices) says that after those steps “the user can’t gain new tokens for any application tied to Microsoft Entra ID.” Revocation on its own doesn’t stop someone who still knows the password from signing in again. Every client that still holds a refresh token for that user fails on its next refresh. That includes the attacker’s client. Each of those failures is a 50173 row with an IP address, a user agent and device details.

Pattern after a revocation or password reset Likely meaning
50173 from the user’s own managed devices and usual IPs The legitimate user’s apps being signed out. Expected.
50173 from an IP, country or device you can’t tie to the user A client you didn’t know about was holding a token. Treat it as the attacker’s session and pivot on that IP.
50173 rows continue from the same unknown IP, followed by interactive attempts (SigninLogs) The attacker is trying to get back in with credentials. Check the password was actually changed and MFA methods are clean.
No 50173 at all after the revocation Nothing was refreshing a token for that user in the window you looked at. Not proof that nothing was ever stolen.

Two reading notes:

  • The TokensValidFrom date in the message is the cut-off set by the revocation or password change. Tokens issued before it are refused.
  • Revocation only stops new tokens. Microsoft notes that “By default, access tokens issued by Microsoft Entra ID last for 1 hour.” An attacker can keep using an access token they already have until it expires, and you won’t see a 50173 for that period. The exception is Continuous Access Evaluation: Microsoft’s CAE page says the implementation “focuses on Exchange, Teams, and SharePoint Online” and needs a CAE-capable client. There, an admin revocation or password change is enforced on the access token before it expires, with “latency of up to 15 minutes”. CAE access tokens themselves are long-lived, “up to 28 hours”, and “If you aren’t using CAE-capable clients, your default access token lifetime remains 1 hour.” The session revocation guide covers this and how to prove the cut-off.

Who was still holding a token for this user after you revoked it? Set the user and the time you revoked.

let revokedUser = "user@contoso.com";
let revokedAt = datetime(2026-10-11T09:00:00Z);
AADNonInteractiveUserSignInLogs
| where TimeGenerated > revokedAt
| where UserPrincipalName =~ revokedUser
| where ResultType == "50173"
| extend Device = parse_json(DeviceDetail), Location = parse_json(LocationDetails)
| summarize FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated),
Rows = count(),
Apps = make_set(AppDisplayName, 10)
by IPAddress,
Country = tostring(Location.countryOrRegion),
City = tostring(Location.city),
OS = tostring(Device.operatingSystem),
Browser = tostring(Device.browser),
DeviceId = tostring(Device.deviceId),
IsManaged = tostring(Device.isManaged),
IsCompliant = tostring(Device.isCompliant),
UserAgent
| sort by FirstSeen asc

DeviceDetail and LocationDetails are strings in AADNonInteractiveUserSignInLogs (they are dynamic in SigninLogs), so they need parse_json before you can read their fields. The JSON field names above follow the Microsoft Graph signIn resource; check them against a row in your own workspace.

Non-interactive rows are aggregated when application, user, IP address, status and resource match, so Rows is a count of log rows, not of refresh attempts.

Then take every IP from that result that isn’t the user’s and see what else it touched, across all users:

let suspectIPs = dynamic(["203.0.113.10"]);
union
(SigninLogs
| project TimeGenerated, UserPrincipalName, IPAddress, ResultType, AppDisplayName, Table = "Interactive"),
(AADNonInteractiveUserSignInLogs
| project TimeGenerated, UserPrincipalName, IPAddress, ResultType, AppDisplayName, Table = "NonInteractive")
| where TimeGenerated > ago(14d)
| where IPAddress in (suspectIPs)
| summarize Users = make_set(UserPrincipalName, 20),
Results = make_set(ResultType, 20),
Apps = make_set(AppDisplayName, 20),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated)
by IPAddress, Table

ResultType is a string column, so compare it with "50173", not 50173.

How do Conditional Access and MFA affect it?

Section titled “How do Conditional Access and MFA affect it?”
  • Revocation works independently of Conditional Access. No policy has to match for a 50173 to happen.
  • After a 50173 the client needs a fresh interactive sign-in. That new sign-in goes through the password check, MFA and your Conditional Access policies again. That is the point: an attacker with a stolen refresh token but without the password and the MFA factor can’t get past it.
  • If the attacker also has the password, revocation alone isn’t enough: it ends their current sessions, but they can sign in again interactively, and if they registered their own MFA method they will pass that step too. Reset the password and check the user’s registered MFA methods in the same response.

For the user: sign in again. Each app will prompt once.

For admins (incident response):

  1. Reset the password if it may be known to the attacker. Microsoft’s procedure resets before it revokes, so a new sign-in can’t slip in between.
  2. Revoke the user’s sessions: Revoke-MgUserSignInSession -UserId $User.Id, or Revoke sessions on the user’s Overview page.
  3. Microsoft’s revoke-access guidance also disables the user’s devices (Update-MgDevice -AccountEnabled:$false). Do that for devices you suspect.
  4. Run the first query above for the time after the revocation. Every 50173 from an IP or device you can’t tie to the user is an attacker indicator. Block it and hunt it across other accounts with the second query.
  5. Remember the access-token window: allow for up to an hour of continued access after revocation for clients and resources without Continuous Access Evaluation, and about 15 minutes for Exchange, SharePoint and Teams through CAE-capable clients.

Guides that use this code

Sources

  1. Microsoft Entra authentication and authorization error codes
  2. Error AADSTS50173 - The provided grant has expired due to it being revoked
  3. Revoke user access in Microsoft Entra ID
  4. Non-interactive user sign-ins
  5. Microsoft Graph: user: revokeSignInSessions
  6. Continuous access evaluation
  7. AADNonInteractiveUserSignInLogs table reference (Azure Monitor)