Skip to content

AADSTS7000014: Device code value isn't valid (fix)

Short answer: AADSTS7000014 means a device code token request carried a device_code value that Entra doesn't accept. In the lab it came back for a device_code that was never issued. Microsoft doesn't document the code; most likely the app sent a wrong, cut-off or made-up value, not an expired one (that is 70020, per user reports). It has low attack value. Fix how the app stores and sends the code.

Fix: User: start the sign-in again so the app gets a fresh code; if it fails again, report the tool and version to its maintainer. Developer: poll `/token` with the exact `device_code` string from `/devicecode` (not the `user_code`), using the same `client_id` and tenant endpoint for both calls. Full steps

At a glance
CodeAADSTS7000014
In Microsoft's error referenceNo (checked ). Wording on this page is what Entra returned or what users report.
CategoryTokens and sessions
TypeFailure
Attack signalLow: usually configuration or user error
Microsoft lookuplogin.microsoftonline.com/error?code=7000014

Microsoft’s error code reference doesn’t list AADSTS7000014 (checked 30 October 2026). I found no other Microsoft page that documents it either.

My lab tenant returned this message for a device code token request whose device_code value had never been issued:

AADSTS7000014: The provided value for the input parameter ‘device_code’ is not valid.

How the device code flow works, from Microsoft’s device code page: the app first calls /devicecode and gets back a device_code, “A long string used to verify the session between the client and the authorization server.” The app then polls /token with grant_type=urn:ietf:params:oauth:grant-type:device_code, the same client_id (“Must match the client_id used in the initial request”) and that device_code. 7000014 is a rejection of the device_code value in that second step.

Microsoft’s page lists the protocol errors an app can get while polling. One of them fits this case:

bad_verification_code: The device_code sent to the /token endpoint wasn’t recognized. Verify that the client is sending the correct device_code in the request.

Our reading: 7000014 is the AADSTS code behind an unrecognised device_code. The lab run recorded only the message line, not the error field, so which protocol error comes with it is not confirmed.

Two sibling codes have nearly the same wording. Neither is in Microsoft’s reference either, and the wording below comes from user reports:

Code Message as users posted it Meaning
70020 “The provided value for the input parameter ‘device_code’ is not valid. This device code has expired.” (azure-cli issue 22251) The code was real but its time ran out.
90132 “The provided value for the input parameter ‘device_code’ is not valid. Device codes supporting the personal Microsoft Account sign-in audience can only be used for v2 common or consumers tenants.” (Microsoft Q&A 929217) A personal account was used with a tenant-specific endpoint.

7000014 carries no such second sentence. It looks like the general “this value isn’t one we recognise” case.

On 30 October 2026 an automated lab run sent a device code token request to my lab tenant with a device_code that the tenant had never issued. Entra returned AADSTS7000014 with this first line:

AADSTS7000014: The provided value for the input parameter ‘device_code’ is not valid.

That confirms the code and its wording at the token endpoint. Note what the run expected: 70020, 70000 or 9002313. It got none of those. No row for it appeared in the lab tenant’s exported sign-in logs (interactive, non-interactive and service principal, exported 30 October 2026). Likely a device code that was never issued is rejected before any sign-in is recorded, but that is unconfirmed. The KQL on this page returns nothing on the lab rows, as expected.

Usually not. It points to an app that sends a broken device_code.

Pattern Likely meaning
A CLI, script or tool fails right after it shows the “enter the code” message The app stores or sends the device_code wrongly: cut off, double-encoded, or from a different request. Likely, but unconfirmed.
A home-grown device code script that never worked The script polls with the user_code (the short code the user types) instead of the device_code. A guess; not tested.
Failures after a long wait Expect 70020 (expired) rather than 7000014, based on user reports of 70020.
Polling with a different client_id or tenant than the /devicecode call Microsoft requires the same client_id. Which code this returns is untested.

Device code phishing is a real attack: Microsoft’s Conditional Access page calls the flow “a high-risk authentication method that can be part of a phishing attack.” Our reading is that 7000014 is not a sign of it. In that attack the attacker requests a real code and polls with it, so their requests carry a valid device_code. A burst of 7000014 from one IP is more likely a broken tool than a phishing kit.

Microsoft doesn’t document which sign-in table 7000014 is logged in. The request likely names a client and a tenant but no user, because no user ever approved a code that was never issued. A row may not exist at all. Check anyway:

union withsource=SourceTable SigninLogs, AADNonInteractiveUserSignInLogs, AADServicePrincipalSignInLogs
| where TimeGenerated > ago(30d)
| where ResultType in ("7000014", "70020", "90132")
| summarize Rows = count(), LastSeen = max(TimeGenerated) by SourceTable, ResultType, AppId

More useful in practice: see which apps use the device code flow in your tenant and how they fare. AuthenticationProtocol lists deviceCode among its documented values:

SigninLogs
| where TimeGenerated > ago(30d)
| where AuthenticationProtocol == "deviceCode"
| summarize Rows = count(), Users = dcount(UserPrincipalName), Failures = countif(ResultType != "0") by AppDisplayName, AppId
| sort by Rows desc

An app that shows up here and that you don’t expect is worth a look whatever its error code.

  • Microsoft “recommends blocking device code flow wherever possible” with a Conditional Access authentication flows policy.
  • Our reading: 7000014 is not that block. The value is rejected before any user is known, so there is nothing for a policy to evaluate. A user blocked by such a policy gets a Conditional Access failure on the sign-in, which you investigate on the sign-in’s Conditional Access tab, as Microsoft’s page describes.

For the user: start the sign-in again so the app gets a fresh code. If it fails again straight away, report the tool and its version to whoever maintains it.

For developers:

  1. Poll /token with the exact device_code string from the /devicecode response. Don’t trim, re-encode or truncate it; it is long.
  2. Send the device_code, not the user_code.
  3. Use the same client_id and the same tenant endpoint for both calls.
  4. Handle the documented polling errors: repeat on authorization_pending after interval seconds; stop on authorization_declined, bad_verification_code and expired_token.
  5. Prefer a library (MSAL) over hand-written polling.

For admins:

  1. Find the app with the first query, then ask its owner which tool and version it is.
  2. If nobody should use device code flow, block it with a Conditional Access authentication flows policy. That stops the flow for real attackers too.

Sources

  1. Microsoft Entra authentication and authorization error codes
  2. Microsoft identity platform and the OAuth 2.0 device authorization grant flow
  3. Conditional Access: Authentication flows
  4. Azure/azure-cli issue 22251 (AADSTS70020 with az login --use-device-code)
  5. Microsoft Q&A: OAuth2 Error AADSTS90132: Device Code is not valid
  6. SigninLogs table reference (Azure Monitor)