{"record":{"id":"35f8240cfa7681ba","repo":"home-assistant/core","slug":"authentication-failed","errorCode":null,"errorMessage":"authentication_failed","messagePattern":"authentication_failed","errorType":"exception","errorClass":"ConfigEntryAuthFailed","httpStatus":null,"severity":"error","filePath":"homeassistant/components/azure_devops/coordinator.py","lineNumber":90,"sourceCode":"            name=DOMAIN,\n            update_interval=timedelta(seconds=300),\n        )\n\n        self.client = DevOpsClient(session=async_get_clientsession(hass))\n        self.organization = config_entry.data[CONF_ORG]\n\n    @ado_exception_none_handler\n    async def authorize(\n        self,\n        personal_access_token: str,\n    ) -> bool:\n        \"\"\"Authorize with Azure DevOps.\"\"\"\n        await self.client.authorize(\n            personal_access_token,\n            self.organization,\n        )\n        if not self.client.authorized:\n            raise ConfigEntryAuthFailed(\n                translation_domain=DOMAIN,\n                translation_key=\"authentication_failed\",\n                translation_placeholders={\"title\": self.title},\n            )\n\n        return True\n\n    @ado_exception_none_handler\n    async def get_project(\n        self,\n        project: str,\n    ) -> Project | None:\n        \"\"\"Get the project.\"\"\"\n        return await self.client.get_project(\n            self.organization,\n            project,\n        )\n","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/home-assistant/core/blob/58a3fdb3ea0538617f0a07efcfba6294de64fd59/homeassistant/components/azure_devops/coordinator.py#L72-L108","documentation":"Raised as ConfigEntryAuthFailed (translation_key authentication_failed, placeholder title) by the Azure DevOps coordinator's authorize() when client.authorize(pat, organization) completes without transport error but self.client.authorized is False — the Azure DevOps API did not accept the personal access token. Home Assistant then launches the re-auth flow. Note authorize() is wrapped by ado_exception_none_handler, so the ConfigEntryAuthFailed propagates as-is.","triggerScenarios":"POSTing the PAT to the organization's _apis/connectionData endpoint returns 401/203-non-authorized: expired or revoked PAT, PAT from a different organization/Azure AD tenant, insufficient scope, or SSO policy blocking basic PAT auth.","commonSituations":"PAT expired (default 30/90 day lifetime); user regenerated the token but did not update HA; organization enforces SSH/OAuth only; PAT created in a different AzDO org.","solutions":["Generate a fresh PAT in Azure DevOps (User settings > Personal access tokens) with Read scopes for Build, Code, Project and Team Information.","Complete the re-authentication flow triggered by this error and paste the new token.","Confirm the PAT belongs to the same organization and the account has access to the configured project.","If org policy disables PATs, use a service account or adjust policy; the API cannot authorize otherwise."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"async def pat_works(client, organization: str, pat: str) -> bool:\n    await client.authorize(pat, organization)\n    return client.authorized\n","typeGuard":null,"tryCatchPattern":"from homeassistant.exceptions import ConfigEntryAuthFailed\n\ntry:\n    await coordinator.authorize(pat)\nexcept ConfigEntryAuthFailed:\n    # PAT rejected: launch re-auth flow, never retry the same token\n    start_reauth(entry)","preventionTips":["Create PATs with the longest allowed lifetime or calendar a rotation reminder.","Test a new PAT against the org's connectionData endpoint before configuring HA.","On token regeneration, immediately update it in Home Assistant via re-auth."],"tags":["home-assistant","azure-devops","authentication","pat","reauth"],"backgroundTag":null,"analyzedSha":"58a3fdb3ea0538617f0a07efcfba6294de64fd59","analyzedAt":"2026-08-14T20:54:38.818Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}