Implement Vipps API Client with token exchange and userinfo endpoints
epic-bankid-vipps-login-api-clients-task-003 — Build the Vipps API Client infrastructure component responsible for all HTTP communication with the Vipps Login OAuth 2.0 endpoints. Implement token exchange (authorization code → access token), userinfo fetch (retrieve personnummer and profile), and refresh token handling. Use the environment-aware config from task-002 and surface typed errors from task-001. The client must support both test and production Vipps environments and be injectable as a dependency for the Vipps Authentication Service.
Acceptance Criteria
Technical Requirements
Execution Context
Tier 1 - 540 tasks
Can start after Tier 0 completes
Implementation Notes
Use Dart's http package (or dio) with a custom HttpClient abstracted behind an interface for testability. Model all requests as value objects: VippsTokenRequest, VippsUserinfoRequest. Parse responses into typed Dart classes with fromJson factories — never access raw map keys outside the model. Compute expiresAt = DateTime.now().add(Duration(seconds: expiresIn)) at parse time.
The refresh token flow should check if the refresh token itself is expired before making the network call. PKCE code_verifier must be received from the caller (generated by the deep link/OAuth layer) — the client is stateless. Register as Provider
Testing Requirements
Unit tests using flutter_test with a mock HTTP client (MockClient or dio interceptor). Test cases: (1) successful token exchange returns correct VippsTokenResponse fields; (2) successful userinfo returns typed response with sub and nin; (3) HTTP 400 maps to InvalidGrantFailure; (4) HTTP 401 maps to UnauthorizedFailure; (5) network timeout maps to NetworkFailure; (6) HTTP 500 maps to ServerFailure; (7) missing nin in userinfo response maps to MissingPersonnummerFailure. Assert no raw exceptions escape. Assert User-Agent header is present in all requests.
Norway has multiple BankID broker providers (e.g., Signicat, Criipto, Nets) with different integration contracts, pricing, and WebView behavior. If the broker is not selected and contractually agreed before implementation begins, the BankIDProviderClient may need to be rewritten after initial build.
Mitigation & Contingency
Mitigation: Define a minimal broker interface abstraction (session initiation, WebView URL generation, assertion validation) before writing any provider-specific code. Confirm broker selection with Norse Digital Products before starting this epic.
Contingency: If the broker changes after implementation, the abstraction layer allows replacing the provider-specific implementation behind the same interface with a targeted rewrite rather than a full redesign.
Android deep link handling with custom URI schemes can conflict with existing app links (HTTPS-based) or fail silently on certain Android versions if the intent filter is misconfigured, causing OAuth callbacks to never reach the app and leaving users stranded on the Vipps or BankID page.
Mitigation & Contingency
Mitigation: Use HTTPS app links (Android App Links) rather than custom URI schemes where possible, as they are more reliable on modern Android. Test deep link receipt on Android 12+ explicitly during development, as this version changed intent flag requirements.
Contingency: Implement a polling fallback for Vipps (check auth status on app foreground) as a secondary callback mechanism if deep link receipt fails on specific Android configurations.
Vipps Login has a separate test environment (mt2.vipps.no) that requires distinct test merchant credentials which must be applied for separately. If test credentials are delayed, integration testing of the VippsApiClient cannot proceed, blocking the entire authentication flow.
Mitigation & Contingency
Mitigation: Apply for Vipps test merchant credentials at the start of the project sprint, not when implementation begins. Use Vipps' publicly documented mock token responses for unit tests to decouple unit testing from live credentials.
Contingency: Implement the VippsApiClient with full mock injection support so all service-layer tests can run against a stub client while waiting for official test credentials.