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:
@@ -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;
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user