I have installed Laravel Passport and configured it according to the documentation. When calling axios.get from my VueJS file, the first call works as expected. the laravel_session Request Cookie is injected into the request, and the authentication passes, returning the resource.
My problem arises when I try to call the axios.get method again. My use case here is a search function. I'm making a call to /api/banking/accounts/search/{search-term} whenever the user types into a text field, using the code below:
remoteMethod(query) {
if (query !== '') {
this.loading = true;
axios.get(
`/api/banking/accounts/search/${escape(query)}`
).then(res => {
this.destinationAccountDirectory = res.data;
this.loading = false;
});
} else {
this.destinationAccountDirectory = [];
}
},
This code works fine without any auth:api middleware on the route, and for the first time with auth:api middleware. As can be seen from the screenshots below, the laravel_token value changes and is rejected on subsequent calls to the API.
**I've tried to removed the \Laravel\Passport\Http\Middleware\CreateFreshApiToken that was added to the web middleware group during passport installation, which seemed to have temporarily solved the issue, until I receive a 419 on a request shortly after. What could be causing the new laravel_tokens to be rejected? **
I solved this by removing the web middleware from my API route. Why it was there in the first place, I have no idea.
I changed my api.php from
Route::group([
'middleware' => [
'web',
'auth:api']], function() {
Route::post('/banking/transactions', 'TransactionController#store');
Route::get('/banking/accounts', 'BankAccountDirectoryController#index');
Route::get('/accounts/{account}', 'BankAccountDirectoryController#show');
Route::get('/banking/accounts/search/{term?}', 'BankAccountDirectoryController#search');
});
to
Route::group([
'middleware' => [
'auth:api']], function() {
Route::post('/banking/transactions', 'TransactionController#store');
Route::get('/banking/accounts', 'BankAccountDirectoryController#index');
Route::get('/accounts/{account}', 'BankAccountDirectoryController#show');
Route::get('/banking/accounts/search/{term?}', 'BankAccountDirectoryController#search');
});
Should the API routes be under the web group to benefit from the middleware, or is it purely for UI? Am I safe to do this?
Related
I'm starting up a learning project with Laravel, VueJS. I'm using Sanctum cookie based.
I have got the authentication working with the help of several tutorials, but none of the tutorials covers the piece of checking if your session is expired or not. The tutorials that where covering it where using LocalStorage, and what I red about is that you should avoid LocalStorage.
I'm looking for a simple possibility to check if a user is still authenticated and if not, then redirect them to the login page, or even better, show a modal to login and go further where they are.
22 jan 2021 Still haven't got he answer :(
I'm fairly new to VueJS, Vuex and so on :)
Thanks for the help !
Try this, its what I've been using so far. Its not very ideal but works out fine so far until I can make it better.
Put this in App.vue created method
// each call needs csrf token to work, so we call this on app load once.
axios.get(axios.rootURL + '/sanctum/csrf-cookie').catch(() => {
alert('Something went wrong, Contact admin <br> ErrorCode: csrf')
})
// this part is not necessary, you may adapt as required
// let isLoggedIn = localStorage.getItem('isLoggedIn') ? true : false
// this.setIsLoggedIn(isLoggedIn)
axios.interceptors.request.use(
config => {
return config
},
error => {
return Promise.reject(error)
}
)
// this is the actual part you need, here we check on each call
// if we get error 401 which is unauthenticated we redirect to login. That's it
axios.interceptors.response.use(
response => {
return response
},
error => {
if (error.response.status === 401) {
this.$router.push({ name: 'login' })
localStorage.removeItem('isLoggedIn')
this.setIsLoggedIn(false)
}
return Promise.reject(error)
}
)
Lumen is sending response to the client side according to the order of requests. It is holding next response until previous response completes. I need to make it asynchronously
Laravel Lumen Routing Code:
$router->get('waist-xxxxxxx/v20/', ['uses' => 'DemoController#fnDemoFunction']);
$router->get('waist-xxxxxxx/v20/{serverSideRowUuid}', ['uses' => 'DemoController#fnDemoFunction']);
$router->post('waist-xxxxxxx/v20/', ['uses' => 'DemoController#create']);
$router->put('waist-xxxxxxx/v20/{serverSideRowUuid}', ['uses' => 'DemoController#update']);
$router->options('waist-xxxxxxx/v20', function () {
return response('OK', \Illuminate\Http\Response::HTTP_NO_CONTENT)
->header('Access-Control-Allow-Credentials', 'true')
->header('Connection', 'keep-alive');
});
$router->options('waist-xxxxxxx/v20/{serverSideRowUuid}', function () {
return response('OK', \Illuminate\Http\Response::HTTP_NO_CONTENT)
->header('Access-Control-Allow-Credentials', 'true')
->header('Connection', 'keep-alive');
});
Vue.js App code for API calling:
export default {
methods: {
async mxGetDataFromDb() {
/*
TODO: Need to restrict the load to current data
api is vuex-orm-axios plugin function
When using json-server backend the code is:
*/
console.log('reminders req sent')
const proRemsFromDB = await clientSideTable.api().get(clientSideTable.apiUrl)
console.log('reminders recd')
if (proRemsFromDB.ok) {
}
},
},
}
Here is a screenshot for better understanding: enter image description here
I suspect you're using php artisan serve to test with.
This command utilizes the built-in PHP development server. It's a great tool, but it can only handle one request at a time:
The web server runs only one single-threaded process, so PHP applications will stall if a request is blocked.
In general, while php artisan serve is great for quick testing, you'll want to set up something like Laravel Homestead or some other more robust development environment long-term.
I've got a question regarding Laravel framework (vers. 5.2) and the authentication. I have 2 domains which represent a software. let's call them https://azure.mydomain.com and https://azuresoftware.mydomain.com.
The Laravel application is hosted on the domain https://azuresoftware.mydomain.com. https://azure.mydomain.com is just a CMS framework which is providing some information about the website.
Now I want to display different menus, if the user is logged in or not on https://azure.mydomain.com. I thought, I can do a fetch request to https://azuresoftware.mydomain.com/ and use the Laravel methods Auth::check() to check if the user is already logged in or not. I know that this is a CORS fetch request, but this is not the issue. I've allowed in the IIS webserver requests from https://azure.mydomain.com. The request works fine and also just a simple request. But actually Auth::check() is always returning false, even when I'm logged in on the software side.
This is my code so far:
<script>
fetch('https://azuresoftware.mydomain.com/checkLogin', {
method: 'GET',
headers: {
'Content-Type': 'text/plain'
}
})
.then(function(res) {
return res.json()
})
.then(function(data) {
if(data.isLoggedIn) {
// do some stuff...
}
else
{
// do some other stuff...
}
});
</script>
routes.php:
Route::group(['middleware' => 'web'], function () {
...
Route::get('checkLogin', function() {
return json_encode(['isLoggedIn'=>\Auth::check()]);
});
...
I'm sure, I forgot something essential, why it is not working this way.
This is due to the fact that AJAX calls only send cookies if the url you're calling is on the same domain as your calling script.
See Cross domain POST request is not sending cookie Ajax Jquery for more information.
The Sanctum Auth system on my local machine works well and I have no errors. But my deployed app is having trouble with authorizing a user. When I login it sends a request to get the user data then redirects. After auth completes you are redirected and the app make a GET request for more data. This GET route is guarded using laravel sanctum. But the backend is not registering that the user has made a successful login attempt so it sends a 401 Unauthorized error. Here is some code...
loadUser action from store.js
actions: {
async loadUser({ commit, dispatch }) {
if (isLoggedIn()) {
try {
const user = (await Axios.get('/user')).data;
commit('setUser', user);
commit('setLoggedIn', true);
} catch (error) {
dispatch('logout');
}
}
},
}
Route Guard on the routs.js checking to see isLoggedIn (which is just a boolean store locally)
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// if (to.meta.requiresAuth) {
if (isLoggedIn()) {
next();
} else {
next({
name: 'home'
});
}
} else {
next();
}
})
It was pointed out that I had forgotten the withCredetials setting for axios in bootstrap.js. I made this addition but my issue still remains.
window.axios = require('axios');
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
window.axios.defaults.withCredentials = true;
Route middleware guard on the server side (this is where the request is getting turned away)
Route::middleware('auth:sanctum')->group(function () {
Route::apiResource('trucks', 'Api\TruckController');
});
In the laravel cors.php config file I changed the "supports_credentials" from false to true
'supports_credentials' => true,
It seems to me that the cookie information is not being over the api call (but I'm really not sure). This setup is working on my local machine but not on the server that I have deployed to.
Needed to add an environment variable to the .env file for SANCTUM_STATEFUL_DOMAINS and made that equal the domain name.
In the laravel sanctum.php config file...
'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', 'localhost,127.0.0.1')),
I have a situation. I am trying to create an application that will have only one route file, api.php for both the web app (spa) and mobile app.The problem is now that the entire application is stateless (as it should be), I can't even login. Because, routes in api.php expect a token in the request header, which I don't know how to provide.I am using vue in the front-end I have this simple strategy:<button #click="login">Login</button>and the login method looks like this:
login(){
axios.post('login',this.credentials)
.then( window.location = "http://localhost:3000/app" );
}
And my route definition:
Route::group(['middleware' => ['role:admin']], function () {
Route::get('app', function () {
return view('index');
});
});
But it redirects me back to the login page. I wish I could do something like window.header = Bearer myLongToken. I am using JWT, if that helps.
Update:
It looks like there is something else going on. If I remove the role:admin middleware, then I get redirected to desired route, but if I add the middleware, I get redirected back to the login route even if the credentials are valid.
// Route::group(['middleware' => ['role:admin']], function () {
Route::get('app', function () {
return view('index');
});
// });