BankID & Vipps Authentication
Feature Detail
Description
This feature implements Norwegian national e-ID authentication via BankID and Vipps as the primary login method, with biometric (Face ID / fingerprint) as a fast re-authentication mechanism after initial setup. On first login, the user authenticates through BankID or Vipps, which returns a verified identity and optionally a national ID number (personnummer) that can be synced back to member systems. Subsequent sessions use device biometrics via the Biometric Auth Service, falling back to BankID/Vipps if biometrics fail. Dedicated screens handle each provider flow and biometric prompts.
Analysis
BankID and Vipps are the dominant trusted identity providers in Norway, and all three workshop organizations (NHF, Blindeforbundet, HLF) explicitly require them as the primary authentication path. Vipps login has a critical side-benefit: it can return the user's personnummer to member systems that currently lack it, resolving a longstanding data quality problem across organizations. Biometric re-authentication dramatically reduces friction for daily users — peer mentors logging activities multiple times per day benefit directly. This feature is foundational to user trust, regulatory compliance, and the app's value proposition as a professional-grade tool.
BankID and Vipps integration uses their respective OAuth2/OIDC flows via dedicated API Gateways. In Flutter, this is handled via in-app browser (flutter_web_auth_2 or similar) launching the provider's authentication URL and receiving a callback with tokens. Auth tokens are stored in the Auth Token Repository using Flutter Secure Storage. Biometric authentication uses local_auth package with platform-specific implementations (Face ID on iOS, fingerprint on Android), gating access to the stored Supabase session token rather than re-authenticating with the provider. The BankID and Vipps gateways must handle redirect URIs, token exchange, and error states including user cancellation and provider unavailability.
Dependencies
Definition of Done
User Stories (27)
As a As a user
I want I want to be able to enable, disable, or re-enroll biometric authentication from the app settings
So that So that I can control how I authenticate and update my biometric enrollment if my device or preferences change
- Given a user with biometrics enrolled, when they navigate to authentication settings, then they see their current status as 'Face ID enabled' (iOS) or 'Fingerprint enabled' (Android) with an option to disable
- Given a user who disables biometric authentication in settings, when they confirm the action, then the encrypted token reference is removed from Secure Storage and subsequent app launches go to the BankID/Vipps selection screen
- Given a user without biometrics enrolled, when they navigate to authentication settings, then they see an 'Enable biometric login' option that launches the enrollment flow on tap
- +3 more
As a As a user
I want I want to be able to enable, disable, or re-enroll biometric authentication from the app settings
So that So that I can control how I authenticate and update my biometric enrollment if my device or preferences change
- Given a user with biometrics enrolled, when they navigate to authentication settings, then they see their current status as 'Face ID enabled' (iOS) or 'Fingerprint enabled' (Android) with an option to disable
- Given a user who disables biometric authentication in settings, when they confirm the action, then the encrypted token reference is removed from Secure Storage and subsequent app launches go to the BankID/Vipps selection screen
- Given a user without biometrics enrolled, when they navigate to authentication settings, then they see an 'Enable biometric login' option that launches the enrollment flow on tap
- +3 more
As a As a user
I want I want to be able to enable, disable, or re-enroll biometric authentication from the app settings
So that So that I can control how I authenticate and update my biometric enrollment if my device or preferences change
- Given a user with biometrics enrolled, when they navigate to authentication settings, then they see their current status as 'Face ID enabled' (iOS) or 'Fingerprint enabled' (Android) with an option to disable
- Given a user who disables biometric authentication in settings, when they confirm the action, then the encrypted token reference is removed from Secure Storage and subsequent app launches go to the BankID/Vipps selection screen
- Given a user without biometrics enrolled, when they navigate to authentication settings, then they see an 'Enable biometric login' option that launches the enrollment flow on tap
- +3 more
As a As a user
I want I want to be automatically redirected to BankID or Vipps login if my biometric authentication fails or is unavailable
So that So that I am never locked out of the app due to biometric failure and can always reach my account through a trusted fallback method
- Given a biometric failure (hardware error, too many attempts, or OS-level biometric change), when the Biometric Auth Service receives a failure response, then the Biometric Auth Screen displays a friendly message and a prominent 'Use BankID or Vipps' button
- Given a user whose biometric credentials are invalidated (e.g., new fingerprint enrolled at OS level), when they attempt biometric login, then the app detects the invalidation, clears the stale biometric token reference, and presents the BankID/Vipps selection screen
- Given a user who completes BankID or Vipps authentication as a fallback, when the new session is established, then the app offers biometric re-enrollment before navigating to the home screen
- +2 more
As a As a user
I want I want the app to handle BankID or Vipps errors and my own cancellation gracefully with clear feedback
So that So that I understand what happened and can retry or choose a different login method without becoming confused or thinking the app has crashed
- Given a user who taps the back button or cancel within the BankID in-app browser, when the browser dismisses, then the app returns to the login screen with the message 'BankID login was cancelled' and no error dialog
- Given a Vipps token exchange failure (e.g., expired authorization code), when the Vipps API Gateway returns an error, then the Vipps Integration Service surfaces a message 'Login failed — please try again' with a retry button on the Vipps Login Screen
- Given a BankID provider outage, when the authorization endpoint is unreachable, then the app displays 'BankID is temporarily unavailable. Try Vipps instead or retry later' with both options visible
- +3 more
As a As a user
I want I want to remain logged in across app restarts without having to re-authenticate every time I open the app
So that So that I can quickly return to my tasks without interruption, while still having the security of biometric or BankID/Vipps re-authentication when the session expires
- Given a user who authenticated within the session lifetime period, when they reopen the app, then no authentication prompt is shown and they are taken directly to the home screen (subject to biometric check if enrolled)
- Given a user whose access token has expired but refresh token is valid, when the app restarts, then a silent token refresh is performed against Supabase before the home screen is shown, with no visible interruption to the user
- Given a user whose refresh token has expired, when the app restarts, then they are redirected to the login screen with a message 'Your session has expired — please log in again'
- +3 more
As a As a user
I want I want to enable Face ID or fingerprint authentication on my device after completing my first BankID or Vipps login
So that So that subsequent app sessions require only a quick biometric scan instead of going through the full BankID or Vipps flow every time
- Given a user who has just completed their first BankID or Vipps login, when the session is established, then the app presents a biometric enrollment prompt with a clear explanation of its purpose
- Given a user who accepts biometric enrollment, when they complete the biometric challenge successfully, then an encrypted token reference is stored in Flutter Secure Storage and enrollment is confirmed
- Given a user who declines biometric enrollment, when they dismiss the prompt, then the app proceeds to the home screen without enrolling and does not repeatedly prompt during the same session
- +3 more
As a As a user
I want I want to unlock the app using my Face ID or fingerprint on subsequent sessions
So that So that I can access the app instantly without repeating the full BankID or Vipps authentication flow each time
- Given a returning user with biometrics enrolled, when the app launches or returns from background after a timeout, then the biometric prompt is shown immediately without requiring the user to navigate to a login screen
- Given a user who passes the biometric challenge, when the stored session token is retrieved from Secure Storage, then the app navigates to the appropriate home screen within 2 seconds of biometric confirmation
- Given a user with an expired session token but valid refresh token, when biometrics succeed and session restoration is attempted, then the session is silently refreshed and the user is logged in without any visible interruption
- +3 more
As a As a user
I want I want my national ID number (personnummer) to be automatically synced to my organization's member record when it is available from Vipps login
So that So that my member profile is kept accurate and complete without requiring me to manually enter my personnummer in the app or on paper forms
- Given a Vipps login where the ID token contains a personnummer claim, when the Vipps Integration Service processes the token, then it checks the user's member record for an existing personnummer value
- Given a member record with no personnummer, when a personnummer is extracted from Vipps, then the member record is updated automatically and the sync is logged with a timestamp and source ('vipps-login')
- Given a member record with a matching personnummer, when the same value arrives from Vipps, then no update is performed and the event is silently logged as 'confirmed, no change'
- +3 more
As a As a user
I want I want to be automatically redirected to BankID or Vipps login if my biometric authentication fails or is unavailable
So that So that I am never locked out of the app due to biometric failure and can always reach my account through a trusted fallback method
- Given a biometric failure (hardware error, too many attempts, or OS-level biometric change), when the Biometric Auth Service receives a failure response, then the Biometric Auth Screen displays a friendly message and a prominent 'Use BankID or Vipps' button
- Given a user whose biometric credentials are invalidated (e.g., new fingerprint enrolled at OS level), when they attempt biometric login, then the app detects the invalidation, clears the stale biometric token reference, and presents the BankID/Vipps selection screen
- Given a user who completes BankID or Vipps authentication as a fallback, when the new session is established, then the app offers biometric re-enrollment before navigating to the home screen
- +2 more
As a As a user
I want I want the app to handle BankID or Vipps errors and my own cancellation gracefully with clear feedback
So that So that I understand what happened and can retry or choose a different login method without becoming confused or thinking the app has crashed
- Given a user who taps the back button or cancel within the BankID in-app browser, when the browser dismisses, then the app returns to the login screen with the message 'BankID login was cancelled' and no error dialog
- Given a Vipps token exchange failure (e.g., expired authorization code), when the Vipps API Gateway returns an error, then the Vipps Integration Service surfaces a message 'Login failed — please try again' with a retry button on the Vipps Login Screen
- Given a BankID provider outage, when the authorization endpoint is unreachable, then the app displays 'BankID is temporarily unavailable. Try Vipps instead or retry later' with both options visible
- +3 more
As a As a user
I want I want to remain logged in across app restarts without having to re-authenticate every time I open the app
So that So that I can quickly return to my tasks without interruption, while still having the security of biometric or BankID/Vipps re-authentication when the session expires
- Given a user who authenticated within the session lifetime period, when they reopen the app, then no authentication prompt is shown and they are taken directly to the home screen (subject to biometric check if enrolled)
- Given a user whose access token has expired but refresh token is valid, when the app restarts, then a silent token refresh is performed against Supabase before the home screen is shown, with no visible interruption to the user
- Given a user whose refresh token has expired, when the app restarts, then they are redirected to the login screen with a message 'Your session has expired — please log in again'
- +3 more
As a As a user
I want I want to enable Face ID or fingerprint authentication on my device after completing my first BankID or Vipps login
So that So that subsequent app sessions require only a quick biometric scan instead of going through the full BankID or Vipps flow every time
- Given a user who has just completed their first BankID or Vipps login, when the session is established, then the app presents a biometric enrollment prompt with a clear explanation of its purpose
- Given a user who accepts biometric enrollment, when they complete the biometric challenge successfully, then an encrypted token reference is stored in Flutter Secure Storage and enrollment is confirmed
- Given a user who declines biometric enrollment, when they dismiss the prompt, then the app proceeds to the home screen without enrolling and does not repeatedly prompt during the same session
- +3 more
As a As a user
I want I want to unlock the app using my Face ID or fingerprint on subsequent sessions
So that So that I can access the app instantly without repeating the full BankID or Vipps authentication flow each time
- Given a returning user with biometrics enrolled, when the app launches or returns from background after a timeout, then the biometric prompt is shown immediately without requiring the user to navigate to a login screen
- Given a user who passes the biometric challenge, when the stored session token is retrieved from Secure Storage, then the app navigates to the appropriate home screen within 2 seconds of biometric confirmation
- Given a user with an expired session token but valid refresh token, when biometrics succeed and session restoration is attempted, then the session is silently refreshed and the user is logged in without any visible interruption
- +3 more
As a As a user
I want I want my national ID number (personnummer) to be automatically synced to my organization's member record when it is available from Vipps login
So that So that my member profile is kept accurate and complete without requiring me to manually enter my personnummer in the app or on paper forms
- Given a Vipps login where the ID token contains a personnummer claim, when the Vipps Integration Service processes the token, then it checks the user's member record for an existing personnummer value
- Given a member record with no personnummer, when a personnummer is extracted from Vipps, then the member record is updated automatically and the sync is logged with a timestamp and source ('vipps-login')
- Given a member record with a matching personnummer, when the same value arrives from Vipps, then no update is performed and the event is silently logged as 'confirmed, no change'
- +3 more
As a As a user
I want I want to be automatically redirected to BankID or Vipps login if my biometric authentication fails or is unavailable
So that So that I am never locked out of the app due to biometric failure and can always reach my account through a trusted fallback method
- Given a biometric failure (hardware error, too many attempts, or OS-level biometric change), when the Biometric Auth Service receives a failure response, then the Biometric Auth Screen displays a friendly message and a prominent 'Use BankID or Vipps' button
- Given a user whose biometric credentials are invalidated (e.g., new fingerprint enrolled at OS level), when they attempt biometric login, then the app detects the invalidation, clears the stale biometric token reference, and presents the BankID/Vipps selection screen
- Given a user who completes BankID or Vipps authentication as a fallback, when the new session is established, then the app offers biometric re-enrollment before navigating to the home screen
- +2 more
As a As a user
I want I want the app to handle BankID or Vipps errors and my own cancellation gracefully with clear feedback
So that So that I understand what happened and can retry or choose a different login method without becoming confused or thinking the app has crashed
- Given a user who taps the back button or cancel within the BankID in-app browser, when the browser dismisses, then the app returns to the login screen with the message 'BankID login was cancelled' and no error dialog
- Given a Vipps token exchange failure (e.g., expired authorization code), when the Vipps API Gateway returns an error, then the Vipps Integration Service surfaces a message 'Login failed — please try again' with a retry button on the Vipps Login Screen
- Given a BankID provider outage, when the authorization endpoint is unreachable, then the app displays 'BankID is temporarily unavailable. Try Vipps instead or retry later' with both options visible
- +3 more
As a As a user
I want I want to remain logged in across app restarts without having to re-authenticate every time I open the app
So that So that I can quickly return to my tasks without interruption, while still having the security of biometric or BankID/Vipps re-authentication when the session expires
- Given a user who authenticated within the session lifetime period, when they reopen the app, then no authentication prompt is shown and they are taken directly to the home screen (subject to biometric check if enrolled)
- Given a user whose access token has expired but refresh token is valid, when the app restarts, then a silent token refresh is performed against Supabase before the home screen is shown, with no visible interruption to the user
- Given a user whose refresh token has expired, when the app restarts, then they are redirected to the login screen with a message 'Your session has expired — please log in again'
- +3 more
As a As a user
I want I want to enable Face ID or fingerprint authentication on my device after completing my first BankID or Vipps login
So that So that subsequent app sessions require only a quick biometric scan instead of going through the full BankID or Vipps flow every time
- Given a user who has just completed their first BankID or Vipps login, when the session is established, then the app presents a biometric enrollment prompt with a clear explanation of its purpose
- Given a user who accepts biometric enrollment, when they complete the biometric challenge successfully, then an encrypted token reference is stored in Flutter Secure Storage and enrollment is confirmed
- Given a user who declines biometric enrollment, when they dismiss the prompt, then the app proceeds to the home screen without enrolling and does not repeatedly prompt during the same session
- +3 more
As a As a user
I want I want to unlock the app using my Face ID or fingerprint on subsequent sessions
So that So that I can access the app instantly without repeating the full BankID or Vipps authentication flow each time
- Given a returning user with biometrics enrolled, when the app launches or returns from background after a timeout, then the biometric prompt is shown immediately without requiring the user to navigate to a login screen
- Given a user who passes the biometric challenge, when the stored session token is retrieved from Secure Storage, then the app navigates to the appropriate home screen within 2 seconds of biometric confirmation
- Given a user with an expired session token but valid refresh token, when biometrics succeed and session restoration is attempted, then the session is silently refreshed and the user is logged in without any visible interruption
- +3 more
As a As a user
I want I want my national ID number (personnummer) to be automatically synced to my organization's member record when it is available from Vipps login
So that So that my member profile is kept accurate and complete without requiring me to manually enter my personnummer in the app or on paper forms
- Given a Vipps login where the ID token contains a personnummer claim, when the Vipps Integration Service processes the token, then it checks the user's member record for an existing personnummer value
- Given a member record with no personnummer, when a personnummer is extracted from Vipps, then the member record is updated automatically and the sync is logged with a timestamp and source ('vipps-login')
- Given a member record with a matching personnummer, when the same value arrives from Vipps, then no update is performed and the event is silently logged as 'confirmed, no change'
- +3 more
As a As a user
I want I want to log in to the app using my BankID
So that So that my identity is verified using Norway's trusted national e-ID, meeting regulatory requirements and giving organizations confidence in who is accessing sensitive data
- Given a user on the login screen, when they tap 'Log in with BankID', then an in-app browser opens to the BankID authorization URL with a valid PKCE code challenge
- Given a user who completes the BankID authentication flow, when the provider redirects with an authorization code, then the app exchanges the code for tokens and creates a valid Supabase session
- Given a successful BankID authentication, when the session is established, then the authenticated user's name and verified identity are stored and the user is navigated to the appropriate home screen
- +3 more
As a As a user
I want I want to log in to the app using my Vipps account
So that So that I can authenticate with the payment app already installed on my phone, avoiding the need for a separate BankID setup, while also enabling automatic sync of my national ID number to the membership system
- Given a user on the login screen, when they tap 'Log in with Vipps', then an in-app browser opens to the Vipps Login authorization URL with correct scopes including openid, phone, and national_id
- Given a user who completes Vipps authentication, when the provider redirects with an authorization code, then the app exchanges the code for tokens and creates a valid Supabase session within 5 seconds
- Given a Vipps login that returns a personnummer in the token claims, when the token is processed, then the Vipps Integration Service attempts to sync the personnummer to the relevant member system and logs the sync outcome
- +3 more
As a As a user
I want I want to log in to the app using my BankID
So that So that my identity is verified using Norway's trusted national e-ID, meeting regulatory requirements and giving organizations confidence in who is accessing sensitive data
- Given a user on the login screen, when they tap 'Log in with BankID', then an in-app browser opens to the BankID authorization URL with a valid PKCE code challenge
- Given a user who completes the BankID authentication flow, when the provider redirects with an authorization code, then the app exchanges the code for tokens and creates a valid Supabase session
- Given a successful BankID authentication, when the session is established, then the authenticated user's name and verified identity are stored and the user is navigated to the appropriate home screen
- +3 more
As a As a user
I want I want to log in to the app using my Vipps account
So that So that I can authenticate with the payment app already installed on my phone, avoiding the need for a separate BankID setup, while also enabling automatic sync of my national ID number to the membership system
- Given a user on the login screen, when they tap 'Log in with Vipps', then an in-app browser opens to the Vipps Login authorization URL with correct scopes including openid, phone, and national_id
- Given a user who completes Vipps authentication, when the provider redirects with an authorization code, then the app exchanges the code for tokens and creates a valid Supabase session within 5 seconds
- Given a Vipps login that returns a personnummer in the token claims, when the token is processed, then the Vipps Integration Service attempts to sync the personnummer to the relevant member system and logs the sync outcome
- +3 more
As a As a user
I want I want to log in to the app using my BankID
So that So that my identity is verified using Norway's trusted national e-ID, meeting regulatory requirements and giving organizations confidence in who is accessing sensitive data
- Given a user on the login screen, when they tap 'Log in with BankID', then an in-app browser opens to the BankID authorization URL with a valid PKCE code challenge
- Given a user who completes the BankID authentication flow, when the provider redirects with an authorization code, then the app exchanges the code for tokens and creates a valid Supabase session
- Given a successful BankID authentication, when the session is established, then the authenticated user's name and verified identity are stored and the user is navigated to the appropriate home screen
- +3 more
As a As a user
I want I want to log in to the app using my Vipps account
So that So that I can authenticate with the payment app already installed on my phone, avoiding the need for a separate BankID setup, while also enabling automatic sync of my national ID number to the membership system
- Given a user on the login screen, when they tap 'Log in with Vipps', then an in-app browser opens to the Vipps Login authorization URL with correct scopes including openid, phone, and national_id
- Given a user who completes Vipps authentication, when the provider redirects with an authorization code, then the app exchanges the code for tokens and creates a valid Supabase session within 5 seconds
- Given a Vipps login that returns a personnummer in the token claims, when the token is processed, then the Vipps Integration Service attempts to sync the personnummer to the relevant member system and logs the sync outcome
- +3 more