Caddy module to require at-proto authentication and restrict routes to DIDs
3

Configure Feed

Select the types of activity you want to include in your feed.

refactor: remove redundant cookie_domain configurations from portal and gate

+15 -60
-9
README.md
··· 65 65 # Default: "Authentication Portal" 66 66 name "My Services" 67 67 68 - # Optional domain for the session cookie. 69 - # Required if the Portal and Gate are on different subdomains. 70 - # e.g., if portal is auth.example.com and gate is app.example.com, set this to example.com 71 - # cookie_domain example.com 72 - 73 68 # Custom UI templates (optional) 74 69 ui { 75 70 # Path to a custom HTML template for the login page. ··· 102 97 # REQUIRED. 103 98 # If the Portal uses a path_prefix (e.g. /auth), append it here (e.g. https://auth.example.com/auth) 104 99 portal_url https://auth.example.com 105 - 106 - # Optional domain for the session cookie. 107 - # Must match the Portal's cookie_domain if it is set. 108 - # cookie_domain example.com 109 100 110 101 # Client ID for Transparent Refresh (Optional) 111 102 # If provided, enables background token refreshing using the shared DB.
+6 -18
gate.go
··· 27 27 // Gate acts as a middleware that guards endpoints 28 28 // and validates the session cookie. 29 29 type Gate struct { 30 - Allow []string `json:"allow,omitempty"` 31 - ClientID string `json:"client_id,omitempty"` // ClientID for session refreshing (e.g. https://example.com/client-metadata.json) 32 - PortalURL string `json:"portal_url,omitempty"` // URL of the auth portal (e.g. http://localhost:8080 or /) 33 - CookieDomain string `json:"cookie_domain,omitempty"` // Optional domain for the session cookie (e.g. example.com) 34 - UI ui.Config `json:"ui,omitempty"` // Custom UI configuration 30 + Allow []string `json:"allow,omitempty"` 31 + ClientID string `json:"client_id,omitempty"` // ClientID for session refreshing (e.g. https://example.com/client-metadata.json) 32 + PortalURL string `json:"portal_url,omitempty"` // URL of the auth portal (e.g. http://localhost:8080 or /) 33 + UI ui.Config `json:"ui,omitempty"` // Custom UI configuration 35 34 36 35 // Dependencies 37 36 app *App ··· 140 139 return d.ArgErr() 141 140 } 142 141 g.PortalURL = d.Val() 143 - case "cookie_domain": 144 - if !d.NextArg() { 145 - return d.ArgErr() 146 - } 147 - g.CookieDomain = d.Val() 148 142 case "ui": 149 143 for nesting := d.Nesting(); d.NextBlock(nesting); { 150 144 switch d.Val() { ··· 206 200 } 207 201 208 202 // Clear local session cookie 209 - http.SetCookie(w, g.sessions.ClearCookie(g.CookieDomain)) 203 + http.SetCookie(w, g.sessions.ClearCookie(strings.Split(host, ":")[0])) 210 204 211 205 portalLogout := fmt.Sprintf("%s/logout?redirect_to=%s", portalURL, url.QueryEscape(currentURL)) 212 206 http.Redirect(w, r, portalLogout, http.StatusFound) ··· 229 223 // We need to extend expiration. 230 224 // Handle lookup might be needed if not in session? 231 225 // Sess has Handle. 232 - cookieDomain := g.CookieDomain 233 - if cookieDomain == "" { 234 - cookieDomain = r.Host 235 - } 236 - cookieDomain = strings.Split(cookieDomain, ":")[0] 237 - 238 226 cookie, err := g.sessions.CreateCookie( 239 227 clientSession.Data.AccountDID, 240 228 sess.Handle, // Keep handle from old cookie 241 229 clientSession.Data.SessionID, 242 230 24*7*time.Hour, 243 - cookieDomain, 231 + strings.Split(r.Host, ":")[0], 244 232 ) 245 233 if err == nil { 246 234 http.SetCookie(w, cookie)
+9 -33
portal.go
··· 25 25 26 26 // Portal is the centralized authentication portal for Path B (Auth Hub). 27 27 type Portal struct { 28 - Name string `json:"name,omitempty"` 29 - Domain string `json:"domain,omitempty"` // Public domain of the portal (e.g. auth.example.com) 30 - CookieDomain string `json:"cookie_domain,omitempty"` // Optional domain for the session cookie (e.g. example.com) 31 - UI ui.Config `json:"ui,omitempty"` // Custom UI configuration 28 + Name string `json:"name,omitempty"` 29 + Domain string `json:"domain,omitempty"` // Public domain of the portal (e.g. auth.example.com) 30 + UI ui.Config `json:"ui,omitempty"` // Custom UI configuration 32 31 33 32 // Paths configuration 34 33 PathPrefix string `json:"path_prefix,omitempty"` ··· 117 116 return d.ArgErr() 118 117 } 119 118 p.Domain = d.Val() 120 - case "cookie_domain": 121 - if !d.NextArg() { 122 - return d.ArgErr() 123 - } 124 - p.CookieDomain = d.Val() 125 119 case "path_prefix": 126 120 if !d.NextArg() { 127 121 return d.ArgErr() ··· 188 182 return nil 189 183 } 190 184 191 - cookieDomain := p.CookieDomain 192 - if cookieDomain == "" { 193 - cookieDomain = p.Domain 194 - } 195 - cookieDomain = strings.Split(cookieDomain, ":")[0] 185 + reqDomain := strings.Split(p.Domain, ":")[0] 196 186 197 187 // Create Session Cookie 198 188 cookie, err := p.sessions.CreateCookie( ··· 200 190 handle, 201 191 sessionData.SessionID, 202 192 24*7*time.Hour, 203 - cookieDomain, 193 + reqDomain, 204 194 ) 205 195 if err != nil { 206 196 p.logger.Error("failed to create session cookie", zap.Error(err)) ··· 212 202 213 203 appNameForLog := p.Name 214 204 if appNameForLog == "" { 215 - appNameForLog = cookieDomain 205 + appNameForLog = reqDomain 216 206 } 217 207 p.logger.Info(fmt.Sprintf("@%s (did: %s) has logged in for %s", handle, sessionData.AccountDID.String(), appNameForLog)) 218 208 ··· 241 231 h := parsed.Host 242 232 if h == p.Domain { 243 233 isAllowedDomain = true 244 - } else if p.CookieDomain != "" { 245 - cleanCookieDomain := strings.TrimPrefix(p.CookieDomain, ".") 246 - if h == cleanCookieDomain || strings.HasSuffix(h, "."+cleanCookieDomain) { 247 - isAllowedDomain = true 248 - } 249 234 } 250 235 } 251 236 ··· 329 314 // Invalidate credential if session exists 330 315 sess, err := p.sessions.VerifyCookie(r) 331 316 332 - cookieDomain := p.CookieDomain 333 - if cookieDomain == "" { 334 - cookieDomain = p.Domain 335 - } 336 - cookieDomain = strings.Split(cookieDomain, ":")[0] 317 + reqDomain := strings.Split(p.Domain, ":")[0] 337 318 338 319 if err == nil || err == session.ErrExpired { 339 320 appNameForLog := p.Name 340 321 if appNameForLog == "" { 341 - appNameForLog = cookieDomain 322 + appNameForLog = reqDomain 342 323 } 343 324 p.logger.Info(fmt.Sprintf("@%s (did: %s) has logged out for %s", sess.Handle, sess.DID, appNameForLog)) 344 325 ··· 347 328 } 348 329 } 349 330 350 - http.SetCookie(w, p.sessions.ClearCookie(cookieDomain)) 331 + http.SetCookie(w, p.sessions.ClearCookie(reqDomain)) 351 332 352 333 // Handle redirect_to for logout 353 334 redirectTo := r.URL.Query().Get("redirect_to") ··· 362 343 h := parsed.Host 363 344 if h == p.Domain { 364 345 isAllowedDomain = true 365 - } else if p.CookieDomain != "" { 366 - cleanCookieDomain := strings.TrimPrefix(p.CookieDomain, ".") 367 - if h == cleanCookieDomain || strings.HasSuffix(h, "."+cleanCookieDomain) { 368 - isAllowedDomain = true 369 - } 370 346 } 371 347 } 372 348