Skip to content

[FOSSOVERFLOW-26] migrate auth+login to supabase from firebase#3

Open
Ashish-Kumar-Dash wants to merge 2 commits intoOpenLake:mainfrom
Ashish-Kumar-Dash:backend-akd
Open

[FOSSOVERFLOW-26] migrate auth+login to supabase from firebase#3
Ashish-Kumar-Dash wants to merge 2 commits intoOpenLake:mainfrom
Ashish-Kumar-Dash:backend-akd

Conversation

@Ashish-Kumar-Dash
Copy link

@Ashish-Kumar-Dash Ashish-Kumar-Dash commented Feb 15, 2026

Migrate authentication from Firebase to Supabase

Overview:
Complete migration from Firebase to Supabase backend with enhanced authentication, clean architecture, and production-ready Android configuration.

Key Changes:

Backend Migration:

  • ❌ Removed Firebase (firebase_core, firebase_auth, cloud_firestore)
  • ✅ Integrated Supabase Flutter SDK (^2.8.0)
  • ✅ PostgreSQL-based user profiles with RLS policies
  • ✅ Session persistence and auto-login

Authentication Features:

  • Email/password signup with validation
  • Email/password login
  • Google OAuth integration with token-based auth
  • Auto profile creation in database
  • Proper error handling with user-friendly messages
  • Logout functionality

Architecture:

  • AuthService - Clean service layer for all auth operations
  • AuthProvider - Riverpod state management
  • AuthWrapper - Handles navigation based on auth state
  • Separation of concerns between UI and business logic

