Setup:
- Client type: public client, PKCE required (confirmed — see below), no client secret
- redirect_uri: http://localhost:4200/ (registered exactly as such in the developer portal, verified via the client editor UI)
- Scope requested: IoT User offline_access
- Grant: authorization_code with code_challenge_method=S256
Flow followed (per the Getting Started guide):
1. GET https://iam.viessmann-climatesolutions.com/idp/v3/authorize?client_id=...&redirect_uri=http://localh......
2. Logged in interactively in a real browser (reCAPTCHA passed normally).
3. Browser redirects to http://localhost:4200/?code=...&state=... as expected — state always matches.
4. POST https://iam.viessmann-climatesolutions.com/idp/v3/token with grant_type=authorization_code, client_id, redirect_uri, code, code_verifier.
Result every time: 400 {"error":"invalid_grant","error_description":"Invalid grant"}
What I've ruled out, to save the next reader's time:
- PKCE math — independently recomputed BASE6and confirmed it matches the code_challengesent at step 1. - Code freshness / latency — set up a local irect URI that performs the token exchangeinline, in the same process, the instant the redirect lands (effectively zero delay between code issua exchange). Same invalid_grant.
- Client/redirect_uri mismatch — visually confirmed in the developer portal's client editor that the reg redirect URI is exactly http://localhost:4n both requests, and this was alreadyconfigured before any of these attempts (not something added reactively). - PKCE optionality — tried omitting code_cha entirely to see if this client accepts aplain authorization_code flow. Got a different, earlier error instead: invalid_request: "Code Challeng thrown at the /authorize step itself, befored. This confirms PKCE is mandatory for thisclient and that the client is otherwise reachable/valid. - Tested across 5 independent attempts with ier each time — same result every time.
Additional context: the same client_id can sccess token via the developer portal's own"try it" feature, and that token works fine against the IoT API. So the client itself is active and the client_id/scope combination is valid for APIthe browser-driven Authorization Code + PKCEexchange that fails.
I can confirm the same issue independently with the official Home Assistant ViCare integration.
I reproduced it today, 18 September 2026, with Home Assistant Core 2026.9.2.
My Developer Portal client is configured according to the official Home Assistant ViCare documentation:
The authorization/login succeeds and the OAuth callback reaches Home Assistant. The failure occurs specifically during the authorization-code/PKCE token exchange at:
https://iam.viessmann-climatesolutions.com/idp/v3/token
With OAuth debug logging enabled, Home Assistant reports:
Token request for vicare_... failed (400): invalid_grant: Invalid grant
I have reproduced the complete OAuth flow several times with fresh authorization codes and always get the same result.
I also deleted and recreated the Home Assistant OAuth application credentials, freshly copied the Client ID from the Viessmann Developer Portal, verified the redirect URI and reCAPTCHA setting, and restarted Home Assistant. The result remains unchanged.
This therefore appears to reproduce the same authorization-code/PKCE token-exchange problem described in the original post, using a completely independent implementation (the official Home Assistant ViCare integration).
Could Viessmann please investigate whether there is currently an issue with the PKCE authorization-code exchange at the /idp/v3/token endpoint?
I can provide additional debug information privately if required.