I am creating a simple CRUD operations in laravel by using Vue js along with vue axios and vue router.
Routing is working fine as expected but the issue is when i have save the data by using axios the response i get is 401 unauthorized.
I have protected my route just like this in web.php
Route::get('/{any}', function () {
return view('posts');
})->where('any', '.*')->middleware(['auth']);
And in api.php i have routes like this.
Route::post('/quiz/create-quiz-category', 'QuizCategoryController#store')->middleware(['auth']);
I am currently using laravel default auth system.
Below is my vue component script code.
this.axios.post(uri, {post: this.post}, {
headers: {
'x-csrf-token': document.querySelectorAll('meta[name=csrf-token]')[0].getAttributeNode('content').value,
'Accept' : 'application/json'
}
}).then((response) => {
// this.$router.push({name: 'home'});
});
I appreciate if someone tell me that what wrong with code, and i am not currently using any passport or jwt.
Thanks.
api_token: this.user.api_token
axios.post("http://foo",
{headers: { 'Authorization' : 'Bearer '+ api_token}})
.then(response => {
//action
})
link: https://forum.vuejs.org/t/401-unauthorized-vuejs-laravel-and-passport/59770
or
postComment() {
axios.post('/api/posts/'+this.post.id+'/comment', {
api_token: this.user.api_token,
body: this.commentBox
})
but make sure that you have "user.api_token"
Related
I am working on a project for my self learning that has laravel in the backend and running react native in the front end. I have implemented the login and register screen for my apps. Now I am trying to connect it to my laravel server through its api routes. I was first having CORS issue so I solved it by making a new middleware and editing the kernel.php file as stated in this thread.
CORS Issue with React app and Laravel API
Now I tried to run some tests first with get request my submit function in react is
handleSubmit = async() => {
const email = this.state.email
const pass = this.state.password
const proxyurl = "https://cors-anywhere.herokuapp.com/";
/*TEST FOR GET REQUEST */
let response = await fetch(`http://mobileprediction/api/user?email=${email}&pass=${pass}`, {
headers: {
"Content-Type" : "application/json",
"Accept" : "application/json"
},
})
let result = await response.json()
console.log(result)
}
and my api.php file in the routes of laravel was
Route::get("/user", function (Request $request) {
return $request;
});
and it gave the desired output, but then when I tested the same way with a post request I am getting an empty array no matter what and I am unable to figure out what the problem is
the handlesubmit function in my react native app is
handleSubmit = async() => {
const email = this.state.email
const pass = this.state.password
/*TEST FOR POST REQUEST */
let response = await fetch(`http://mobileprediction/api/user`, {
method: "POST",
header : {
"Content-Type" : "application/json",
"Accept" : "application/json"
},
body : JSON.stringify({
emailid : email,
password : pass
}),
})
let result = await response.json()
console.log(result)
}
and api.php file in laravel is
Route::get("/user", function (Request $request) {
return $request;
});
Route::post("/user", function(Request $request) {
return $request;
});
I think you write your routes in web.php, for your API could write the endpoints in api.php.
Try to comment VerifyCsrfToken middleware in app/Http/Kenrel.php.
it has security issue, but you can do it in your learning steps.
[ https://laravel.com/docs/6.x/routing ] [search CSRF in this link]
Any routes pointing to POST, PUT, or DELETE routes that are defined in the web routes file should include a CSRF token field.
So what I understood is that from the fetch request in react native its not sending just the inputs but rather a page with a body that has json formatted key values. So I cant access data in my server as
$request->param
or with
request("param")
you could get the json formatted string with
$request->json()->all()
but still I couldnt get to the individual values
for me what was working is to get all the contents and then access the values with
$postInput = file_get_contents('php://input');
$data = json_decode($postInput, true);
return ["email" => $data["emailid"] ];
I am using Vuejs SPA with Laravel API as backend. I successfully got the personal access token and store in localStorage and Vuex state like below.
token: localStorage.getItem('token') || '',
expiresAt: localStorage.getItem('expiresAt') || '',
I use the access token every time I send axios request to laravel api. Every thing works well. However, initially the token was set to 1 year expiration so when I develop I didn't care about token being expired and today suddenly I thought what is going to happen if token expired. So I set token expiry to 10 seconds in laravel AuthServiceProvier.php.
Passport::personalAccessTokensExpireIn(Carbon::now()->addSecond(10));
and then I logged in and after 10 seconds, every requests stopped working because the token was expired and got 401 unauthorised error.
In this case, how can I know if the token is expired? I would like to redirect the user to login page if token is expired when the user is using the website.
Be as user friendly as possible. Rather than waiting until the token expires, receiving a 401 error response, and then redirecting, set up a token verification check on the mounted hook of your main SPA instance and have it make a ajax call to e.g. /validatePersonalToken on the server, then do something like this in your routes or controller.
Route::get('/validatePersonalToken', function () {
return ['message' => 'is valid'];
})->middleware('auth:api');
This should return "error": "Unauthenticated" if the token is not valid. This way the user will be directed to authenticate before continuing to use the app and submitting data and then potentially losing work (like submitting a form) which is not very user friendly.
You could potentially do this on a component by component basis rather than the main instance by using a Vue Mixin. This would work better for very short lived tokens that might expire while the app is being used. Put the check in the mounted() hook of the mixin and then use that mixin in any component that makes api calls so that the check is run when that component is mounted. https://v2.vuejs.org/v2/guide/mixins.html
This is what I do. Axios will throw error if the response code is 4xx or 5xx, and then I add an if to check if response status is 401, then redirect to login page.
export default {
methods: {
loadData () {
axios
.request({
method: 'get',
url: 'https://mysite/api/route',
})
.then(response => {
// assign response.data to a variable
})
.catch(error => {
if (error.response.status === 401) {
this.$router.replace({name: 'login'})
}
})
}
}
}
But if you do it like this, you have to copy paste the catch on all axios call inside your programs.
The way I did it is to put the code above to a javascript files api.js, import the class to main.js, and assign it to Vue.prototype.$api
import api from './api'
Object.defineProperty(Vue.prototype, '$api', { value: api })
So that in my component, I just call the axios like this.
this.$api.GET(url, params)
.then(response => {
// do something
})
The error is handled on api.js.
This is my full api.js
import Vue from 'vue'
import axios from 'axios'
import router from '#/router'
let config = {
baseURL : process.env.VUE_APP_BASE_API,
timeout : 30000,
headers : {
Accept : 'application/json',
'Content-Type' : 'application/json',
},
}
const GET = (url, params) => REQUEST({ method: 'get', url, params })
const POST = (url, data) => REQUEST({ method: 'post', url, data })
const PUT = (url, data) => REQUEST({ method: 'put', url, data })
const PATCH = (url, data) => REQUEST({ method: 'patch', url, data })
const DELETE = url => REQUEST({ method: 'delete', url })
const REQUEST = conf => {
conf = { ...conf, ...config }
conf = setAccessTokenHeader(conf)
return new Promise((resolve, reject) => {
axios
.request(conf)
.then(response => {
resolve(response.data)
})
.catch(error => {
outputError(error)
reject(error)
})
})
}
function setAccessTokenHeader (config) {
const access_token = Vue.cookie.get('access_token')
if (access_token) {
config.headers.Authorization = 'Bearer ' + access_token
}
return config
}
/* https://github.com/axios/axios#handling-errors */
function outputError (error) {
if (error.response) {
/**
* The request was made and the server responded with a
* status code that falls out of the range of 2xx
*/
if (error.response.status === 401) {
router.replace({ name: 'login' })
return
}
else {
/* other response status such as 403, 404, 422, etc */
}
}
else if (error.request) {
/**
* The request was made but no response was received
* `error.request` is an instance of XMLHttpRequest in the browser
* and an instance of http.ClientRequest in node.js
*/
}
else {
/* Something happened in setting up the request that triggered an Error */
}
}
export default {
GET,
POST,
DELETE,
PUT,
PATCH,
REQUEST,
}
You could use an interceptor with axios. Catch the 401s and clear the local storage when you do then redirect user to appropriate page.
I am setting up authentication using Laravel (Laravel Framework version 5.8.4) as a REST API, but when I make a post request using Axios, I get back an empty string.
Here is my code in Laravel: "login" endpoint in my main controller:
class MainController extends Controller
{
public function login(Request $request){
$data = [
'message' => 'yo'
];
return Response::json($data, 200);
}
}
Here is my Axios code (from Vue.js method):
methods: {
submitRegistration: function() {
axios.post('http://envelope-api.test/api/auth/login', {
name: this.form.name,
email: this.form.email,
password: this.form.password,
password_confirmation: this.form.password_confirmation
})
.then(function (response) {
console.log("here's the response")
console.log(response);
})
.catch(function (error) {
console.log(error);
});
},
}
Here is the response from Postman (it works!)
{
"message": "yo"
}
Here is the response from my axios request in console (empty string, where's the data?) :
{data: "", status: 200, statusText: "OK", headers: {…}, config: {…}, …}
To get data from axios you should use response.data, not just response.
Edit: Try to respond with the helper.
response()->json($data);
I've got this figured out. Thanks for your help.
I had this chrome extension installed to allow CORS (Cross Origin Resource Sharing) so I could do API requests from localhost (apparently, not needed for Postman?).
I turned it off and installed it locally on Laravel using this post (answer from naabster)
After I installed this way, it worked regularly.
I'm tying to get an API working with Vue.JS 2 and Laravel 5.4.
In my App.vue I have the following code:
export default {
name: 'app',
components: {
Hello
},
created () {
const postData = {
grant_type: 'password',
client_id: 2,
client_secret: 'somesecret',
username: 'my#mail.com',
password: 'password',
scope: ''
}
this.$http.post('http://localhost:8000/oauth/token', postData)
.then(response => {
console.log(response)
const header = {
'Accept': 'application/json',
'Authorization': 'Bearer ' + response.body.access_token
}
this.$http.get('http://localhost:8000/api/test', {headers: header})
.then(response => {
console.log(response)
})
})
}
}
While 'POST' is working without any problems, I just can't get 'GET' working.
My console.log shows the following:
Uncaught (in promise) TypeError: Cannot read property 'access_token'
of undefined at eval (eval at <anonymous> (app.js:810), <anonymous>:33:51)
(anonymous) # App.vue?86c0:29
Unfortunately I couldn't find any explanation why this might be happening.
Does anybody know if they changed 'access_token' to something else or why this is happening?
Hope someone knows :|
Thanks in advance!
Paul
This is off the top of my head.
But i'm sure if you are using axios as your XHR client your response body is under the 'data' parameter and not 'body'.
In summary your reference to access_token would be
'Authorization': 'Bearer ' + response.data.access_token
You can refer to the following link or you can compare with the below git repository
https://github.com/safiahmed4cs/Larave-Passport-with-Vue-Vue-Router-and-axios
which has Laravel App, Laravel Passport,
Axios, Vue Js, Vue Resource and Vue Router are imported as well,
Let me know if you required more info or if you face any issues.
Currently, my restAPI and my App are both hosted on XAMPP. My restAPI url is laravel.dev.
My POST route looks as so...
Route::post('/content', 'Test#save');
and my Controller...
class Test extends Controller
{
public function save()
{
return "here";
}
}
Pretty simple, but now I want to make a POST request to this route from my App. I am trying to that using react's fetch, but I do not know what URL to put since my attempt does not work...
fetch('laravel.dev', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
})
})
.then((response) => response.json())
.then((responseJson) => {
console.log(responseJson);
});
I don't care about passing anything to the route, I just want a successful call to the restAPI server. Right now I'm getting...
POST http://localhost/App/src/laravel.dev 404 (Not Found)
That is also the wrong path as well, as /App is my app and I am trying to call the restAPI server.
What do I need to change to make a successful call?
fetch needs a protocol. Right now it tries to request a "local" resource. Also, add your endpoint:
fetch('http://laravel.dev/content', {
// ...
});