Authentication Methods
The app supports three authentication modes:Email/Password
Standard login with optional two-factor authentication (MFA)
SSO (OAuth 2.0)
Sign in with Google or other configured identity providers
API Key
Authenticate using a personal API key
Email/Password Authentication
Login Flow
The standard login process follows these steps:Two-Factor Authentication (MFA)
When MFA is enabled on a user account:Submit OTP Code
User enters the OTP from their authenticator app. The app retries login with the code:
MFA users cannot use SSO authentication on mobile. They must sign in with email and password.
SSO Authentication (OAuth 2.0)
The mobile app supports SSO through configured identity providers (e.g., Google).SSO Login Flow
Server Handles SSO
On the backend,
SessionsController#mobile_sso_start (sessions_controller.rb:117-143):- Validates the provider is configured
- Verifies device information is present
- Stores device info in session:
- Renders auto-submitting form to POST to OmniAuth
User Authenticates with IdP
User completes authentication with their identity provider (e.g., Google login).
OmniAuth Callback
Backend receives callback at
SessionsController#openid_connect (sessions_controller.rb:145-210):- Validates OIDC identity exists
- Checks if this is a mobile SSO flow (
session[:mobile_sso].present?) - If MFA is required, returns error (MFA not supported for mobile SSO)
- Calls
handle_mobile_sso_callback(sessions_controller.rb:244-274):- Creates/updates MobileDevice record
- Issues Doorkeeper OAuth tokens
- Generates one-time authorization code
- Stores tokens in Redis cache (5-minute expiry)
Exchange Authorization Code
App exchanges the one-time code for tokens:Backend retrieves tokens from cache, returns them, and deletes the cache entry.
SSO Error Handling
Common SSO error scenarios:Account Not Linked
Account Not Linked
Error:
account_not_linkedCause: User’s identity provider account is not linked to a Sure account.Solution: User must first link their Google account from the web app:- Log into Sure web app
- Go to Settings → Connected Accounts
- Link Google account
- Retry mobile SSO
MFA Not Supported
MFA Not Supported
Error:
mfa_not_supportedCause: User has MFA enabled on their account.Solution: MFA users must sign in with email and password, not SSO.Invalid Provider
Invalid Provider
Error:
invalid_providerCause: SSO provider is not configured on the backend.Solution: Administrator must configure the provider in config/omniauth.yml or via database.Missing Device Info
Missing Device Info
Error:
missing_device_infoCause: Device information is incomplete.Solution: This is an app bug. Ensure DeviceService.getDeviceInfo() returns all required fields.API Key Authentication
For programmatic access or testing, users can authenticate with an API key:Generate API Key
Users create an API key from the web app:
- Settings → API Keys
- Click “Create New API Key”
- Copy the key (shown only once)
Token Management
Token Storage
Tokens are stored using Flutter Secure Storage:- iOS
- Android
Tokens are stored in the iOS Keychain:
- Encrypted by the system
- Tied to the app’s bundle ID
- Automatically deleted when app is uninstalled
- Survives app updates
Token Refresh
Access tokens expire after a configured duration (typically 1 hour). The app automatically refreshes them:Token Lifecycle
Device Management
Each mobile device is tracked on the backend:Device Information
Collected on every login:Backend Device Records
The backend creates/updates aMobileDevice record:
Authentication State
The app uses Provider for authentication state management:Using Auth State in UI
Logout
Logging out clears all authentication state:Logout only clears local data. Backend sessions remain active until they expire or are revoked.
Security Best Practices
Secure Storage
- Never store tokens in SharedPreferences
- Always use FlutterSecureStorage for sensitive data
- Tokens are encrypted at rest
Token Rotation
- Access tokens expire regularly (1 hour)
- Refresh tokens rotate on use
- Old tokens are immediately invalidated
Device Tracking
- Each device has a unique OAuth token
- Users can revoke device access remotely
- Monitor devices from web app
HTTPS Only
- Production requires HTTPS
- Certificate pinning (future enhancement)
- No tokens sent over unencrypted connections
Troubleshooting
Cannot login with valid credentials
Cannot login with valid credentials
Check:
- Backend server is running and accessible
- Correct backend URL in
lib/services/api_config.dart - Network connectivity (WiFi/cellular)
- View logs:
flutter logs
SSO redirect not working
SSO redirect not working
Check:
- Deep link scheme registered:
sureapp:// app_linkspackage configured inandroid/app/src/main/AndroidManifest.xmlandios/Runner/Info.plist- SSO provider configured on backend
- Account is linked in web app
Token refresh fails repeatedly
Token refresh fails repeatedly
Possible causes:
- Refresh token expired (user was inactive for extended period)
- Backend clock skew causing expiration calculation errors
- Refresh token revoked (user changed password)
API key authentication not working
API key authentication not working
Check:
- API key is valid (not revoked)
- API key has correct permissions
- Backend accepts
X-Api-Keyheader
Next Steps
- Review API Documentation for available endpoints
- Explore state management in
lib/providers/ - Implement custom authentication screens
- Add biometric authentication (future feature)
Related Files
Backend Controller
app/controllers/sessions_controller.rb - Handles web and mobile SSOAuth Service
mobile/lib/services/auth_service.dart - Mobile authentication logicAuth Provider
mobile/lib/providers/auth_provider.dart - State managementDevice Service
mobile/lib/services/device_service.dart - Device info collection