···
···
"github.com/bluesky-social/indigo/atproto/auth/oauth"
"github.com/bluesky-social/indigo/atproto/syntax"
16
+
// mobileCallbackTemplate is the intermediate page shown after OAuth completes
17
+
// before redirecting to the mobile app via custom scheme.
18
+
// This prevents the browser from showing a stale PDS page after the redirect.
19
+
var mobileCallbackTemplate = template.Must(template.New("mobile_callback").Parse(`<!DOCTYPE html>
22
+
<meta charset="utf-8">
23
+
<meta name="viewport" content="width=device-width, initial-scale=1">
24
+
<title>Login Complete - Coves</title>
25
+
<meta http-equiv="refresh" content="1;url={{.DeepLink}}">
27
+
* { box-sizing: border-box; margin: 0; padding: 0; }
29
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
30
+
background: #0B0F14;
34
+
justify-content: center;
35
+
align-items: center;
45
+
margin: 0 auto 16px;
50
+
margin: 0 auto 24px;
51
+
background: #FF6B35;
54
+
align-items: center;
55
+
justify-content: center;
56
+
animation: scale-in 0.3s ease-out;
65
+
@keyframes scale-in {
66
+
0% { transform: scale(0); }
67
+
50% { transform: scale(1.1); }
68
+
100% { transform: scale(1); }
79
+
margin-bottom: 24px;
84
+
background: #1A1F26;
87
+
margin-bottom: 24px;
88
+
display: inline-block;
98
+
border: 2px solid #2A2F36;
99
+
border-top-color: #FF6B35;
100
+
border-radius: 50%;
101
+
animation: spin 1s linear infinite;
102
+
display: inline-block;
103
+
vertical-align: middle;
107
+
to { transform: rotate(360deg); }
113
+
<div class="checkmark">
114
+
<svg viewBox="0 0 24 24">
115
+
<polyline points="20 6 9 17 4 12"></polyline>
118
+
<h1>Login Complete</h1>
119
+
<p class="subtitle">
120
+
<span class="spinner"></span>
121
+
Returning to Coves...
124
+
<div class="handle">@{{.Handle}}</div>
126
+
<p class="hint">If the app doesn't open automatically,<br>you can close this window.</p>
129
+
// Redirect to app immediately
130
+
window.location.href = {{.DeepLink}};
131
+
// Try to close window after a delay
132
+
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)
486
-
// Redirect to mobile app deep link
487
-
http.Redirect(w, r, deepLink, http.StatusFound)
611
+
// Serve intermediate page that redirects to the app
612
+
// This prevents the browser from showing a stale PDS page after the custom scheme redirect
613
+
w.Header().Set("Content-Type", "text/html; charset=utf-8")
614
+
w.Header().Set("Cache-Control", "no-store, no-cache, must-revalidate")
620
+
DeepLink: deepLink,
624
+
if err := mobileCallbackTemplate.Execute(w, data); err != nil {
625
+
slog.Error("failed to render mobile callback template", "error", err)
626
+
// Fallback to direct redirect if template fails
627
+
http.Redirect(w, r, deepLink, http.StatusFound)
// HandleLogout revokes the session and clears cookies