'How to force Laravel API to always return JSON, no redirects
I have a Laravel application that I've built to act only as a JSON API. It has no views, and acts only to support our 1st party SPA. It uses Laravel 8, Fortify, and Sanctum. My SPA lives at my-app.test, and the api at api.my-app.test. The SPA works as expected. However, if I visit one of my authenticated API routes in the browser, e.g. api.my-app.test/someResource, I get an error page telling me "Route [login] not defined.", and the stack trace reveals this code:
vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php:393
protected function unauthenticated($request, AuthenticationException $exception)
{
return $request->expectsJson()
? response()->json(['message' => $exception->getMessage()], 401)
: redirect()->guest($exception->redirectTo() ?? route('login'));
}
I have the following file where I've tried to override the redirectTo and unauthenticated methods, but it doesn't work:
app/Http/Middleware/Authenticate.php
protected function unauthenticated($request, array $guards): JsonResponse
{
return response()->json(['message' => 'Unauthenticated.'], Response::HTTP_UNAUTHORIZED);
}
protected function redirectTo($request)
{
return response()->json(['message' => 'Unauthenticated.'], Response::HTTP_UNAUTHORIZED);
}
When I implement unauthenticated above, it seems it no longer authenticates any of my routes, hitting any API endpoint returns results that should be guarded. When I implement redirectTo above, I get another error saying "Header may not contain more than a single header, new line detected" and I'm not sure where to go from there.
What's the correct way to globally disable all views and redirects, and force Laravel to always return JSON? Is there a way to override expectsJson?
Solution 1:[1]
Just handle the AuthenticationException in your App\Exceptions\Handler, like this:
public function render($request, Throwable $exception)
{
if ($exception instanceof AuthenticationException) {
return response()->json(["error"=>30001, "message"=>"authenticate failed"]);
}
return parent::render($request, $exception);
}
Solution 2:[2]
This code will check the routes containing /api/* then it will return json data and for other routes (not containing /api/* ) will redirect to login page.
Put this code in app/Exceptions/Handler.php
use Illuminate\Auth\AuthenticationException;
protected function unauthenticated($request, AuthenticationException $ex){
if( $request->is('api/*') ) { // for routes starting with `/api`
return response()->json(['success' => false, 'message' => $ex->getMessage()], 401);
}
return redirect('/login'); // for normal routes
}
Solution 3:[3]
You can also override unauthenticated function in app/Exceptions/Handler.php:
protected function unauthenticated($request, AuthenticationException $exception)
{
return response()->json(['message' => $exception->getMessage()], 401);
}
Solution 4:[4]
You should save the information you have saved in the localStorage or sessionStorage or anywhere else after refreshing it so that you do not have any problems. My suggestion is to do this in the app.component.ts , such as the link and sample code below.
I have done the same thing once before. link
// Restore user information from localStorage
const token = localStorage.getItem('token');
const user: User = JSON.parse(localStorage.getItem('user'));
if (token && user) {
this._authService.setCurrentUser = user;
this._authService.setUserLoggedIn = true;
} else {
this._authService.logout();
this._router.navigate(['/login']);
}
I hope this information helps you solve your problem.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Jaren Feng |
| Solution 2 | Rahul Kulabhi |
| Solution 3 | Yszty |
| Solution 4 | Alireza Ebrahimkhani |
