Connection refused error.- axios and reactjs - ajax

I have made the Login page The UI and integrate the API through the Axios library and when I hit the API it shows the error
xhr.js:166 OPTIONS https://testapi.halanx.com/rest-auth/login/ net::ERR_CONNECTION_REFUSED
URL of App UI: https://assignment-task1.herokuapp.com/
URL OF code: https://github.com/rahulkhowal/Query-Related-to-Internship-Task---Web-Development
This is the code of login
handleSubmit=(e)=>{
e.preventDefault()
//console.log("Ihi")
const Login={
username:this.state.email || ' ',
password: this.state.password || ''
}
console.log("Login", Login);
axios.post('http://testapi.halanx.com/rest-auth/login/', {...Login})
.then(res => {
console.log(res);
console.log(res.data);
axios.defaults.headers.common['Authorization'] =res.data;
cookies.set('loggedIn', res.data, {path:'/'})
this.props.history.push('Dashboard')
})
.catch(error => {
if(!error.response){
this.errorStatus='Error:Network Error';
}else{
this.errorStatus=error.respose.data.message;
}
})
}

It is not the problem with your code. Your webserver is refusing a preflight for your POST request. Probably you are trying to call to authentication service from different domain.
Please refer to this doc.
https://developer.mozilla.org/en-US/docs/Glossary/Preflight_request

Related

The first API call after login is unauthorized until page reload (Laravel Sanctum & VueJS)

I am trying to resolve this 401 issue for some time. After logging in and obtaining the token I am setting it as a header, but keep getting 401 exception on first load of the page. The error goes away after refresh. It seems that the token is not written to store or localStorage the first time around. Here's my code for login (I set the token to state.token in the mutation):
retrieveToken(context, credentials) {
return new Promise((resolve, reject) => {
axios.post('api/login', {
email: credentials.email,
password: credentials.password,
})
.then(response => {
const token = response.data.access_token
localStorage.setItem('access_token', token)
context.commit('RETRIEVE_TOKEN', token)
resolve(response)
console.log(response.data)
})
.catch(error => {
console.log(error)
reject(error)
})
})
},
And that's how I set it to header (setting it from localStorage doesn't solve the issue):
const authorizedApiClient = axios.create({
baseURL: process.env.VUE_APP_PRODUCTION_URL,
headers: {
Accept: 'application/json',
'Authorization': `Bearer ${store.getters.token}`
}
})
This behavior baffles me. Is there any theory or suggestions on how to debug?
I guess when the axios client is created the token is not yet retrieved from api. Try setting the header before each request using an interceptor:
const authorizedApiClient = axios.create({
baseURL: process.env.VUE_APP_PRODUCTION_URL,
headers: {
Accept: 'application/json'
}
})
authorizedApiClient.interceptors.request.use((config) => {
if (store.getters.token){ // or get it from localStorage
config.headers["Authorization"] = "Bearer " + store.getters.token
}
return config
})

Spring security does not redirect after successful login authentication

I am using spring security + thymeleaf to recognise my css and javascript files. These css and javascript files make up my front end login page, and for special reasons, my login form is within a js file and i include this file in my main html file. To authenticate the login credentials, a custom /POST request needs to be called using javascript like below. This function below executes when the form submit button is pressed.
function submitForm() {
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
var urlencoded = new URLSearchParams();
urlencoded.append("username", "<removed>");
urlencoded.append("password", "<removed>");
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow'
};
fetch("http://localhost:8080/userAuth", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
}
Controller to handle successful login end point
#Controller
public class LoginSuccessController {
#GetMapping("/login_success")
public String success() {
return "success";
}
}
On the browser, I can infer that authentication is successful and there is something that happens related to my successful login endpoint. However, my browser remains at localhost:8080/login and does not redirect to the login_success endpoint. I am unable to figure out why so. Any help is much appreciated.
Browser network activity after submit button
because you use ajax. if you check networks tab I believe you will see response ans 301/302 with Location header.
Edit: you have to either use plain html form or redirect manually from js side
Edit 2:
fetch("http://localhost:8080/userAuth", requestOptions)
.then(response => response.text())
.then(result => {
// do some stuff with response
location.href = '/my-success-page-after-login'; // <- here is redirect
})
.catch(error => console.log('error', error));
Explanation: the problem is that browser doesn't follow redirect response for AJAX calls. Ajax call will just return you a response from server(redirect with 301/302 status code in your case) but this will NOT make browser to follow that redirect

Where to add axios interceptors code in vue js

I am using vue js as frontend with laravel. I am using laravel passport for auth, now i wants to show some error message once received 401 unauthentic error message that mostly occurs when my token expired. so to do this i am using axios interceptors my code is like
axios.interceptors.response.use(function (response) {
return response
}, function (error) {
// const { config, response: { status } } = error
const { config, response } = error
const originalRequest = config
if (response && response.status === 401) {
//notication or redirection
this.$vs.notify({
title: 'Error',
text: response.data['message'],
iconPack: 'feather',
icon: 'icon-check-circle',
color: 'danger'
})
}
return Promise.reject(error)
})
Now Question is that where i put this code in vue js so that it call after every request & so an error message shown & redirect to login once get 401 unauthorized..
Any Suggestion from anyone.
Thanks in advance!!
app.js or add them to separate file and include in app.js. There is post about this https://medium.com/#yaob/how-to-globally-use-axios-instance-and-interceptors-e28f351bb794

Vuejs Laravel Passport - what should I do if access token is expired?

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.

Can't use fetch api in laravel, redirect login page

I'm trying to use fetch api with laravel, but the request goes to the login url, not the given url.
for example;
route
//also this route group has auth and admin middlewares (checks user is authenticated and is admin)
Route::delete("media/delete/{id}", ["as" => "admin.posts.media.delete", "uses" => "AdminController#deletePostMedia"]);
ajax
fetch("../../media/delete/" + id, {
method: "DELETE",
headers: new Headers({
"X-CSRF-TOKEN": document.head.querySelector("[name=csrf-token]").content
})
})
it gives me the below error:
DELETE http://commerce.test/login 405 (Method Not Allowed)
as you can see above, the request goes to login url, not given url..
How can I fix this?
Laravel by default includes axios for ajax requests and it's very easy to use, have a look here.
In your example you'd write something like this:
axios.delete('/media/delete/' + id)
.then(response => {
console.log(response.data);
})
.catch(error=> {
console.log(error);
});

Resources