Skip to content

For AI agents and tools

Everything on this site about AADSTS sign-in errors also exists as plain files: JSON per code, a Markdown twin of every code page, the raw lab runs and an OpenAPI description. They are generated at build time from the same source as the HTML pages, so a fact in a JSON file is the same fact the page shows, as of the same build. There is no server behind them and this site runs no analytics: they are static files. The host, Cloudflare, still processes ordinary request data as described on the Datenschutz page.

At this build: 118 AADSTS code pages (43 for codes Microsoft's error reference does not list), 35 of them marked lab-reproduced; 276 KQL queries across those pages; 14 lab runs with 505 recorded results, dated 2026-10-25 to 2026-10-31.

File What it holds
/api/aadsts/index.json One entry per published code: code, title, HTML URL, Markdown and JSON URLs, labReproduced (true or false), inMicrosoftReference, attack signal, last update.
/api/aadsts/{code}.json (for example 50126) The full record of one code page: Microsoft’s wording as the page quotes it, the security reading (category, attack signal, MITRE ATT&CK techniques, Conditional Access interaction), every KQL block, the fix, the lab reproduction when there is one, the matching lab-run rows, sources, canonical URL, dates, license.
/entra/aadsts/{code}.md (for example 50126) A Markdown twin of the HTML page with the same sections, plus an evidence section and the citation line. Each HTML code page links to its twins with <link rel="alternate">.
/llms-full.txt All Markdown twins in one file, each preceded by a separator line and its canonical URL.
/llms.txt A short description of the site with a link to every page and data file.
/lab-runs.json Every automated lab run: scenario, expected code, returned code, first line of the message as returned, date, method and the GitHub issue that holds the raw output.
/aadsts.json The dataset archived on Zenodo: the site’s own classification fields only, no Microsoft text. Described on the KQL lookup page.
/graph-errors.json Microsoft Graph error codes as the live service returned them in the lab.
/openapi.json An OpenAPI 3.1 description of these files, with examples taken from the same build.
/checksums.json SHA-256 of every file above, written at the end of the build. Not a signature; it tells two downloads apart.

The JSON files under /api/, /lab-runs.json, /openapi.json, /checksums.json, /aadsts.json and /graph-errors.json are served with Access-Control-Allow-Origin: *, so a browser-based tool can read them from another origin.

  • verification has three values. documentation: the page is based on Microsoft’s documentation and has not been reproduced in the lab. lab-reproduced: an automated run in a lab tenant returned the code; labReproduced then holds the date, method, scenario and Microsoft’s first line as returned. lab-verified: I reviewed the page myself, captured the sign-in log row and ran every query against it. No page is lab-verified yet; how pages are written and checked describes each state.
  • labReproduced is null on pages that have no lab reproduction, and the index marks them false. The count of reproduced pages is in the index as labReproducedCount and in the sentence at the top of this page.
  • inMicrosoftReference is false when Microsoft’s error code reference does not list the code. For those pages microsoftWording quotes what the lab returned or what users reported, and source says which.
  • securityReading is my classification, not Microsoft’s: attackSignal (high, medium, low), category, kind (failure, interrupt or configuration error), MITRE techniques with their names and tables (which sign-in log tables carry the code). isItAnAttack and conditionalAccess are the Markdown of those sections.
  • kql lists every query on the page with the sentence that introduces it. Queries are starting points: the thresholds are mine, and only pages with labReproduced.kqlTested had their queries run against exported lab rows.
  • labRuns on a code record are the rows of /lab-runs.json whose returned code or expected code names that code. expected can list alternatives separated by /; matchedExpectation says whether the returned code was among them. Graph runs record no expected code, so there it is null and matchedExpectation comes from the run’s own marking.
  • Placeholders. The lab tenant’s identifiers do not appear in these files (the raw lab run copies in the public aadsts-dataset repository still contain them; they are lab identifiers, not secrets). A tenant id reads {tenant-id}, an app id {app-id}, an object id {object-id}, an address {user-principal-name}, an IP {ip-address}, anything else {guid}. Microsoft’s own cut-off {EUII Hidden} is left as Microsoft returned it. A handful of Microsoft-published identifiers are kept, because the pages that quote them would lose their meaning otherwise. The complete list, read from the redaction code at build time:
  • 00000000-0000-0000-0000-000000000000: the nil GUID, quoted from Microsoft's cmdlet reference
  • 00000002-0000-0000-c000-000000000000: Windows Azure Active Directory (Azure AD Graph) resource
  • 00000002-0000-0ff1-ce00-000000000000: Office 365 Exchange Online
  • 9cdead84-a844-4324-93f2-b2e6bb768d07: Azure Virtual Desktop (client app)
  • f8cdef31-a31e-4b4a-93e4-5f571e91255a: Microsoft Services tenant (owner tenant of first-party apps, published by Microsoft)
  • 72f988bf-86f1-41af-91ab-2d7cd011db47: Microsoft corporate tenant (owner tenant of first-party apps, published by Microsoft)
  • 193.26.115.0: attacker network 193.26.115.0/24 (1337 Services GmbH), an indicator of compromise named in the token-replay guide

Every file carries generatedAt, the moment of the build, and every code record carries lastUpdated, the date the page last changed. /lab-runs.json is append-only: a run is never edited after the fact, and a new run is a new record with its own date. A result is a measurement on that day. Microsoft changes error wording and behavior, so a later run can return something different from an earlier one, and both stay in the file. The AADSTS change tracker records what Microsoft changed in its reference, week by week.

Each code record has an attribution string in the form Bram Brinkmeier, “title”, URL (CC BY 4.0), and lastUpdated for the date. The Markdown twins end with the same line. CC BY 4.0 covers my own text and classification fields. Quoted Microsoft wording belongs to Microsoft, is marked as a quote with its source, and can change. The Zenodo-archived dataset has its own DOI, given on the KQL lookup page and in the repository’s CITATION.cff.

The files are only as right as the pages they are built from. A wrong fact, a placeholder that leaked an identifier, or a lab result that no longer holds is a GitHub issue on the aadsts-dataset repository. A fix lands on the page, and the next build changes every file with it. The changelog lists what changed and when.

A build reads the code pages’ frontmatter and Markdown bodies and the files in data/lab-runs/, replaces identifiers, and writes the JSON, Markdown and text files next to the HTML. Tests compare the JSON facts with the HTML page facts, scan every published JSON, Markdown and text file for identifiers, validate the OpenAPI document and check the checksums against the files. The build code is in the site’s private repository under src/lib/ (redact.mjs, lab-runs.mjs, code-record.mjs, ai-data.ts), the endpoints under src/pages/, the post-build checksum script under scripts/.