···
···
"github.com/bluesky-social/indigo/atproto/auth/oauth"
"github.com/bluesky-social/indigo/atproto/syntax"
+
// mobileCallbackTemplate is the intermediate page shown after OAuth completes
+
// before redirecting to the mobile app via custom scheme.
+
// This prevents the browser from showing a stale PDS page after the redirect.
+
var mobileCallbackTemplate = template.Must(template.New("mobile_callback").Parse(`<!DOCTYPE html>
+
<meta name="viewport" content="width=device-width, initial-scale=1">
+
<title>Login Complete - Coves</title>
+
<meta http-equiv="refresh" content="1;url={{.DeepLink}}">
+
* { box-sizing: border-box; margin: 0; padding: 0; }
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
+
justify-content: center;
+
justify-content: center;
+
animation: scale-in 0.3s ease-out;
+
0% { transform: scale(0); }
+
50% { transform: scale(1.1); }
+
100% { transform: scale(1); }
+
border: 2px solid #2A2F36;
+
border-top-color: #FF6B35;
+
animation: spin 1s linear infinite;
+
vertical-align: middle;
+
to { transform: rotate(360deg); }
+
<div class="checkmark">
+
<svg viewBox="0 0 24 24">
+
<polyline points="20 6 9 17 4 12"></polyline>
+
<h1>Login Complete</h1>
+
<span class="spinner"></span>
+
<div class="handle">@{{.Handle}}</div>
+
<p class="hint">If the app doesn't open automatically,<br>you can close this window.</p>
+
// Redirect to app immediately
+
window.location.href = {{.DeepLink}};
+
// Try to close window after a delay
+
setTimeout(function() {
// MobileOAuthStore interface for mobile-specific OAuth operations
// This extends the base OAuth store with mobile CSRF tracking
···
// Log mobile redirect (sanitized - no token or session ID to avoid leaking credentials)
slog.Info("redirecting to mobile app", "did", sessData.AccountDID, "handle", handle)
+
// Serve intermediate page that redirects to the app
+
// This prevents the browser from showing a stale PDS page after the custom scheme redirect
+
w.Header().Set("Content-Type", "text/html; charset=utf-8")
+
w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate")
+
if err := mobileCallbackTemplate.Execute(w, data); err != nil {
+
slog.Error("failed to render mobile callback template", "error", err)
+
// Fallback to direct redirect if template fails
+
http.Redirect(w, r, deepLink, http.StatusFound)
// HandleLogout revokes the session and clears cookies