critical priority low complexity infrastructure pending backend specialist Tier 0

Acceptance Criteria

A sealed AuthEnvironmentConfig class (or equivalent Dart sealed/abstract) exposes typed fields: vippsBaseUrl, vippsClientId, vippsRedirectUri, bankIdEdgeFunctionUrl — no raw strings outside this class
A VippsEndpointConfig value object is produced containing tokenEndpoint, userinfoEndpoint, and authorizationEndpoint derived from vippsBaseUrl
A BankIdEndpointConfig value object is produced containing initiateSessionEndpoint and assertionEndpoint derived from bankIdEdgeFunctionUrl
Test environment resolves to Vipps test URLs (https://apitest.vipps.no) and a Supabase staging Edge Function URL; production resolves to live Vipps and production Edge Function URLs
Configuration is injected via Riverpod provider (or BLoC dependency injection) — no static globals or singletons accessed directly in API clients
Flutter --dart-define or environment-specific flavors (dev/staging/prod) drive config selection; no if-else on string literals inside production code paths
Unit test confirms correct URL resolution for both test and production environments without network calls
No secrets (client secrets, API keys) are stored in this config module; only public-facing base URLs and client IDs
Config objects are immutable (final fields, const constructors where possible)

Technical Requirements

frameworks
Flutter
Riverpod
Dart
apis
Vipps Login API (test and production base URLs)
Supabase Edge Functions (staging and production base URLs)
performance requirements
Config resolution must be synchronous — no async initialization at app startup
Config objects must be constructed once and cached via Riverpod provider
security requirements
No client secrets or Supabase service role keys in this config module
Flutter --dart-define values are compile-time constants, not runtime reads from files
Never log config values in production builds; use kDebugMode guards
redirectUri must use the app's registered custom URI scheme, not an http:// scheme

Execution Context

Execution Tier
Tier 0

Tier 0 - 440 tasks

Implementation Notes

Use Flutter flavors or --dart-define-from-file for environment switching. Define a sealed class AuthEnvironmentConfig with two concrete implementations: TestAuthEnvironmentConfig and ProductionAuthEnvironmentConfig. Expose a Riverpod Provider registered at app bootstrap based on the compile-time constant. Derived endpoint configs (VippsEndpointConfig, BankIdEndpointConfig) are computed getters on the base class.

This ensures both API clients receive typed, correct URLs with zero string duplication. Avoid the antipattern of reading environment from a .env file at runtime — this is a mobile app, use compile-time injection.

Testing Requirements

Unit tests using flutter_test. Two test cases minimum: (1) test environment returns correct Vipps test base URL and staging Edge Function URL; (2) production environment returns correct live URLs. Use a factory or mock flavor injection to avoid needing actual --dart-define at test time. Assert all derived endpoint paths are correctly appended (e.g., /v2/login/token).

No integration or network calls in these tests.

Component
Vipps API Client
infrastructure medium
Epic Risks (3)
high impact high prob dependency

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.

high impact medium prob technical

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.

medium impact medium prob dependency

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.