44
55use ChurchCRM \Authentication \AuthenticationManager ;
66use ChurchCRM \Authentication \Requests \APITokenAuthenticationRequest ;
7+ use ChurchCRM \dto \SystemURLs ;
78use ChurchCRM \Utils \LoggerUtils ;
89use Laminas \Diactoros \Response ;
910use Psr \Http \Message \ServerRequestInterface ;
@@ -50,6 +51,12 @@ public function process(ServerRequestInterface $request, RequestHandlerInterface
5051 'path ' => $ request ->getUri ()->getPath (),
5152 'method ' => $ request ->getMethod ()
5253 ]);
54+
55+ // Check if this is a browser request - redirect to login instead of JSON error
56+ if ($ this ->isBrowserRequest ($ request )) {
57+ return $ this ->redirectToLogin ();
58+ }
59+
5360 $ response = new Response ();
5461 $ errorBody = json_encode (['error ' => gettext ('No logged in user ' ), 'code ' => 401 ]);
5562 $ response ->getBody ()->write ($ errorBody );
@@ -69,4 +76,49 @@ private function isPath(ServerRequestInterface $request, string $pathPart): bool
6976
7077 return false ;
7178 }
79+
80+ /**
81+ * Check if request is from a browser (expects HTML) vs API client (expects JSON)
82+ */
83+ private function isBrowserRequest (ServerRequestInterface $ request ): bool
84+ {
85+ $ path = $ request ->getUri ()->getPath ();
86+
87+ // API routes should always return JSON
88+ if (str_contains ($ path , '/api/ ' )) {
89+ return false ;
90+ }
91+
92+ // Check Accept header - browsers typically send text/html
93+ $ acceptHeader = $ request ->getHeaderLine ('Accept ' );
94+ if (!empty ($ acceptHeader )) {
95+ // If client explicitly wants JSON, it's an API request
96+ if (str_contains ($ acceptHeader , 'application/json ' ) && !str_contains ($ acceptHeader , 'text/html ' )) {
97+ return false ;
98+ }
99+ // If client accepts HTML, treat as browser
100+ if (str_contains ($ acceptHeader , 'text/html ' )) {
101+ return true ;
102+ }
103+ }
104+
105+ // Check X-Requested-With header (AJAX requests)
106+ if ($ request ->getHeaderLine ('X-Requested-With ' ) === 'XMLHttpRequest ' ) {
107+ return false ;
108+ }
109+
110+ // Default to browser for non-API routes
111+ return true ;
112+ }
113+
114+ /**
115+ * Redirect to the login page
116+ */
117+ private function redirectToLogin (): ResponseInterface
118+ {
119+ $ response = new Response ();
120+ $ redirectUrl = SystemURLs::getRootPath () . '/session/begin ' ;
121+
122+ return $ response ->withStatus (302 )->withHeader ('Location ' , $ redirectUrl );
123+ }
72124}
0 commit comments