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("/oauth/jwks.json", handler.HandleJWKS)
32
33 // Alternative well-known paths for OAuth metadata
34 r.Get("/.well-known/oauth-jwks.json", handler.HandleJWKS)
35 r.Get("/.well-known/oauth-protected-resource", handler.HandleProtectedResourceMetadata)
36
37 // OAuth flow endpoints - stricter rate limiting for authentication attempts
38 r.With(loginLimiter.Middleware).Get("/oauth/login", handler.HandleLogin)
39 r.With(loginLimiter.Middleware).Get("/oauth/mobile/login", handler.HandleMobileLogin)
40
41 // OAuth callback - needs CORS for potential cross-origin redirects from PDS
42 // Use login limiter since callback completes the authentication flow
43 r.With(corsMiddleware(allowedOrigins), loginLimiter.Middleware).Get("/oauth/callback", handler.HandleCallback)
44
45 // Mobile Universal Link callback route
46 // This route is used for iOS Universal Links and Android App Links
47 // Path must match the path in .well-known/apple-app-site-association
48 // Uses the same handler as web callback - the system routes it to the mobile app
49 r.With(loginLimiter.Middleware).Get("/app/oauth/callback", handler.HandleCallback)
50
51 // Session management - dedicated rate limits
52 r.With(logoutLimiter.Middleware).Post("/oauth/logout", handler.HandleLogout)
53 r.With(refreshLimiter.Middleware).Post("/oauth/refresh", handler.HandleRefresh)
54}
55
56// corsMiddleware creates a CORS middleware for OAuth callback with specific allowed origins
57func corsMiddleware(allowedOrigins []string) func(next http.Handler) http.Handler {
58 return cors.Handler(cors.Options{
59 AllowedOrigins: allowedOrigins, // Only allow specific origins for OAuth callback
60 AllowedMethods: []string{"GET", "POST", "OPTIONS"},
61 AllowedHeaders: []string{
62 "Accept",
63 "Authorization",
64 "Content-Type",
65 "X-CSRF-Token",
66 },
67 ExposedHeaders: []string{"Link"},
68 AllowCredentials: true,
69 MaxAge: 300, // 5 minutes
70 })
71}