Skip to content

Commit 4a35a15

Browse files
committed
update google flow (not sure if it is working
1 parent 41f2788 commit 4a35a15

File tree

2 files changed

+76
-44
lines changed

2 files changed

+76
-44
lines changed

pwa_ios/TerrierPWA.xcodeproj/project.pbxproj

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,10 +274,11 @@
274274
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
275275
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
276276
CODE_SIGN_ENTITLEMENTS = TerrierPWA/TerrierPWA.entitlements;
277+
CODE_SIGN_IDENTITY = "Apple Development";
277278
CODE_SIGN_STYLE = Automatic;
278279
CURRENT_PROJECT_VERSION = 1;
279280
DEVELOPMENT_ASSET_PATHS = "";
280-
DEVELOPMENT_TEAM = "";
281+
DEVELOPMENT_TEAM = 4Y39FMA838;
281282
ENABLE_PREVIEWS = YES;
282283
GENERATE_INFOPLIST_FILE = NO;
283284
INFOPLIST_FILE = TerrierPWA/Info.plist;
@@ -295,6 +296,7 @@
295296
MARKETING_VERSION = 1.0.0;
296297
PRODUCT_BUNDLE_IDENTIFIER = org.scottylabs.terrier;
297298
PRODUCT_NAME = "$(TARGET_NAME)";
299+
PROVISIONING_PROFILE_SPECIFIER = "";
298300
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
299301
SUPPORTS_MACCATALYST = NO;
300302
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
@@ -310,10 +312,11 @@
310312
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
311313
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
312314
CODE_SIGN_ENTITLEMENTS = TerrierPWA/TerrierPWA.entitlements;
315+
CODE_SIGN_IDENTITY = "Apple Development";
313316
CODE_SIGN_STYLE = Automatic;
314317
CURRENT_PROJECT_VERSION = 1;
315318
DEVELOPMENT_ASSET_PATHS = "";
316-
DEVELOPMENT_TEAM = "";
319+
DEVELOPMENT_TEAM = X39S5JJUD8;
317320
ENABLE_PREVIEWS = YES;
318321
GENERATE_INFOPLIST_FILE = NO;
319322
INFOPLIST_FILE = TerrierPWA/Info.plist;
@@ -331,6 +334,7 @@
331334
MARKETING_VERSION = 1.0.0;
332335
PRODUCT_BUNDLE_IDENTIFIER = org.scottylabs.terrier;
333336
PRODUCT_NAME = "$(TARGET_NAME)";
337+
PROVISIONING_PROFILE_SPECIFIER = "";
334338
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
335339
SUPPORTS_MACCATALYST = NO;
336340
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;

pwa_ios/TerrierPWA/PWAWebView.swift

Lines changed: 70 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -372,9 +372,8 @@ struct PWAWebView: UIViewRepresentable {
372372

373373
// MARK: - Coordinator
374374

375-
class Coordinator: NSObject, WKNavigationDelegate, WKUIDelegate, WKScriptMessageHandler, UIScrollViewDelegate, ASWebAuthenticationPresentationContextProviding {
375+
class Coordinator: NSObject, WKNavigationDelegate, WKUIDelegate, WKScriptMessageHandler, UIScrollViewDelegate, ASWebAuthenticationPresentationContextProviding, SFSafariViewControllerDelegate {
376376
var parent: PWAWebView
377-
var authSession: ASWebAuthenticationSession?
378377

379378
init(_ parent: PWAWebView) {
380379
self.parent = parent
@@ -392,60 +391,89 @@ struct PWAWebView: UIViewRepresentable {
392391

393392
// MARK: - External Browser Authentication (for Google, etc.)
394393

395-
/// Start authentication in Safari for providers that block WebView
396-
/// We use SFSafariViewController which shares cookies with Safari
397-
/// When auth completes, the callback URL will open the app via Universal Links
394+
var safariVC: SFSafariViewController?
395+
396+
/// Start authentication using SFSafariViewController for providers that block WebView
397+
/// Google accepts SFSafariViewController as a "system browser" (not an embedded webview)
398+
/// Unlike ASWebAuthenticationSession, this works with the server's HTTPS callback URL
398399
func startExternalBrowserAuth(url: URL) {
399-
print("[AUTH] 🌐 Opening Safari for auth: \(url.absoluteString)")
400-
print("[AUTH] 💡 After sign-in, the app should reopen automatically via Universal Links")
401-
print("[AUTH] 💡 If not, user can return to app and pull-to-refresh")
402-
403-
// Open in Safari (external browser)
404-
// Safari will handle the OAuth flow and cookies will be stored in Safari's cookie store
405-
// When auth completes at terrier.scottylabs.org/auth/callback,
406-
// Universal Links will open the app if configured
407-
UIApplication.shared.open(url, options: [:]) { success in
408-
if success {
409-
print("[AUTH] ✅ Opened Safari successfully")
400+
print("[AUTH] 🌐 Opening SFSafariViewController for: \(url.absoluteString)")
401+
402+
let config = SFSafariViewController.Configuration()
403+
config.entersReaderIfAvailable = false
404+
config.barCollapsingEnabled = true
405+
406+
let safari = SFSafariViewController(url: url, configuration: config)
407+
safari.delegate = self
408+
safari.preferredControlTintColor = .systemBlue
409+
safari.dismissButtonStyle = .cancel
410+
411+
safariVC = safari
412+
413+
// Present the Safari view controller
414+
DispatchQueue.main.async {
415+
if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
416+
let rootVC = scene.windows.first?.rootViewController {
417+
// Find the topmost presented view controller
418+
var topVC = rootVC
419+
while let presented = topVC.presentedViewController {
420+
topVC = presented
421+
}
422+
topVC.present(safari, animated: true)
423+
print("[AUTH] ✅ SFSafariViewController presented")
410424
} else {
411-
print("[AUTH] ❌ Failed to open Safari")
425+
print("[AUTH] ❌ Could not find root view controller")
412426
}
413427
}
414428
}
415429

416-
/// Handle the callback URL from external auth
417-
private func handleAuthCallback(_ callbackURL: URL) {
418-
// The callback URL will be like: terrier://auth/callback?code=xxx&state=yyy
419-
// We need to convert it to: https://terrier.scottylabs.org/auth/callback?code=xxx&state=yyy
420-
421-
var pathComponents = [String]()
422-
if let host = callbackURL.host {
423-
pathComponents.append(host)
424-
}
425-
if !callbackURL.path.isEmpty && callbackURL.path != "/" {
426-
pathComponents.append(String(callbackURL.path.dropFirst()))
427-
}
428-
let path = pathComponents.joined(separator: "/")
430+
/// Called when Safari view finishes loading - check if we've returned to the app domain after auth
431+
func safariViewController(_ controller: SFSafariViewController, didCompleteInitialLoad didLoadSuccessfully: Bool) {
432+
print("[AUTH] 📄 Safari initial load complete, success: \(didLoadSuccessfully)")
433+
}
434+
435+
/// Called when the user taps Done button or Safari redirects
436+
func safariViewControllerDidFinish(_ controller: SFSafariViewController) {
437+
print("[AUTH] ⏹️ User dismissed Safari view controller")
438+
safariVC = nil
429439

430-
var webURLString = "https://terrier.scottylabs.org/\(path)"
431-
if let query = callbackURL.query {
432-
webURLString += "?\(query)"
440+
// Sync cookies and reload the WebView to pick up any session changes
441+
print("[AUTH] 🍪 Syncing cookies after Safari dismiss...")
442+
syncCookiesToWebView { [weak self] in
443+
DispatchQueue.main.async {
444+
self?.parent.state.webView?.reload()
445+
}
433446
}
447+
}
448+
449+
/// Called when Safari redirects to a URL - detect auth completion
450+
func safariViewController(_ controller: SFSafariViewController, initialLoadDidRedirectTo URL: URL) {
451+
print("[AUTH] 🔀 Safari redirected to: \(URL.absoluteString)")
434452

435-
// Sync cookies from the shared HTTP cookie storage to WKWebView
436-
// ASWebAuthenticationSession stores cookies in HTTPCookieStorage.shared
437-
print("[AUTH] 🍪 Syncing cookies from system store to WKWebView...")
438-
self.syncCookiesToWebView {
439-
if let webURL = URL(string: webURLString) {
440-
print("[AUTH] 🔄 Loading callback in WebView: \(webURL.absoluteString)")
441-
DispatchQueue.main.async {
442-
self.parent.state.webView?.load(URLRequest(url: webURL))
453+
// Check if we've returned to our app's domain after auth callback
454+
if let host = URL.host?.lowercased(),
455+
host.contains("scottylabs.org"),
456+
!URL.path.contains("/realms/") { // Not still in Keycloak login
457+
458+
// Auth likely completed - dismiss Safari and sync session
459+
print("[AUTH] ✅ Detected return to app domain, dismissing Safari...")
460+
461+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
462+
controller.dismiss(animated: true) {
463+
self?.safariVC = nil
464+
print("[AUTH] 🍪 Syncing cookies after auth completion...")
465+
self?.syncCookiesToWebView {
466+
DispatchQueue.main.async {
467+
// Reload to the current URL (which is the auth callback result)
468+
self?.parent.state.webView?.load(URLRequest(url: URL))
469+
}
470+
}
443471
}
444472
}
445473
}
446474
}
447475

448-
/// Sync cookies from HTTPCookieStorage.shared to WKWebView's cookie store
476+
/// Sync cookies from Safari's shared cookie storage to WKWebView
449477
private func syncCookiesToWebView(completion: @escaping () -> Void) {
450478
let sharedCookies = HTTPCookieStorage.shared.cookies ?? []
451479
let wkCookieStore = WKWebsiteDataStore.default().httpCookieStore

0 commit comments

Comments
 (0)