Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 3.35.0 - 2026-07-18

- Add `completeSignInWithRedirect` to the auth service. On web, OAuth sign-in with `redirect: true` reloads the page on return from the provider, discarding the in-flight `signInWith...` call before it can provision a `YustUser` — leaving an authenticated Firebase user with no matching `YustUser`. Call `completeSignInWithRedirect` once at app startup to fetch the pending redirect result and create/link the `YustUser`. No-op when there is no pending redirect (safe to call on every startup) and on non-web platforms.

## 3.33.2 - 2026-05-18

- Fix handling of empty maps in `YustDatabaseService` (dart-only)
Expand Down
4 changes: 4 additions & 0 deletions lib/src/services/yust_auth_service_dart.dart
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,10 @@ class YustAuthService {
throw UnsupportedError('Not supported. No UI available.');
}

/// Completes an OAuth redirect sign-in. Web-only concept; on the server this
/// is a no-op so shared code can call it unconditionally.
Future<YustUser?> completeSignInWithRedirect() async => null;

/// Sign out the current user.
Future<void> signOut() async {
throw UnsupportedError('Not supported. No UI available.');
Expand Down
53 changes: 53 additions & 0 deletions lib/src/services/yust_auth_service_flutter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,42 @@ class YustAuthService {
provider,
redirect: redirect,
);
return _provisionYustUser(userCredential, method);
}

/// Completes an OAuth sign-in that was started with `redirect: true` on web.
///
/// The redirect flow navigates the whole page away to the identity provider
/// and reloads the app on return, which discards the in-flight
/// `signInWith...` call before it can provision a [YustUser]. Firebase
/// restores the auth user from persistence on reload, but the [YustUser]
/// document would otherwise never be created — leaving an authenticated
/// Firebase user with no matching domain user.
///
/// Call this once at app startup (web only). It fetches the pending redirect
/// result and, if a sign-in just completed, creates or links the matching
/// [YustUser]. It is a no-op when there is no pending redirect result, so it
/// is safe to call on every startup.
Future<YustUser?> completeSignInWithRedirect() async {
if (!kIsWeb) return null;
final userCredential = await _fireAuth.getRedirectResult();
if (userCredential.user == null) return null;
final method = _methodFromProviderId(
userCredential.additionalUserInfo?.providerId ??
userCredential.credential?.providerId,
);
return _provisionYustUser(userCredential, method);
}

/// Ensures a [YustUser] exists for the signed-in [userCredential], linking
/// an existing user (matched by email) or creating a new one. Returns the
/// created user, or `null` when the sign-in failed or a matching user
/// already existed / was linked. Idempotent — safe to call for a user that
/// is already provisioned.
Future<YustUser?> _provisionYustUser(
UserCredential userCredential,
YustAuthenticationMethod? method,
) async {
if (_signInFailed(userCredential)) return null;
final connectedYustUser = await _maybeGetConnectedYustUser(userCredential);
if (_yustUserWasLinked(connectedYustUser)) return null;
Expand Down Expand Up @@ -146,6 +182,23 @@ class YustAuthService {
);
}

YustAuthenticationMethod? _methodFromProviderId(String? providerId) {
switch (providerId) {
case 'microsoft.com':
return YustAuthenticationMethod.microsoft;
case 'google.com':
return YustAuthenticationMethod.google;
case 'apple.com':
return YustAuthenticationMethod.apple;
case null:
case 'password':
case 'firebase':
return null;
default:
return YustAuthenticationMethod.openId;
}
}

String _getId(UserCredential userCredential) => userCredential.user!.uid;

String _getEmail(UserCredential userCredential) =>
Expand Down
3 changes: 3 additions & 0 deletions lib/src/services/yust_auth_service_mocked.dart
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ class YustAuthServiceMocked implements YustAuthService {
bool redirect = false,
}) => throw UnimplementedError();

@override
Future<YustUser?> completeSignInWithRedirect() async => null;

@override
Future<void> signOut() => throw UnimplementedError();

Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: yust
description: Build awesome apps with Flutter and Firebase - this package allows communication with Firebase to be a breeze.
version: 3.33.2
version: 3.35.0
homepage: https://github.com/univelop/yust

environment:
Expand Down