@@ -341,30 +341,49 @@ class _WebViewLoginScreenState extends State<WebViewLoginScreen> {
341341 }
342342 }
343343
344- // Check if we're on the AGiXT domain and on the chat page (successful login)
345- final isAgixtDomain = uri.host.contains ('agixt' );
344+ // Check if we're on the app domain and on the chat page (successful login)
345+ // Use the configured appUri domain instead of hardcoding 'agixt'
346+ final appHost = Uri .parse (AuthService .appUri).host;
347+ final isAppDomain = uri.host == appHost ||
348+ uri.host.endsWith ('.$appHost ' ) ||
349+ uri.host.contains ('agixt' );
346350 final isOnChat = uri.path == '/chat' || uri.path.startsWith ('/chat/' );
347351
348- if (isAgixtDomain && isOnChat) {
352+ if (isAppDomain && isOnChat) {
349353 debugPrint ('WebView Login: Successfully landed on chat page' );
350354 _hasCheckedAuth = true ;
351355
352356 // We're on the chat page - try to extract the JWT
353357 String ? jwtToken = await _extractJwtFromWebView ();
354358
355359 if (jwtToken != null && jwtToken.isNotEmpty) {
356- debugPrint ('WebView Login: Found JWT token, storing it ' );
357- await AuthService . storeJwt (jwtToken);
360+ debugPrint ('WebView Login: Found JWT token from webview, navigating to home ' );
361+ await _handleSuccessfulLogin (jwtToken);
358362 } else {
359- // Even if we couldn't extract the JWT, we're logged in via the web app cookies
360- debugPrint (
361- 'WebView Login: No JWT found but on chat page - using cookie auth' );
362- await AuthService .setCookieAuthenticated (true );
363- }
363+ // Try to get JWT from the API using the session cookies in the webview
364+ debugPrint ('WebView Login: No JWT in storage, trying API extraction...' );
365+ jwtToken = await _extractJwtFromApi ();
366+
367+ if (jwtToken != null && jwtToken.isNotEmpty) {
368+ debugPrint ('WebView Login: Got JWT from API, navigating to home' );
369+ await _handleSuccessfulLogin (jwtToken);
370+ } else {
371+ // Fallback: use cookie-based auth
372+ debugPrint ('WebView Login: No JWT found, using cookie auth fallback' );
373+ await AuthService .setCookieAuthenticated (true );
374+
375+ if (mounted) {
376+ AGiXTApp .onLoginSuccess? .call ();
377+ await Future .delayed (const Duration (milliseconds: 100 ));
364378
365- // Mark as authenticated and stay on this page (don't navigate away)
366- // The user is already on the chat page in this WebView, so let them continue
367- await _markAuthenticatedAndStayInWebView ();
379+ Navigator .of (context).pushNamedAndRemoveUntil (
380+ '/home' ,
381+ (route) => false ,
382+ arguments: {'forceNewChat' : true },
383+ );
384+ }
385+ }
386+ }
368387 }
369388 }
370389
@@ -1209,37 +1228,97 @@ class _WebViewLoginScreenState extends State<WebViewLoginScreen> {
12091228 }
12101229 }
12111230
1231+ /// Try to get a JWT by calling the user endpoint from within the webview
1232+ /// This works because the webview has the session cookies from SSO
1233+ Future <String ?> _extractJwtFromApi () async {
1234+ if (_controller == null ) return null ;
1235+
1236+ try {
1237+ final serverUrl = AuthService .serverUrl;
1238+ final jsResult = await _controller! .runJavaScriptReturningResult ('''
1239+ (async function() {
1240+ try {
1241+ // The jwt cookie should already be set by the Next.js middleware
1242+ // Try reading it directly first
1243+ var cookies = document.cookie.split(';');
1244+ for (var i = 0; i < cookies.length; i++) {
1245+ var cookie = cookies[i].trim();
1246+ if (cookie.startsWith('jwt=')) {
1247+ var val = cookie.substring(4);
1248+ // Decode URI component in case it's encoded
1249+ try { val = decodeURIComponent(val); } catch(e) {}
1250+ if (val && val.length > 20 && val !== 'null' && val !== 'undefined') {
1251+ return val;
1252+ }
1253+ }
1254+ }
1255+ return 'null';
1256+ } catch(e) {
1257+ return 'null';
1258+ }
1259+ })()
1260+ ''' );
1261+
1262+ if (jsResult != null && jsResult.toString () != 'null' ) {
1263+ var token = jsResult.toString ().replaceAll ('"' , '' ).replaceAll ("'" , '' );
1264+ if (token != 'null' && token.isNotEmpty && token.length > 20 ) {
1265+ debugPrint ('WebView Login: Found JWT from API/cookie extraction' );
1266+ return token;
1267+ }
1268+ }
1269+ } catch (e) {
1270+ debugPrint ('WebView Login: Error extracting JWT from API: $e ' );
1271+ }
1272+
1273+ return null ;
1274+ }
1275+
12121276 Future <String ?> _extractJwtFromWebView () async {
12131277 if (_controller == null ) return null ;
12141278
12151279 try {
12161280 final jsResult = await _controller! .runJavaScriptReturningResult ('''
12171281 (function() {
1282+ // PRIORITY: Check the 'jwt' cookie first - this is what the web app uses
1283+ var cookies = document.cookie.split(';');
1284+ for (var j = 0; j < cookies.length; j++) {
1285+ var cookie = cookies[j].trim();
1286+ if (cookie.startsWith('jwt=')) {
1287+ var val = cookie.substring(4);
1288+ try { val = decodeURIComponent(val); } catch(e) {}
1289+ if (val && val.length > 20 && val !== 'null' && val !== 'undefined') {
1290+ return val;
1291+ }
1292+ }
1293+ }
1294+
12181295 // Try localStorage with various keys
12191296 var keys = ['jwt', 'token', 'access_token', 'accessToken', 'auth_token', 'authToken', 'id_token', 'idToken'];
12201297 for (var i = 0; i < keys.length; i++) {
12211298 var token = localStorage.getItem(keys[i]);
1222- if (token && token !== 'null' && token !== 'undefined') {
1299+ if (token && token !== 'null' && token !== 'undefined' && token.length > 20 ) {
12231300 return token;
12241301 }
12251302 }
12261303
12271304 // Try sessionStorage with various keys
12281305 for (var i = 0; i < keys.length; i++) {
12291306 var token = sessionStorage.getItem(keys[i]);
1230- if (token && token !== 'null' && token !== 'undefined') {
1307+ if (token && token !== 'null' && token !== 'undefined' && token.length > 20 ) {
12311308 return token;
12321309 }
12331310 }
12341311
1235- // Try cookies with various names
1236- var cookieKeys = ['jwt', 'token', 'access_token', 'accessToken', 'auth_token', 'authToken'];
1237- var cookies = document.cookie.split(';');
1312+ // Try other cookies with various names
1313+ var cookieKeys = ['token', 'access_token', 'accessToken', 'auth_token', 'authToken'];
12381314 for (var j = 0; j < cookies.length; j++) {
12391315 var cookie = cookies[j].trim();
12401316 for (var k = 0; k < cookieKeys.length; k++) {
12411317 if (cookie.startsWith(cookieKeys[k] + '=')) {
1242- return cookie.substring(cookieKeys[k].length + 1);
1318+ var val = cookie.substring(cookieKeys[k].length + 1);
1319+ if (val && val.length > 20) {
1320+ return val;
1321+ }
12431322 }
12441323 }
12451324 }
@@ -1262,7 +1341,7 @@ class _WebViewLoginScreenState extends State<WebViewLoginScreen> {
12621341 if (jsResult != 'null' && jsResult.toString ().isNotEmpty) {
12631342 // Remove quotes if present
12641343 var token = jsResult.toString ().replaceAll ('"' , '' ).replaceAll ("'" , '' );
1265- if (token != 'null' && token.isNotEmpty) {
1344+ if (token != 'null' && token.isNotEmpty && token.length > 20 ) {
12661345 return token;
12671346 }
12681347 }
@@ -1296,8 +1375,30 @@ class _WebViewLoginScreenState extends State<WebViewLoginScreen> {
12961375 debugPrint (
12971376 'WebView Login: After storing JWT, isLoggedIn = $isNowLoggedIn ' );
12981377
1299- // Stay in WebView instead of navigating away
1300- await _markAuthenticatedAndStayInWebView ();
1378+ if (! isNowLoggedIn) {
1379+ throw StateError ('JWT was not stored properly' );
1380+ }
1381+
1382+ setState (() {
1383+ _isAuthenticated = true ;
1384+ });
1385+
1386+ if (mounted) {
1387+ // Notify the root state of successful login
1388+ debugPrint ('WebView Login: Calling onLoginSuccess callback...' );
1389+ AGiXTApp .onLoginSuccess? .call ();
1390+
1391+ // Small delay to ensure state propagates
1392+ await Future .delayed (const Duration (milliseconds: 100 ));
1393+
1394+ // Navigate directly to home screen (like Phantom wallet flow)
1395+ debugPrint ('WebView Login: Navigating to /home...' );
1396+ Navigator .of (context).pushNamedAndRemoveUntil (
1397+ '/home' ,
1398+ (route) => false ,
1399+ arguments: {'forceNewChat' : true },
1400+ );
1401+ }
13011402 } catch (e) {
13021403 debugPrint ('WebView Login: Error storing token: $e ' );
13031404 if (mounted) {
0 commit comments