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

Canonical: https://brambrinkmeier.com/entra/aadsts/7000014/
By Bram Brinkmeier. JSON: https://brambrinkmeier.com/api/aadsts/7000014.json

**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.

| Field | Value |
|---|---|
| Code | AADSTS7000014 |
| Category | Tokens and sessions |
| Type | Failure |
| Attack signal | Low: usually configuration or user error |
| In Microsoft's error reference | No (checked 2026-10-30) |
| Verification | lab-reproduced (2026-10-30) |
| Last updated | 2026-10-30 |

## What does AADSTS7000014 mean?

Microsoft's [error code reference](https://learn.microsoft.com/entra/identity-platform/reference-error-codes) 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](https://github.com/Azure/azure-cli/issues/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](https://learn.microsoft.com/en-us/answers/questions/929217/oauth2-error-aadsts90132-device-code-is-not-valid)) | 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.

## Reproduced in the lab

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.

## Is it an attack?

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.

## How do I find it in my logs (KQL)?

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:

```kusto
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:

```kusto
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.

## How does Conditional Access affect it?

- 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.

## How do I fix AADSTS7000014?

**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.

## Evidence

Reproduced in a lab tenant on 2026-10-30 (Device code token request against a lab tenant; scenario: Device code that was never issued). First line returned:

> AADSTS7000014: The provided value for the input parameter 'device_code' is not valid.

Lab-run rows naming this code (8; full list at https://brambrinkmeier.com/lab-runs.json):

| Date | Scenario | Expected | Got | Message (first line) |
|---|---|---|---|---|
| 2026-10-30 | Device code that was never issued | 70020 / 70000 / 9002313 | 7000014 | AADSTS7000014: The provided value for the input parameter 'device_code' is not valid. |
| 2026-10-30 | Device code that was never issued | 70020 / 70000 / 9002313 | 7000014 | AADSTS7000014: The provided value for the input parameter 'device_code' is not valid. |
| 2026-10-30 | Device code that was never issued | 70020 / 70000 / 9002313 | 7000014 | AADSTS7000014: The provided value for the input parameter 'device_code' is not valid. |
| 2026-10-30 | Device code that was never issued | 70020 / 70000 / 9002313 | 7000014 | AADSTS7000014: The provided value for the input parameter 'device_code' is not valid. |
| 2026-10-30 | Device code that was never issued | 70020 / 70000 / 9002313 | 7000014 | AADSTS7000014: The provided value for the input parameter 'device_code' is not valid. |
| 2026-10-30 | Device code that was never issued | 70020 / 70000 / 9002313 | 7000014 | AADSTS7000014: The provided value for the input parameter 'device_code' is not valid. |
| 2026-10-31 | Device code that was never issued | 70020 / 70000 / 9002313 | 7000014 | AADSTS7000014: The provided value for the input parameter 'device_code' is not valid. |
| 2026-10-31 | Device code that was never issued | 70020 / 70000 / 9002313 | 7000014 | AADSTS7000014: The provided value for the input parameter 'device_code' is not valid. |

## Sources

1. [Microsoft Entra authentication and authorization error codes](https://learn.microsoft.com/entra/identity-platform/reference-error-codes)
2. [Microsoft identity platform and the OAuth 2.0 device authorization grant flow](https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-device-code)
3. [Conditional Access: Authentication flows](https://learn.microsoft.com/en-us/entra/identity/conditional-access/concept-authentication-flows)
4. [Azure/azure-cli issue 22251 (AADSTS70020 with az login --use-device-code)](https://github.com/Azure/azure-cli/issues/22251)
5. [Microsoft Q&A: OAuth2 Error AADSTS90132: Device Code is not valid](https://learn.microsoft.com/en-us/answers/questions/929217/oauth2-error-aadsts90132-device-code-is-not-valid)
6. [SigninLogs table reference (Azure Monitor)](https://learn.microsoft.com/en-us/azure/azure-monitor/reference/tables/signinlogs)

## Related codes

[AADSTS9002313](https://brambrinkmeier.com/entra/aadsts/9002313/), [AADSTS700016](https://brambrinkmeier.com/entra/aadsts/700016/), [AADSTS70016](https://brambrinkmeier.com/entra/aadsts/70016/), [AADSTS90023](https://brambrinkmeier.com/entra/aadsts/90023/)

## License and citation

CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/). CC BY 4.0 covers the author's own text and classification fields. Quoted Microsoft error wording belongs to Microsoft, is quoted with its source and can change.

Cite as: Bram Brinkmeier, "AADSTS7000014: Device code value isn't valid (fix)", https://brambrinkmeier.com/entra/aadsts/7000014/ (CC BY 4.0), last updated 2026-10-30.