Android Configuration Fixes:

  • Added INTERNET and ACCESS_NETWORK_STATE permissions
  • Configured deep links for OAuth callbacks (io.supabase.getwelplus://login-callback)
  • Added package visibility queries for Android 11+ (browser, Google Play Services)
  • Set explicit minSdk=21 (Supabase requirement)
  • Enabled MultiDex support
  • Updated play-services-auth to 21.1.0
  • Fixed Google Sign-In scopes configuration

Files Modified:

  • main.dart - Supabase initialization
  • auth_service.dart - Complete rewrite for Supabase
  • login_page.dart - Google OAuth button + error handling
  • signup_page.dart - Profile creation flow
  • lib/pages/homepage.dart - Migrated from Firestore to Supabase
  • build.gradle.kts - Android config fixes
  • AndroidManifest.xml - Permissions + deep links
  • pubspec.yaml - Dependency swap
    @Asp-irin kindly review

Summary by CodeRabbit

  • New Features

    • Added Google Sign-In authentication option for faster account creation and login.
    • Enabled OAuth callback support for seamless authentication flows.
  • Refactor

    • Migrated authentication backend from Firebase to Supabase for improved performance and flexibility.
    • Enhanced security with updated network and permission configurations.
    • Redesigned homepage with improved navigation and user profile integration.

@coderabbitai
Copy link

coderabbitai bot commented Feb 15, 2026

Walkthrough

This pull request migrates the Flutter application's authentication backend from Firebase to Supabase. Changes include replacing Firebase dependencies with Supabase packages, updating authentication service implementations, reconfiguring Android platform files, adding OAuth deep links, and updating platform-specific plugin registrations across Linux, macOS, and Windows.

Changes

Cohort / File(s) Summary
Dependency & App Initialization
pubspec.yaml, flutter_app/lib/main.dart
Removed Firebase dependencies (firebase_core, firebase_auth, cloud_firestore) and added Supabase (supabase_flutter, google_sign_in, app_links). Updated main.dart to initialize Supabase with URL and anonKey before running the app.
Core Authentication Service
flutter_app/lib/auth/auth_service.dart, flutter_app/lib/auth/auth_provider.dart
Replaced Firebase Auth with Supabase client integration. Added new getters (currentUser, authStateChanges, isLoggedIn) and methods (signUp, signIn, signInWithGoogle, signOut, getUserProfile, updateUserProfile, resetPassword). Updated provider definitions to stream AuthState instead of User?.
Authentication UI Components
flutter_app/lib/auth/auth_wrapper.dart, flutter_app/lib/auth/login_page.dart, flutter_app/lib/auth/signup_page.dart
Migrated UI pages from Firebase to Supabase authentication. Added dedicated handlers (_handleLogin, _handleSignup, _handleGoogleSignIn) with loading and error states. Updated stream sources to use Supabase auth state changes and added Google Sign-In button to login page.
Android Platform Configuration
flutter_app/android/build.gradle.kts, flutter_app/android/app/build.gradle.kts, flutter_app/android/app/src/main/AndroidManifest.xml, flutter_app/android/app/src/main/res/xml/network_security_config.xml
Removed Google Services Gradle plugin. Added multiDexEnabled for large apps. Added INTERNET and ACCESS_NETWORK_STATE permissions. Configured Supabase OAuth deep links (io.supabase.getwelplus scheme) with autoVerify intent-filter. Created network security configuration to allow Supabase domain connections.
Home Page Refactor
flutter_app/lib/pages/homepage.dart
Converted from stateless to stateful ConsumerStatefulWidget. Replaced Firestore data streaming with Supabase profile loading in initState. Added redesigned AppBar, Drawer with user profile, and refactored feature cards (Online Meet, Track Mood, Guided Meditation, Book a Session, Stress Check, Psychology Articles, Calm Music) with navigation to respective pages.
Platform Plugin Registrations
flutter_app/linux/flutter/generated_plugin_registrant.cc, flutter_app/linux/flutter/generated_plugins.cmake, flutter_app/macos/Flutter/GeneratedPluginRegistrant.swift, flutter_app/windows/flutter/generated_plugin_registrant.cc, flutter_app/windows/flutter/generated_plugins.cmake
Updated platform-specific plugin registrations, removing Firebase plugins (cloud_firestore, firebase_auth, firebase_core) and adding Supabase-compatible plugins (GTK, UrlLauncher on Linux; AppLinks, Google Sign-In, Shared Preferences, UrlLauncher on macOS/Windows).
Type System & Configuration
flutter_app/lib/core/theme/app_theme.dart, .vscode/settings.json
Added explicit ThemeData return type annotations to AppTheme static getters (light, dark). Added VSCode settings for Java configuration and CMake source directory.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant App as Flutter App
    participant AuthService as AuthService
    participant Supabase as Supabase Auth
    participant DB as Supabase DB

    User->>App: Enter email/password
    App->>AuthService: signUp(email, password, name)
    AuthService->>Supabase: signUp with credentials
    activate Supabase
    Supabase-->>AuthService: AuthResponse with user
    deactivate Supabase
    AuthService->>DB: Create profile in users table
    activate DB
    DB-->>AuthService: Profile created
    deactivate DB
    AuthService-->>App: Success
    App->>User: Navigate to home
Loading
sequenceDiagram
    participant User
    participant App as Flutter App
    participant AuthService as AuthService
    participant GoogleSignIn as GoogleSignIn
    participant Supabase as Supabase Auth
    participant DB as Supabase DB

    User->>App: Tap Google Sign-In
    App->>AuthService: signInWithGoogle()
    AuthService->>GoogleSignIn: Initiate Google OAuth
    activate GoogleSignIn
    GoogleSignIn-->>AuthService: ID token
    deactivate GoogleSignIn
    AuthService->>Supabase: signInWithIdToken(token)
    activate Supabase
    Supabase-->>AuthService: AuthResponse with user
    deactivate Supabase
    AuthService->>DB: Check if profile exists
    alt Profile missing
        AuthService->>DB: Create profile with Google name
        activate DB
        DB-->>AuthService: Profile created
        deactivate DB
    end
    AuthService-->>App: Success
    App->>User: Navigate to home
Loading
sequenceDiagram
    participant App as Flutter App
    participant AuthWrapper as AuthWrapper
    participant Supabase as Supabase Auth
    participant HomePage as HomePage

    App->>AuthWrapper: Initialize
    AuthWrapper->>Supabase: Listen to auth state changes
    activate Supabase
    Supabase-->>AuthWrapper: Emit AuthState (session present)
    deactivate Supabase
    AuthWrapper->>HomePage: Render home UI
    activate HomePage
    HomePage->>Supabase: Load user profile
    Supabase-->>HomePage: Return profile data
    HomePage->>HomePage: Render with user name
    deactivate HomePage
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • project initialised with basic ui and auth #1: Introduces initial Firebase authentication implementation that this PR completely replaces with Supabase, affecting the same auth service layer, UI components, and platform configurations.

Poem

🐰 Hop, hop, migrations away!
Firebase fades, Supabase saves the day,
From old auth trees to clouds so new,
Deep links and sign-ins, OAuth flows through,
A rabbit's delight—authentication anew! 🎉

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the primary change: migrating authentication from Firebase to Supabase, which is the core objective of this comprehensive pull request.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

🤖 Fix all issues with AI agents
In `@flutter_app/android/app/build.gradle.kts`:
- Line 27: The comment next to the minSdk assignment is misleading because
minSdk is set from flutter.minSdkVersion (the Flutter default) rather than an
explicit Supabase requirement; either hardcode the required minimum (e.g., set
minSdk = 21) if Supabase demands a specific SDK level, or keep
flutter.minSdkVersion and remove the "Required for Supabase" comment to avoid
confusion — update the minSdk line and/or comment accordingly in the build file
where minSdk and flutter.minSdkVersion are referenced.

In `@flutter_app/android/app/src/main/AndroidManifest.xml`:
- Around line 32-39: Remove the ineffective android:autoVerify="true" attribute
from the <intent-filter> (autoVerify only applies to http/https App Links) and
delete the stale comment "<!-- Replace with your actual deep link scheme -->"
since the scheme is already set (android:scheme="io.supabase.getwelplus" and
android:host="login-callback"); keep the intent-filter and <data> element as-is
so the custom URI scheme continues to work.

In `@flutter_app/android/app/src/main/res/xml/network_security_config.xml`:
- Around line 9-16: Remove the redundant <domain-config> block that duplicates
the <base-config> (same cleartextTrafficPermitted and identical trust-anchors)
so it has no effect; instead, move user certificate trust (certificates
src="user") into the <debug-overrides> section so user-added certs are only
allowed in debug mode and keep the base-config with system certs only, updating
the network_security_config.xml elements <base-config>, <debug-overrides>, and
any existing <domain-config> entries (e.g., the supabase.co domain-config)
accordingly.
- Around line 3-8: The network_security_config currently trusts user-installed
CAs in production by including <certificates src="user" /> inside the
base-config; remove or relocate that entry so release builds do not trust user
CAs and instead add a <debug-overrides> section that contains <trust-anchors>
with <certificates src="user" /> for debugging only (use the existing
base-config for system certs only). Update the network_security_config.xml to
keep <base-config cleartextTrafficPermitted="false"> with only <certificates
src="system" /> and move <certificates src="user" /> under a <debug-overrides>
block to ensure user CA trust is limited to debug builds.

In `@flutter_app/lib/auth/auth_provider.dart`:
- Around line 15-18: currentUserProvider currently reads a snapshot
(ref.read(authServiceProvider).currentUser) and never updates; change it to
derive from the AuthService's reactive auth-state stream by using a
StreamProvider (or Provider that ref.watch(...)s the service's stream) instead
of ref.read, e.g., have currentUserProvider subscribe to the AuthService's
stream property (authStateStream / authStateChanges / currentUserStream) so it
emits updated User? values on login/logout; update references to
currentUserProvider accordingly.

In `@flutter_app/lib/auth/auth_service.dart`:
- Around line 64-67: The hard-coded OAuth client ID in signInWithGoogle (the
webClientId constant) should be moved to an environment-level configuration and
loaded at runtime; replace the inline string with a call that reads from your
chosen config source (e.g., Dart compile-time defines via
String.fromEnvironment, a runtime .env loader like flutter_dotenv, or your
backend/Supabase-configured OAuth value) and update signInWithGoogle to use that
config value and fail-fast with a clear error if the env value is missing;
ensure you document the required env key and remove the literal from source
control.
- Around line 83-85: Replace the raw string throw with a typed AuthException so
callers using "on AuthException catch (e)" can handle it: in auth_service.dart
(inside the code path that checks accessToken and idToken) throw an
AuthException with a clear message (e.g., "Google authentication tokens not
found") instead of throwing a String; ensure you import or reference the
AuthException class used by login_page.dart and preserve the original message
when constructing the exception.
- Around line 29-39: The profile insertion currently swallows all errors in the
try/catch around _supabase.from('users').insert(...); change the catch to handle
PostgrestException specifically: if the error indicates a duplicate key (unique
constraint violation) then ignore/return, otherwise log the full error (or
rethrow) so calling code can detect failed profile creation; ensure you
reference the insert call on _supabase and the caught PostgrestException
(dbError) so the fix is applied in the same method that inserts the user
profile.

In `@flutter_app/lib/core/theme/app_theme.dart`:
- Line 1: The file imports Flutter internals via
"package:flutter/src/material/theme_data.dart"; change that to use the public
barrel export (e.g., import from package:flutter/material.dart) so ThemeData and
related symbols are referenced from the supported public API; update the import
line that currently references theme_data.dart and ensure any usages of
ThemeData in this file remain the same.

In `@flutter_app/lib/main.dart`:
- Around line 11-15: Replace the hardcoded Supabase credentials passed into
Supabase.initialize (the url and anonKey arguments) with environment-configured
values: read them via compile-time dart-define (e.g., const
String.fromEnvironment('SUPABASE_URL') / 'SUPABASE_ANON_KEY') or via
flutter_dotenv (dotenv.env['SUPABASE_URL'] / dotenv.env['SUPABASE_ANON_KEY']),
and update the Supabase.initialize call to use those variables; ensure you
document the required --dart-define keys (SUPABASE_URL, SUPABASE_ANON_KEY) or
add .env handling so secrets are not committed in main.dart and can be injected
at build/run time.

In `@flutter_app/lib/pages/homepage.dart`:
- Around line 35-54: In _loadUserProfile ensure isLoading is always cleared and
errors are logged: if Supabase.instance.client.auth.currentUser?.id is null,
call setState to set isLoading = false (and leave userProfile unchanged) instead
of skipping, and in the catch block log the exception (e.g., using debugPrint or
your logger) before setting isLoading = false; keep the mounted checks and
update userProfile only when authService.getUserProfile succeeds.
🧹 Nitpick comments (10)
.vscode/settings.json (1)

1-4: Avoid committing user-specific absolute paths in workspace settings.

The "cmake.sourceDirectory" value is an absolute Windows path tied to one developer’s machine, which will break for others and in CI. Prefer a relative path (e.g., ${workspaceFolder}/linux) or move this setting to a local, untracked VS Code settings file.

♻️ Proposed fix
 {
     "java.configuration.updateBuildConfiguration": "interactive",
-    "cmake.sourceDirectory": "C:/Users/akd24/Documents/GetWelPlus/flutter_app/linux"
+    "cmake.sourceDirectory": "${workspaceFolder}/linux"
 }
flutter_app/android/app/build.gradle.kts (1)

31-31: multiDexEnabled and the multidex dependency are unnecessary with minSdk ≥ 21.

Since flutter.minSdkVersion resolves to 21 (Android 5.0 / ART), the runtime natively supports multiple DEX files. Both multiDexEnabled = true and the androidx.multidex:multidex dependency can be removed without impact.

♻️ Suggested cleanup
-        multiDexEnabled = true  // Required for apps with many dependencies
-    implementation("androidx.multidex:multidex:2.0.1")

Also applies to: 49-49

flutter_app/lib/pages/homepage.dart (1)

24-27: Refactor to use Riverpod's authServiceProvider instead of direct instantiation.

The _HomePageState extends ConsumerState, which provides access to the ref object. Replace final authService = AuthService(); with ref.watch(authServiceProvider) or ref.read(authServiceProvider) depending on whether the value needs to be reactive or accessed once. This aligns with the app's existing Riverpod setup in auth_provider.dart and improves testability and dependency injection.

flutter_app/lib/auth/login_page.dart (3)

30-61: isLoading is never reset on successful login.

On the success path (line 48 returns, execution continues past await), isLoading remains true. This works because AuthWrapper disposes this widget on session change, but if there's any delay or if the widget remains mounted, the UI stays stuck on a spinner with no way out.

Consider resetting isLoading = false in a finally block to be defensive:

Proposed fix
     try {
       await authService.signIn(
         email: email.text.trim(),
         password: pass.text.trim(),
       );
       // Navigation handled by AuthWrapper
     } on AuthException catch (e) {
       setState(() {
         errorMessage = e.message;
-        isLoading = false;
       });
     } catch (e) {
       setState(() {
         errorMessage = 'Login failed. Please try again.';
-        isLoading = false;
       });
+    } finally {
+      if (mounted) {
+        setState(() => isLoading = false);
+      }
     }

36-42: formkey is unused — Form validation is bypassed.

A GlobalKey<FormState> is declared (line 18) and assigned to the Form widget (line 98), but formkey.currentState!.validate() is never called. Validation is done manually at line 36. Either leverage Form validators on Inputfield widgets (the idiomatic Flutter approach) or drop the Form/formkey entirely.

Also applies to: 97-98


63-89: Same isLoading issue applies to _handleGoogleSignIn.

On a successful Google sign-in (line 77 falls through to the end), isLoading stays true. Apply the same finally + mounted guard as suggested for _handleLogin.

flutter_app/lib/auth/signup_page.dart (1)

99-100: Redundant consecutive spacing.

Two SizedBox widgets with height: 20 and height: 10 appear back-to-back, which looks unintentional. Consolidate into a single SizedBox(height: 30) or remove one.

-                const SizedBox(height: 20),
-                const SizedBox(height: 10),
+                const SizedBox(height: 30),
flutter_app/lib/auth/auth_service.dart (2)

35-36: Client-side created_at timestamps are unreliable.

DateTime.now().toIso8601String() uses the device clock, which may be wrong or manipulated. Prefer a server-side default on the created_at column (e.g., DEFAULT now() in your Supabase table definition) and omit created_at from the insert payload entirely.

Also applies to: 105-107


48-61: Redundant try/catch/rethrow blocks add noise.

signIn, signOut, getUserProfile, updateUserProfile, and resetPassword all catch and immediately rethrow without adding any context or logging. These can be simplified by removing the try/catch entirely:

Example for signIn
   Future<AuthResponse> signIn({
     required String email,
     required String password,
   }) async {
-    try {
-      return await _supabase.auth.signInWithPassword(
-        email: email,
-        password: password,
-      );
-    } catch (e) {
-      rethrow;
-    }
+    return await _supabase.auth.signInWithPassword(
+      email: email,
+      password: password,
+    );
   }

Apply the same simplification to signOut, getUserProfile, updateUserProfile, and resetPassword.

Also applies to: 117-159

flutter_app/lib/auth/auth_provider.dart (1)

6-13: Wire the pages to use the providers or remove them if not needed.

authServiceProvider and authStateProvider are unused. AuthWrapper directly accesses Supabase.instance.client.auth.onAuthStateChange, and both LoginPage and SignupPage instantiate AuthService() directly, bypassing the provider layer entirely. Either refactor these pages to use ConsumerWidget/ConsumerStatefulWidget and access the providers via ref.watch(), or remove the providers until they are needed.

// You can update the following values to match your application needs.
// For more information, see: https://flutter.dev/to/review-gradle-config.
minSdk = flutter.minSdkVersion
minSdk = flutter.minSdkVersion // Required for Supabase
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Misleading comment — this just uses Flutter's default minSdkVersion.

The comment "Required for Supabase" suggests a deliberate override, but flutter.minSdkVersion is Flutter's default (currently 21). If Supabase requires a specific minimum SDK, hardcode it (e.g., minSdk = 21). If not, remove the comment to avoid confusion.

🤖 Prompt for AI Agents
In `@flutter_app/android/app/build.gradle.kts` at line 27, The comment next to the
minSdk assignment is misleading because minSdk is set from flutter.minSdkVersion
(the Flutter default) rather than an explicit Supabase requirement; either
hardcode the required minimum (e.g., set minSdk = 21) if Supabase demands a
specific SDK level, or keep flutter.minSdkVersion and remove the "Required for
Supabase" comment to avoid confusion — update the minSdk line and/or comment
accordingly in the build file where minSdk and flutter.minSdkVersion are
referenced.

Comment on lines +32 to +39
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Replace with your actual deep link scheme -->
<data
android:scheme="io.supabase.getwelplus"
android:host="login-callback" />
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Android autoVerify custom URI schemes intent-filter

💡 Result:

android:autoVerify="true" does not work for custom URI schemes (e.g., myapp://...). Auto-verification is only for Android App Links, which are web URLs using http/https and are verified via a website-hosted Digital Asset Links file (/.well-known/assetlinks.json). Also, an intent-filter considered for verification must not declare any other schemes besides http/https. [1], [4], [5]

What to do instead

  • If you need “no chooser dialog” deep links: use HTTPS App Links with android:autoVerify="true" + assetlinks.json. [1], [4]
  • If you must use a custom scheme (myapp://): you can still declare it in an intent-filter, but it can’t be verified; if another app registers the same scheme, Android may show the chooser. [6]

Common setup pattern (recommended)

  • One intent-filter for verified links:
    • https://yourdomain/... with android:autoVerify="true" (and assetlinks.json). [1], [4]
  • A separate intent-filter for legacy/custom deep links:
    • myapp://... without expecting verification. [6]

Two minor issues with the deep link intent-filter.

  1. android:autoVerify="true" is ineffective with custom URI schemes. Auto-verification is an Android App Links feature that only works with http/https schemes and requires a /.well-known/assetlinks.json file on the verified domain. For the custom scheme io.supabase.getwelplus, this attribute is silently ignored. Remove it to avoid confusion.

  2. Line 36: Stale template comment. The comment <!-- Replace with your actual deep link scheme --> should be removed since the scheme is already configured.

Proposed fix
-            <intent-filter android:autoVerify="true">
+            <intent-filter>
                 <action android:name="android.intent.action.VIEW" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.BROWSABLE" />
-                <!-- Replace with your actual deep link scheme -->
                 <data
                     android:scheme="io.supabase.getwelplus"
                     android:host="login-callback" />
             </intent-filter>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Replace with your actual deep link scheme -->
<data
android:scheme="io.supabase.getwelplus"
android:host="login-callback" />
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:scheme="io.supabase.getwelplus"
android:host="login-callback" />
</intent-filter>
🤖 Prompt for AI Agents
In `@flutter_app/android/app/src/main/AndroidManifest.xml` around lines 32 - 39,
Remove the ineffective android:autoVerify="true" attribute from the
<intent-filter> (autoVerify only applies to http/https App Links) and delete the
stale comment "<!-- Replace with your actual deep link scheme -->" since the
scheme is already set (android:scheme="io.supabase.getwelplus" and
android:host="login-callback"); keep the intent-filter and <data> element as-is
so the custom URI scheme continues to work.

Comment on lines +3 to +8
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Trusting user-installed certificates in production is a security risk.

Including <certificates src="user" /> in <base-config> means release builds will trust user-installed CA certificates, re-enabling MITM proxy attacks that Android 7+ (API 24) disabled by default. User CA trust should be limited to debug builds via <debug-overrides>.

🔒 Proposed fix: restrict user certs to debug builds
 <network-security-config>
     <base-config cleartextTrafficPermitted="false">
         <trust-anchors>
             <certificates src="system" />
-            <certificates src="user" />
         </trust-anchors>
     </base-config>
-    <!-- Allow connections to Supabase in debug mode -->
-    <domain-config cleartextTrafficPermitted="false">
-        <domain includeSubdomains="true">supabase.co</domain>
-        <trust-anchors>
-            <certificates src="system" />
-            <certificates src="user" />
-        </trust-anchors>
-    </domain-config>
+    <debug-overrides>
+        <trust-anchors>
+            <certificates src="user" />
+        </trust-anchors>
+    </debug-overrides>
 </network-security-config>
🤖 Prompt for AI Agents
In `@flutter_app/android/app/src/main/res/xml/network_security_config.xml` around
lines 3 - 8, The network_security_config currently trusts user-installed CAs in
production by including <certificates src="user" /> inside the base-config;
remove or relocate that entry so release builds do not trust user CAs and
instead add a <debug-overrides> section that contains <trust-anchors> with
<certificates src="user" /> for debugging only (use the existing base-config for
system certs only). Update the network_security_config.xml to keep <base-config
cleartextTrafficPermitted="false"> with only <certificates src="system" /> and
move <certificates src="user" /> under a <debug-overrides> block to ensure user
CA trust is limited to debug builds.

Comment on lines +9 to +16
<!-- Allow connections to Supabase in debug mode -->
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">supabase.co</domain>
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</domain-config>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Redundant domain-config — identical to base-config.

This <domain-config> block has the same cleartextTrafficPermitted="false" and the same trust anchors as the <base-config>, so it has no effect. The comment mentions "debug mode," but nothing here is debug-specific. The proposed fix above removes this block and moves user-cert trust into <debug-overrides> where it belongs.

🤖 Prompt for AI Agents
In `@flutter_app/android/app/src/main/res/xml/network_security_config.xml` around
lines 9 - 16, Remove the redundant <domain-config> block that duplicates the
<base-config> (same cleartextTrafficPermitted and identical trust-anchors) so it
has no effect; instead, move user certificate trust (certificates src="user")
into the <debug-overrides> section so user-added certs are only allowed in debug
mode and keep the base-config with system certs only, updating the
network_security_config.xml elements <base-config>, <debug-overrides>, and any
existing <domain-config> entries (e.g., the supabase.co domain-config)
accordingly.

Comment on lines +15 to +18
// Get current user
final currentUserProvider = Provider<User?>((ref) {
return ref.read(authServiceProvider).currentUser;
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

currentUserProvider is not reactive — it returns a stale snapshot.

ref.read(authServiceProvider).currentUser captures the user at provider-creation time and never updates. After login or logout, consumers of this provider will still see the old value.

To make it reactive, derive it from the auth state stream:

Proposed fix
-// Get current user
-final currentUserProvider = Provider<User?>((ref) {
-  return ref.read(authServiceProvider).currentUser;
-});
+// Get current user (reactive)
+final currentUserProvider = Provider<User?>((ref) {
+  // Watch the auth state so this provider rebuilds on auth changes
+  ref.watch(authStateProvider);
+  return ref.read(authServiceProvider).currentUser;
+});
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Get current user
final currentUserProvider = Provider<User?>((ref) {
return ref.read(authServiceProvider).currentUser;
});
// Get current user (reactive)
final currentUserProvider = Provider<User?>((ref) {
// Watch the auth state so this provider rebuilds on auth changes
ref.watch(authStateProvider);
return ref.read(authServiceProvider).currentUser;
});
🤖 Prompt for AI Agents
In `@flutter_app/lib/auth/auth_provider.dart` around lines 15 - 18,
currentUserProvider currently reads a snapshot
(ref.read(authServiceProvider).currentUser) and never updates; change it to
derive from the AuthService's reactive auth-state stream by using a
StreamProvider (or Provider that ref.watch(...)s the service's stream) instead
of ref.read, e.g., have currentUserProvider subscribe to the AuthService's
stream property (authStateStream / authStateChanges / currentUserStream) so it
emits updated User? values on login/logout; update references to
currentUserProvider accordingly.

Comment on lines +64 to +67
Future<bool> signInWithGoogle() async {
try {
const webClientId =
'632491342639-mq70dmjhr8udmps5t312gkcrc5d90a17.apps.googleusercontent.com';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Hard-coded Google OAuth client ID in source code.

The webClientId is a sensitive configuration value committed directly to the repository. While OAuth client IDs are not strictly secret, embedding them here ties the app to a single environment and makes rotation harder. Move this to an environment-level configuration (e.g., --dart-define, a .env file loaded at runtime, or Supabase's dashboard-configured OAuth provider).

🤖 Prompt for AI Agents
In `@flutter_app/lib/auth/auth_service.dart` around lines 64 - 67, The hard-coded
OAuth client ID in signInWithGoogle (the webClientId constant) should be moved
to an environment-level configuration and loaded at runtime; replace the inline
string with a call that reads from your chosen config source (e.g., Dart
compile-time defines via String.fromEnvironment, a runtime .env loader like
flutter_dotenv, or your backend/Supabase-configured OAuth value) and update
signInWithGoogle to use that config value and fail-fast with a clear error if
the env value is missing; ensure you document the required env key and remove
the literal from source control.

Comment on lines +83 to +85
if (accessToken == null || idToken == null) {
throw 'Google authentication tokens not found';
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Throwing a raw String instead of a typed exception.

throw 'Google authentication tokens not found' produces a String, which won't be caught by on AuthException catch (e) in the calling code (login_page.dart line 78). It falls through to the generic catch (e) block, hiding the specific message. Throw an AuthException instead:

-      throw 'Google authentication tokens not found';
+      throw AuthException('Google authentication tokens not found');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (accessToken == null || idToken == null) {
throw 'Google authentication tokens not found';
}
if (accessToken == null || idToken == null) {
throw AuthException('Google authentication tokens not found');
}
🤖 Prompt for AI Agents
In `@flutter_app/lib/auth/auth_service.dart` around lines 83 - 85, Replace the raw
string throw with a typed AuthException so callers using "on AuthException catch
(e)" can handle it: in auth_service.dart (inside the code path that checks
accessToken and idToken) throw an AuthException with a clear message (e.g.,
"Google authentication tokens not found") instead of throwing a String; ensure
you import or reference the AuthException class used by login_page.dart and
preserve the original message when constructing the exception.

@@ -1,8 +1,9 @@
import 'package:flutter/src/material/theme_data.dart';
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Do not import from Flutter's internal src/ directory.

package:flutter/src/material/theme_data.dart is a private implementation path. Use the public barrel export instead — this is more resilient to internal refactors across Flutter versions.

Proposed fix
-import 'package:flutter/src/material/theme_data.dart';
+import 'package:flutter/material.dart';
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import 'package:flutter/src/material/theme_data.dart';
import 'package:flutter/material.dart';
🤖 Prompt for AI Agents
In `@flutter_app/lib/core/theme/app_theme.dart` at line 1, The file imports
Flutter internals via "package:flutter/src/material/theme_data.dart"; change
that to use the public barrel export (e.g., import from
package:flutter/material.dart) so ThemeData and related symbols are referenced
from the supported public API; update the import line that currently references
theme_data.dart and ensure any usages of ThemeData in this file remain the same.

Comment on lines +11 to 15
await Supabase.initialize(
url: 'https://prvbbbnsizxxfxreokov.supabase.co',
anonKey:
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBydmJiYm5zaXp4eGZ4cmVva292Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzA4OTMwODgsImV4cCI6MjA4NjQ2OTA4OH0.GOqP5k0AnGzqse5loXuPz9BkfGCUdJgApUL9QBVw0es',
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Hardcoded Supabase credentials should be externalized.

The Supabase URL and anonKey are committed directly into source. While the anon key is designed for client-side use, hardcoding it in a public repository makes key rotation painful and exposes your project identifier. Use --dart-define, flutter_dotenv, or a compile-time config approach to inject these values.

This was also flagged by Gitleaks (JWT detected on Line 14).

Suggested approach using --dart-define
  await Supabase.initialize(
-   url: 'https://prvbbbnsizxxfxreokov.supabase.co',
-   anonKey:
-       'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBydmJiYm5zaXp4eGZ4cmVva292Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzA4OTMwODgsImV4cCI6MjA4NjQ2OTA4OH0.GOqP5k0AnGzqse5loXuPz9BkfGCUdJgApUL9QBVw0es',
+   url: const String.fromEnvironment('SUPABASE_URL'),
+   anonKey: const String.fromEnvironment('SUPABASE_ANON_KEY'),
  );

Then build with:

flutter run --dart-define=SUPABASE_URL=https://... --dart-define=SUPABASE_ANON_KEY=...
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
await Supabase.initialize(
url: 'https://prvbbbnsizxxfxreokov.supabase.co',
anonKey:
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBydmJiYm5zaXp4eGZ4cmVva292Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzA4OTMwODgsImV4cCI6MjA4NjQ2OTA4OH0.GOqP5k0AnGzqse5loXuPz9BkfGCUdJgApUL9QBVw0es',
);
await Supabase.initialize(
url: const String.fromEnvironment('SUPABASE_URL'),
anonKey: const String.fromEnvironment('SUPABASE_ANON_KEY'),
);
🧰 Tools
🪛 Gitleaks (8.30.0)

[high] 14-14: Uncovered a JSON Web Token, which may lead to unauthorized access to web applications and sensitive user data.

(jwt)

🤖 Prompt for AI Agents
In `@flutter_app/lib/main.dart` around lines 11 - 15, Replace the hardcoded
Supabase credentials passed into Supabase.initialize (the url and anonKey
arguments) with environment-configured values: read them via compile-time
dart-define (e.g., const String.fromEnvironment('SUPABASE_URL') /
'SUPABASE_ANON_KEY') or via flutter_dotenv (dotenv.env['SUPABASE_URL'] /
dotenv.env['SUPABASE_ANON_KEY']), and update the Supabase.initialize call to use
those variables; ensure you document the required --dart-define keys
(SUPABASE_URL, SUPABASE_ANON_KEY) or add .env handling so secrets are not
committed in main.dart and can be injected at build/run time.

Comment on lines +35 to +54
Future<void> _loadUserProfile() async {
try {
final userId = Supabase.instance.client.auth.currentUser?.id;
if (userId != null) {
final profile = await authService.getUserProfile(userId);
if (mounted) {
setState(() {
userProfile = profile;
isLoading = false;
});
}
}
} catch (e) {
if (mounted) {
setState(() {
isLoading = false;
});
}
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Bug: infinite loading spinner when userId is null.

If currentUser is null (e.g., session expired between auth check and page load), the if (userId != null) block is skipped entirely and isLoading is never set to false, leaving the user stuck on a spinner forever.

Also, exceptions are silently swallowed — consider logging them for debuggability.

Proposed fix
  Future<void> _loadUserProfile() async {
    try {
      final userId = Supabase.instance.client.auth.currentUser?.id;
      if (userId != null) {
        final profile = await authService.getUserProfile(userId);
        if (mounted) {
          setState(() {
            userProfile = profile;
            isLoading = false;
          });
        }
+     } else {
+       if (mounted) {
+         setState(() {
+           isLoading = false;
+         });
+       }
      }
    } catch (e) {
+     debugPrint('Failed to load user profile: $e');
      if (mounted) {
        setState(() {
          isLoading = false;
        });
      }
    }
  }
🤖 Prompt for AI Agents
In `@flutter_app/lib/pages/homepage.dart` around lines 35 - 54, In
_loadUserProfile ensure isLoading is always cleared and errors are logged: if
Supabase.instance.client.auth.currentUser?.id is null, call setState to set
isLoading = false (and leave userProfile unchanged) instead of skipping, and in
the catch block log the exception (e.g., using debugPrint or your logger) before
setting isLoading = false; keep the mounted checks and update userProfile only
when authService.getUserProfile succeeds.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

Comments