feat: Enhance authentication by refining user role validation during session handling and ensuring immediate ID token refresh after sign-in to prevent unauthenticated Data Connect SDK requests.

This commit is contained in:
Achintha Isuru
2026-02-28 18:17:49 -05:00
parent d3f3b0f70e
commit 7c701ded5f
2 changed files with 26 additions and 6 deletions

View File

@@ -205,13 +205,23 @@ mixin SessionHandlerMixin {
try { try {
_emitSessionState(SessionState.loading()); _emitSessionState(SessionState.loading());
// Validate role if allowed roles are specified // Validate role only when allowed roles are specified.
if (_allowedRoles.isNotEmpty) { if (_allowedRoles.isNotEmpty) {
final bool isAuthorized = await validateUserRole( final String? userRole = await fetchUserRole(user.uid);
user.uid,
_allowedRoles, if (userRole == null) {
); // User has no record in the database yet. This is expected during
if (!isAuthorized) { // the sign-up flow: Firebase Auth fires authStateChanges before the
// repository has created the PostgreSQL user record. Do NOT sign out —
// just emit unauthenticated and let the registration flow complete.
_emitSessionState(SessionState.unauthenticated());
return;
}
if (!_allowedRoles.contains(userRole)) {
// User IS in the database but has a role that is not permitted in
// this app (e.g., a STAFF-only user trying to use the Client app).
// Sign them out to force them to use the correct app.
await auth.signOut(); await auth.signOut();
_emitSessionState(SessionState.unauthenticated()); _emitSessionState(SessionState.unauthenticated());
return; return;

View File

@@ -90,6 +90,12 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
); );
} }
// Force-refresh the ID token so the Data Connect SDK has a valid bearer
// token before we fire any mutations. Without this, there is a race
// condition where the gRPC layer sends the request unauthenticated
// immediately after account creation (gRPC code 16 UNAUTHENTICATED).
await firebaseUser.getIdToken(true);
// New user created successfully, proceed to create PostgreSQL entities // New user created successfully, proceed to create PostgreSQL entities
return await _createBusinessAndUser( return await _createBusinessAndUser(
firebaseUser: firebaseUser, firebaseUser: firebaseUser,
@@ -165,6 +171,10 @@ class AuthRepositoryImpl implements AuthRepositoryInterface {
); );
} }
// Force-refresh the ID token so the Data Connect SDK receives a valid
// bearer token before any subsequent Data Connect queries run.
await firebaseUser.getIdToken(true);
// Sign-in succeeded! Check if user already has a BUSINESS account in PostgreSQL // Sign-in succeeded! Check if user already has a BUSINESS account in PostgreSQL
final bool hasBusinessAccount = await _checkBusinessUserExists( final bool hasBusinessAccount = await _checkBusinessUserExists(
firebaseUser.uid, firebaseUser.uid,