@@ -51,10 +51,11 @@ class ClerkAuthProvider extends clerk.Auth with ChangeNotifier {
5151
5252 final _errors = StreamController <clerk.AuthError >();
5353 final OverlayEntry _loadingOverlay;
54- OverlayEntry ? _ssoOverlay;
5554
5655 static const _kRotatingTokenNonce = 'rotating_token_nonce' ;
5756
57+ static const _kSsoRouteName = 'clerk_sso_popup' ;
58+
5859 @override
5960 void update () => notifyListeners ();
6061
@@ -71,53 +72,42 @@ class ClerkAuthProvider extends clerk.Auth with ChangeNotifier {
7172 void Function (clerk.AuthError )? onError,
7273 }) async {
7374 final auth = ClerkAuth .of (context);
74- final overlay = Overlay .of (context);
7575 final client = await call (
7676 context,
7777 () => auth.oauthSignIn (strategy: strategy),
7878 onError: onError,
7979 );
8080 final url = client? .signIn? .firstFactorVerification? .providerUrl;
81- if (url case String url) {
82- _ssoOverlay = OverlayEntry (
83- builder: (BuildContext context) {
84- return _SsoWebViewHost (
85- url: url,
86- callback: _ssoCallback (
87- strategy,
88- onError: onError,
89- auth: auth,
90- ),
91- );
92- },
81+ if (url != null && context.mounted) {
82+ final redirectUrl = await showDialog <String >(
83+ context: context,
84+ useSafeArea: false ,
85+ useRootNavigator: true ,
86+ routeSettings: const RouteSettings (name: _kSsoRouteName),
87+ builder: (context) => _SsoWebViewOverlay (url: url),
9388 );
94- overlay.insert (_ssoOverlay! );
95- }
96- }
97-
98- Function (BuildContext , String ) _ssoCallback (
99- clerk.Strategy strategy, {
100- void Function (clerk.AuthError )? onError,
101- required ClerkAuthProvider auth,
102- }) {
103- return (BuildContext context, String redirectUrl) async {
104- final uri = Uri .parse (redirectUrl);
105- final token = uri.queryParameters[_kRotatingTokenNonce];
106- if (token case String token) {
107- await call (
108- context,
109- () => auth.attemptSignIn (strategy: strategy, token: token),
110- onError: onError,
111- );
112- } else {
113- await auth.refreshClient ();
89+ if (redirectUrl != null && context.mounted) {
90+ final uri = Uri .parse (redirectUrl);
91+ final token = uri.queryParameters[_kRotatingTokenNonce];
92+ if (token case String token) {
93+ await call (
94+ context,
95+ () => auth.attemptSignIn (strategy: strategy, token: token),
96+ onError: onError,
97+ );
98+ } else {
99+ await auth.refreshClient ();
100+ if (context.mounted) {
101+ await call (context, () => auth.transfer (), onError: onError);
102+ }
103+ }
114104 if (context.mounted) {
115- await call (context, () => auth.transfer (), onError: onError);
105+ Navigator .of (context).popUntil (
106+ (route) => route.settings.name != _kSsoRouteName,
107+ );
116108 }
117109 }
118- _ssoOverlay? .remove ();
119- _ssoOverlay = null ;
120- };
110+ }
121111 }
122112
123113 /// Convenience method to make an auth call to the backend via ClerkAuth
@@ -198,33 +188,38 @@ class ClerkAuthProvider extends clerk.Auth with ChangeNotifier {
198188 _errors.add (clerk.AuthError (message: message));
199189}
200190
201- class _SsoWebViewHost extends StatefulWidget {
202- const _SsoWebViewHost ({
191+ class _SsoWebViewOverlay extends StatefulWidget {
192+ const _SsoWebViewOverlay ({
203193 required this .url,
204- required this .callback,
205194 });
206195
207196 final String url;
208- final Function (BuildContext context, String redirectUrl) callback;
209197
210198 @override
211- State <_SsoWebViewHost > createState () => _SsoWebViewHostState ();
199+ State <_SsoWebViewOverlay > createState () => _SsoWebViewOverlayState ();
212200}
213201
214- class _SsoWebViewHostState extends State <_SsoWebViewHost > {
202+ class _SsoWebViewOverlayState extends State <_SsoWebViewOverlay > {
215203 late final WebViewController controller;
204+ var _title = Future <String ?>.value ('Loading…' );
216205
217206 @override
218207 void initState () {
219208 super .initState ();
220209 controller = WebViewController ()
221210 ..setUserAgent ('Clerk Flutter SDK v${clerk .Auth .jsVersion }' )
222211 ..setJavaScriptMode (JavaScriptMode .unrestricted)
212+ ..setBackgroundColor (Colors .white)
223213 ..setNavigationDelegate (
224214 NavigationDelegate (
215+ onPageFinished: (_) => _updateTitle (),
225216 onNavigationRequest: (NavigationRequest request) async {
226217 if (request.url.startsWith (clerk.Auth .oauthRedirect)) {
227- widget.callback (context, request.url);
218+ scheduleMicrotask (() {
219+ if (mounted) {
220+ Navigator .of (context).pop (request.url);
221+ }
222+ });
228223 return NavigationDecision .prevent;
229224 }
230225 return NavigationDecision .navigate;
@@ -234,9 +229,25 @@ class _SsoWebViewHostState extends State<_SsoWebViewHost> {
234229 controller.loadRequest (Uri .parse (widget.url));
235230 }
236231
232+ void _updateTitle () {
233+ setState (() {
234+ _title = controller.getTitle ();
235+ });
236+ }
237+
237238 @override
238239 Widget build (BuildContext context) {
239240 return Scaffold (
241+ appBar: AppBar (
242+ automaticallyImplyLeading: false ,
243+ title: FutureBuilder (
244+ future: _title,
245+ builder: (context, snapshot) {
246+ return Text (snapshot.data ?? '' );
247+ },
248+ ),
249+ actions: const [CloseButton ()],
250+ ),
240251 body: WebViewWidget (controller: controller),
241252 );
242253 }
0 commit comments