[FOSSOVERFLOW-26] migrate auth+login to supabase from firebase#3
[FOSSOVERFLOW-26] migrate auth+login to supabase from firebase#3Ashish-Kumar-Dash wants to merge 2 commits intoOpenLake:mainfrom
Conversation
WalkthroughThis 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
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
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
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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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:multiDexEnabledand the multidex dependency are unnecessary with minSdk ≥ 21.Since
flutter.minSdkVersionresolves to 21 (Android 5.0 / ART), the runtime natively supports multiple DEX files. BothmultiDexEnabled = trueand theandroidx.multidex:multidexdependency 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'sauthServiceProviderinstead of direct instantiation.The
_HomePageStateextendsConsumerState, which provides access to therefobject. Replacefinal authService = AuthService();withref.watch(authServiceProvider)orref.read(authServiceProvider)depending on whether the value needs to be reactive or accessed once. This aligns with the app's existing Riverpod setup inauth_provider.dartand improves testability and dependency injection.flutter_app/lib/auth/login_page.dart (3)
30-61:isLoadingis never reset on successful login.On the success path (line 48 returns, execution continues past
await),isLoadingremainstrue. This works becauseAuthWrapperdisposes 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 = falsein afinallyblock 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:formkeyis unused — Form validation is bypassed.A
GlobalKey<FormState>is declared (line 18) and assigned to theFormwidget (line 98), butformkey.currentState!.validate()is never called. Validation is done manually at line 36. Either leverageFormvalidators onInputfieldwidgets (the idiomatic Flutter approach) or drop theForm/formkeyentirely.Also applies to: 97-98
63-89: SameisLoadingissue applies to_handleGoogleSignIn.On a successful Google sign-in (line 77 falls through to the end),
isLoadingstaystrue. Apply the samefinally+mountedguard as suggested for_handleLogin.flutter_app/lib/auth/signup_page.dart (1)
99-100: Redundant consecutive spacing.Two
SizedBoxwidgets withheight: 20andheight: 10appear back-to-back, which looks unintentional. Consolidate into a singleSizedBox(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-sidecreated_attimestamps are unreliable.
DateTime.now().toIso8601String()uses the device clock, which may be wrong or manipulated. Prefer a server-side default on thecreated_atcolumn (e.g.,DEFAULT now()in your Supabase table definition) and omitcreated_atfrom the insert payload entirely.Also applies to: 105-107
48-61: Redundanttry/catch/rethrowblocks add noise.
signIn,signOut,getUserProfile,updateUserProfile, andresetPasswordall 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, andresetPassword.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.
authServiceProviderandauthStateProviderare unused.AuthWrapperdirectly accessesSupabase.instance.client.auth.onAuthStateChange, and bothLoginPageandSignupPageinstantiateAuthService()directly, bypassing the provider layer entirely. Either refactor these pages to useConsumerWidget/ConsumerStatefulWidgetand access the providers viaref.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 |
There was a problem hiding this comment.
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.
| <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" /> |
There was a problem hiding this comment.
🧩 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/...withandroid:autoVerify="true"(andassetlinks.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.
-
android:autoVerify="true"is ineffective with custom URI schemes. Auto-verification is an Android App Links feature that only works withhttp/httpsschemes and requires a/.well-known/assetlinks.jsonfile on the verified domain. For the custom schemeio.supabase.getwelplus, this attribute is silently ignored. Remove it to avoid confusion. -
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.
| <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.
| <base-config cleartextTrafficPermitted="false"> | ||
| <trust-anchors> | ||
| <certificates src="system" /> | ||
| <certificates src="user" /> | ||
| </trust-anchors> | ||
| </base-config> |
There was a problem hiding this comment.
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.
| <!-- 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> |
There was a problem hiding this comment.
🛠️ 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.
| // Get current user | ||
| final currentUserProvider = Provider<User?>((ref) { | ||
| return ref.read(authServiceProvider).currentUser; | ||
| }); |
There was a problem hiding this comment.
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.
| // 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.
| Future<bool> signInWithGoogle() async { | ||
| try { | ||
| const webClientId = | ||
| '632491342639-mq70dmjhr8udmps5t312gkcrc5d90a17.apps.googleusercontent.com'; |
There was a problem hiding this comment.
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.
| if (accessToken == null || idToken == null) { | ||
| throw 'Google authentication tokens not found'; | ||
| } |
There was a problem hiding this comment.
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.
| 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'; | |||
There was a problem hiding this comment.
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.
| 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.
| await Supabase.initialize( | ||
| url: 'https://prvbbbnsizxxfxreokov.supabase.co', | ||
| anonKey: | ||
| 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InBydmJiYm5zaXp4eGZ4cmVva292Iiwicm9sZSI6ImFub24iLCJpYXQiOjE3NzA4OTMwODgsImV4cCI6MjA4NjQ2OTA4OH0.GOqP5k0AnGzqse5loXuPz9BkfGCUdJgApUL9QBVw0es', | ||
| ); |
There was a problem hiding this comment.
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.
| 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.
| 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; | ||
| }); | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
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.
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:
Authentication Features:
Architecture:
AuthService- Clean service layer for all auth operationsAuthProvider- Riverpod state managementAuthWrapper- Handles navigation based on auth stateAndroid Configuration Fixes:
Files Modified:
lib/pages/homepage.dart- Migrated from Firestore to Supabasepubspec.yaml- Dependency swap@Asp-irin kindly review
Summary by CodeRabbit
New Features
Refactor