fix(providers): stop the Fortnox reconnect loop, and make the attachment scopes opt-in (#1761)
The Fortnox document import needs the archive and connectfile scopes, which the registered Fortnox app does not have. Since #1549 pulled them out of the connect request (they broke every connect with invalid_scope before login), every attachment call fails and the user was told "Koppla om Fortnox och godkann behorigheterna", under a button that reruns an authorize URL still not asking for those scopes. Klura AB followed that loop four times and bought the Fortnox Arkiv module trying to satisfy it. Prod evidence: no Fortnox attachment has ever imported, across 166 companies and 24 consents since the feature shipped, and no live token carries the scopes. The error and the scope list now derive from one flag, FORTNOX_DOCUMENT_SCOPES_APPROVED. While it is false a permission failure maps to a new PROVIDER_DOCUMENT_SCOPES_UNAVAILABLE, which says the permission is missing on our side, that reconnecting will not help, and that the rest of the migration came through; the card offers no button, because no user action can succeed. The attachment scopes also become an opt-in consent rather than part of every connect. Fortnox derives customer licence requirements from what an integration requests, so asking everyone for Arkivplats would put a licence in front of customers who never import a receipt; and keeping it off the default connect caps the blast radius of a wrong portal registration at the underlag flow rather than every Fortnox connection. buildFortnoxAuthUrl already took per-call scopes, provider-client simply never passed any, so this threads documentScopes from that one button through /connect into the authorize URL. A document consent is always a superset of an ordinary one: the callback overwrites the consent's tokens in place, so a narrower grant would revoke the migration's own ledger access. Pinned by a test that holds either way the flag is set, alongside one for the 400-with-behorighet answer that six companies hit between 08-13 and 08-19 and saw only a generic retry for. Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Jakob Wennberg
Claude Opus 5
parent
c5b7716f74
commit
f3e4fdcf32
@@ -1135,3 +1135,4 @@ One line per decision: `[YYYY-MM-DD] <decision>: <why>`. Appended by agents and
|
||||
[2026-08-19] #1674 audit fixed the in-repo disclosures only (privacy sub-processor Bedrock row now names Anthropic as model vendor, replay paragraph states the deny-by-default guarantee, both locked by app/(public)/privacy/__tests__): Anthropic was deliberately NOT added as its own sub-processor row because no code path sends data to Anthropic (hosted uses Bedrock in eu-north-1, lib/ai/provider.ts); the artifact the prospect actually read (published DPA PDF or marketing security page listing Anthropic/OpenAI in the US) lives outside this repo and needs founder/legal action, as does any underbitraede-list wording.
|
||||
[2026-08-19] #1674 audit fixed the in-repo disclosures only (privacy sub-processor Bedrock row now says AI requests go to Amazon Bedrock and the models are Anthropics Claude running inside Bedrock, replay paragraph states the deny-by-default guarantee, both locked by app/(public)/privacy/__tests__): Anthropic was not added as its own sub-processor row because the HOSTED posture is Bedrock by credential precedence (lib/ai/provider.ts: static AWS keys select Bedrock, region is AWS_REGION with eu-north-1 as the default, not a guarantee); a direct Anthropic API path DOES exist in code for self-hosted deployments (AI_PROVIDER=anthropic, or ANTHROPIC_API_KEY without static AWS keys), so "no code path sends data to Anthropic" would be false and the page asserts nothing about Anthropics underbitraede status either way; whether Anthropic is an underbitraede, plus aligning the published DPA PDF / marketing security page (which listed Anthropic/OpenAI in the US), is founder/legal action outside this repo.
|
||||
[2026-08-20] Reverted #1765: the company switcher is NOT mounted at the top of the desktop sidebar. Founder call after seeing it live: switching belongs in the bottom user block only (the UserMenu flyout), so the sidebar top stays brand + collapse and the nav starts immediately below. #1664's "one-click from the top" framing is therefore declined, not merely unimplemented; the logo title tooltip went back with the revert since it shipped inside the same commit. Do not re-add a top-of-sidebar switcher from #1664 without a new founder decision.
|
||||
[2026-08-20] Fortnox voucher-attachment scopes (Arkivplats + Koppla filer) are requested per authorize call from the underlag follow-up only, never from an ordinary connect, and gated on FORTNOX_DOCUMENT_SCOPES_APPROVED in lib/providers/fortnox/oauth.ts (the portal-registration switch). Two reasons: Fortnox derives customer licence requirements from what the integration requests, so an all-connects request would put an Arkivplats licence in front of customers who never import a receipt (the portal says so in as many words); and a scope the registered app lacks makes authorize reject with invalid_scope before login, so keeping it off the default connect caps the blast radius at the underlag flow instead of every Fortnox connection (incident 2026-08-13). A document consent is always a superset of an ordinary one, because the callback overwrites the consent's tokens in place and a narrower grant would revoke the migration's own ledger access. While the flag is false the attachment 403 reports PROVIDER_DOCUMENT_SCOPES_UNAVAILABLE with no action offered, instead of reconnect advice for a permission we never ask for: that advice sent Klura AB around the OAuth loop four times and to buy the Fortnox Arkiv module for nothing (support case 2026-08-20). Portal registration alone changes nothing observable, which is why turning the scopes on and back off that day neither caused nor fixed the error.
|
||||
|
||||
Reference in New Issue
Block a user