Why I always catch “UnauthorizedHttpException” when the token has expired? How can I catch “TokenExpiredException”??
try it
try {
if (! $user = JWTAuth::parseToken()->authenticate()) {
return response()->json(['user_not_found'], 404);
}
} catch (Tymon\JWTAuth\Exceptions\TokenExpiredException $e) {
return response()->json(['token_expired'], $e->getStatusCode());
}
See: https://github.com/tymondesigns/jwt-auth/wiki/Authentication
Thanks!
To catch the error globally, go to App/Exceptions/Handler.php and replace render method with it:
public function render($request, Exception $exception)
{
if($exception instanceof \Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException){
return response()->json(["error" => $exception->getMessage()], $exception->getStatusCode());
}
return parent::render($request, $exception);
}
Change the App\Exceptions\Handler.
public function render($request, Exception $exception) {
if ($exception instanceof \Tymon\JWTAuth\Exceptions\TokenExpiredException) {
return response()->json(["error" => $exception->getMessage()], 401);
}
return parent::render($request, $exception);
}
Here's some example code to wet your mojo:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Auth\Middleware\Authenticate as Middleware;
use JWTAuth;
use Tymon\JWTAuth\Exceptions\JWTException;
use Tymon\JWTAuth\Exceptions\TokenBlacklistedException;
use Tymon\JWTAuth\Exceptions\TokenExpiredException;
use Tymon\JWTAuth\Exceptions\TokenInvalidException;
class Authenticate extends Middleware
{
/**
* Exclude these routes from authentication check.
*
* @var array
*/
protected $except = [
'api/logout',
'api/refresh',
];
/**
* Ensure the user is authenticated.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
try {
foreach ($this->except as $excluded_route) {
if ($request->path() === $excluded_route) {
\Log::debug("Skipping $excluded_route from auth check...");
return $next($request);
}
}
\Log::debug('Authenticating... '. $request->url());
JWTAuth::parseToken()->authenticate();
return $next($request);
} catch (TokenExpiredException $e) {
\Log::debug('token expired');
try {
$customClaims = [];
$refreshedToken = JWTAuth::claims($customClaims)
->refresh(JWTAuth::getToken());
} catch (TokenExpiredException $e) {
return response()->json([
'error' => 'token_expired',
'refresh' => false,
], 401);
}
return response()->json([
'error' => 'token_expired_and_refreshed',
'refresh' => [
'token' => $refreshedToken,
],
], 401);
} catch (TokenInvalidException $e) {
\Log::debug('token invalid');
return response()->json([
'error' => 'token_invalid',
], 401);
} catch (TokenBlacklistedException $e) {
\Log::debug('token blacklisted');
return response()->json([
'error' => 'token_blacklisted',
], 401);
} catch (JWTException $e) {
\Log::debug('token absent');
return response()->json([
'error' => 'token_absent',
], 401);
}
}
}
Here is some Axios interceptors that function along with that middleware:
import axios from 'axios';
import Swal from 'sweetalert2';
import store from '~/store';
import router from '~/router';
/**
* Request interceptor: for each request to the server,
* attach the auth token if it exists.
*
*/
axios.interceptors.request.use(async (request) => {
try {
const token = store.getters['auth/token'];
if (token) {
request.headers.common.Authorization = `Bearer ${token}`;
}
// https://laravel.com/docs/7.x/broadcasting
// request.headers['X-Socket-Id'] = Echo.socketId()
return request;
} catch (err) {
throw new Error(`axios# Problem with request during pre-flight phase: ${err}`);
}
});
/**
* Response interceptor: for each server error response,
* check if client-side action is needed.
*
*/
axios.interceptors.response.use(response => response, (error) => {
if (!error.config) {
return Promise.reject(error);
}
const { config, data, status } = error.response;
console.log('ERROR RESPONSE', error.response);
if (status >= 500) {
Swal.fire({
icon: 'error',
title: 'Oops...',
text: 'Something went wrong! Please try again.',
confirmButtonText: 'Ok',
});
}
if (status === 429) {
Swal.fire({
icon: 'error',
title: 'Slow down...',
text: "You've been throttled.",
confirmButtonText: 'Ok',
});
}
if ((status === 401) && (data.error === 'token_expired_and_refreshed')) {
store.commit('auth/SAVE_TOKEN', { token: data.refresh.token });
error.config.headers.Authorization = `Bearer: ${store.getters['auth/token']}`;
return axios.request(config); // re-try the request
}
if ((status === 401) && (data.error === 'token_expired')) {
store.commit('auth/LOGOUT');
if (router.currentRoute.name !== 'login') {
router.push({ name: 'login' }).catch(() => {});
}
}
return Promise.reject(error);
});
Most helpful comment
To catch the error globally, go to App/Exceptions/Handler.php and replace render method with it: