I make @vue/cli 4.5.9 / axios app with data reading from Laravel 7 Backend REST(with "tymon/jwt-auth": "^1.0", "barryvdh/laravel-cors": "^1.0.5") API using axios and I got error :
has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'.
But here I check that all Credentials are filled : https://prnt.sc/vsngs5 I have on client side:
console.log('+login settingCredentialsConfig::')
console.log(settingCredentialsConfig)
axios.post(apiUrl + '/login', userCredentials, settingCredentialsConfig)
.then((response) => {
if (typeof response.data.access_token === 'undefined' || typeof response.data.user === 'undefined') {
commit('auth_error') // call auth_error mutation to make changes to vuex store
bus.$emit('authLoggedError')
return
}
I import settingCredentialsConfig from setings file defined as :
export const settingCredentialsConfig = {
withCredentials:true,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Credentials':true
}
}
and in src/main.js axios defined :
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import axios from 'axios'
export const bus = new Vue()
axios.defaults.crossDomain = true
let apiUrl = process.env.VUE_APP_API_URL
Vue.config.productionTip = false
Vue.prototype.$http = axios
Vue.config.productionTip = false
import Vue2Filters from 'vue2-filters'
Vue.use(Vue2Filters)
new Vue({
router,
store,
bus,
render: h => h(App)
}).$mount('#app')
Vue.use({
install (Vue) {
Vue.prototype.$api = axios.create({
baseURL: apiUrl
})
}
})
In other vue page I have request to backend using the same settingCredentialsConfig var and it works ok. But it does not refere auth of backend User model. On backenbd part I have app/User.php :
<?php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Tymon\JWTAuth\Contracts\JWTSubject; // JWT SUPPORT
class User extends Authenticatable implements JWTSubject // JWT SUPPORT
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* @var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function getJWTIdentifier() // JWT SUPPORT
{
return $this->getKey();
}
public function getJWTCustomClaims() // JWT SUPPORT
{
return [];
}
}
In app/Http/Controllers/API/AuthController.php :
<?php
namespace App\Http\Controllers\API;
use Auth;
use Config;
use DB;
use Validator;
use Carbon\Carbon;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use App\User;
//use Illuminate\Support\Str;
class AuthController extends Controller
{
protected $maxAttempts = 1; // Default is 5
protected $decayMinutes = 1; // Default is 1
/**
* Create a new AuthController instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('jwt.auth', ['except' => ['login', 'register', 'activate']]);
}
public function login(Request $request)
{
$credentials = $request->only('email', 'password');
\Log::info('LOGIN +1 $credentials ::');
if ($token = $this->guard('api')->attempt($credentials /*,['exp' => \Carbon\Carbon::now()->addHours(4)->timestamp]*/)) {
$loggedUser = $this->guard('api')->user();
\Log::info('LOGIN +2 $loggedUser ::');
return $this->respondWithToken($token);
}
\Log::info('LOGIN -3 ::');
return response()->json(['error' => 'Unauthorized'], 401);
}
public function getAuthenticatedUser()
{
try {
\Log::info('-1 getAuthenticatedUser ::');
if ( ! $user = JWTAuth::parseToken()->authenticate()) {
return response()->json(['user_not_found'], 404);
}
} catch (Tymon\JWTAuth\Exceptions\TokenExpiredException $e) {
\Log::info('-2 getAuthenticatedUser ::');
return response()->json(['token_expired'], $e->getStatusCode());
} catch (Tymon\JWTAuth\Exceptions\TokenInvalidException $e) {
\Log::info('-3 getAuthenticatedUser ::');
return response()->json(['token_invalid'], $e->getStatusCode());
} catch (Tymon\JWTAuth\Exceptions\JWTException $e) {
\Log::info('-4 getAuthenticatedUser ::');
return response()->json(['token_absent'], $e->getStatusCode());
}
// the token is valid and we have found the user via the sub claim
return response()->json(compact('user'));
}
public function me()
{
return response()->json($this->guard('api')->user());
}
public function logout()
{
\Log::info('-1 logout ::' . print_r(-1, true));
$this->guard('api')->logout();
return response()->json(['message' => 'Successfully logged out']);
}
public function refresh()
{
return $this->respondWithToken($this->guard()->refresh());
}
protected function respondWithToken($token)
{
$loggedUser = $this->guard()->user();
return response()->json([
'access_token' => $token,
'user' => $loggedUser,
'token_type' => 'bearer',
'expires_in' => $this->guard('api')->factory()->getTTL() * 999360 // TOFIX
]);
}
public function guard()
{
return \Auth::Guard('api');
}
}
and in config/cors.php :
<?php
return [
'paths' => ['api/*'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => false,
];
I generated file config/jwt.php with command :
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
and left it unchanged . In file app/Http/Kernel.php :
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'jwt.auth' => 'Tymon\JWTAuth\Middleware\GetUserFromToken',
'jwt.refresh' => 'Tymon\JWTAuth\Middleware\RefreshToken',
...
What did I miss ?
Thanks!
Change the supports_credentials
value in your config/cors.php
file to true
.
Update (more explanation)
You are dealing with requests that require authentication and which might need access to something like cookies. If supports_credentials
is set to false
these are not included in the cross-origin request. By setting the value to true
you're making sure you're including them in the cross-origin requests as well. Otherwise cross-origin requests for authenticated content will not work.