A community based topic aggregation platform built on atproto
1package routes
2
3import (
4 "Coves/internal/api/middleware"
5 "Coves/internal/atproto/oauth"
6 "net/http"
7 "time"
8
9 "github.com/go-chi/chi/v5"
10 "github.com/go-chi/cors"
11)
12
13// RegisterOAuthRoutes registers OAuth-related endpoints on the router with dedicated rate limiting
14// OAuth endpoints have stricter rate limits to prevent:
15// - Credential stuffing attacks on login endpoints
16// - OAuth state exhaustion
17// - Refresh token abuse
18func RegisterOAuthRoutes(r chi.Router, handler *oauth.OAuthHandler, allowedOrigins []string) {
19 // Create stricter rate limiters for OAuth endpoints
20 // Login endpoints: 10 req/min per IP (credential stuffing protection)
21 loginLimiter := middleware.NewRateLimiter(10, 1*time.Minute)
22
23 // Refresh endpoint: 20 req/min per IP (slightly higher for legitimate token refresh)
24 refreshLimiter := middleware.NewRateLimiter(20, 1*time.Minute)
25
26 // Logout endpoint: 10 req/min per IP
27 logoutLimiter := middleware.NewRateLimiter(10, 1*time.Minute)
28
29 // OAuth metadata endpoints - public, no extra rate limiting (use global limit)
30 r.Get("/oauth/client-metadata.json", handler.HandleClientMetadata)
31 r.Get("/.well-known/oauth-protected-resource", handler.HandleProtectedResourceMetadata)
32
33 // OAuth flow endpoints - stricter rate limiting for authentication attempts
34 r.With(loginLimiter.Middleware).Get("/oauth/login", handler.HandleLogin)
35 r.With(loginLimiter.Middleware).Get("/oauth/mobile/login", handler.HandleMobileLogin)
36
37 // OAuth callback - needs CORS for potential cross-origin redirects from PDS
38 // Use login limiter since callback completes the authentication flow
39 r.With(corsMiddleware(allowedOrigins), loginLimiter.Middleware).Get("/oauth/callback", handler.HandleCallback)
40
41 // Mobile Universal Link callback route (fallback when app doesn't intercept)
42 // This route exists for iOS Universal Links and Android App Links.
43 // When properly configured, the mobile OS intercepts this URL and opens the app
44 // BEFORE the request reaches the server. If this handler is reached, it means
45 // Universal Links failed to intercept.
46 r.With(loginLimiter.Middleware).Get("/app/oauth/callback", handler.HandleMobileDeepLinkFallback)
47
48 // Session management - dedicated rate limits
49 r.With(logoutLimiter.Middleware).Post("/oauth/logout", handler.HandleLogout)
50 r.With(refreshLimiter.Middleware).Post("/oauth/refresh", handler.HandleRefresh)
51}
52
53// corsMiddleware creates a CORS middleware for OAuth callback with specific allowed origins
54func corsMiddleware(allowedOrigins []string) func(next http.Handler) http.Handler {
55 return cors.Handler(cors.Options{
56 AllowedOrigins: allowedOrigins, // Only allow specific origins for OAuth callback
57 AllowedMethods: []string{"GET", "POST", "OPTIONS"},
58 AllowedHeaders: []string{
59 "Accept",
60 "Authorization",
61 "Content-Type",
62 "X-CSRF-Token",
63 },
64 ExposedHeaders: []string{"Link"},
65 AllowCredentials: true,
66 MaxAge: 300, // 5 minutes
67 })
68}