4

I face a problem but i don't know where it be and why. I have a backend API based on express4(nodejs) We have implemented Auth with passport.

When i use postman, i log with post on /login. it store a session cookie and all route is now accesible since the cookie is not expired.

But with my frontend based on VueJS. I use Axios for doing the Request. The request seems to be good. but any cookie is stored so the browser do a loopback on he login page.

I have tried without the auth check or not it the same. But on postman it work.

the main.js for Vue:

import Vue from 'vue'
import VueRouter from 'vue-router'
import Axios from 'axios'
Vue.use(VueRouter)

import auth from './utils/auth'

import App from './components/App.vue'

import Login from './components/Login.vue'
import Home from './components/Containers.vue'

require('font-awesome-loader');

function requireAuth (to, from, next) {
  if (!auth.checkAuth()) {
    next({
      path: '/login',
      query: { redirect: to.fullPath }
    })
  } else {
    next()
  }
}

const router = new VueRouter({
  mode: 'history',
  routes: [
    { path: '/', name: 'containers', component: Home, beforeEnter: requireAuth },
    { path: '/login', component: Login },
    { path: '/logout',
      beforeEnter (to, from, next) {
        auth.logout()
        next('/')
      }}
  ]
})

new Vue({
  el: '#app',
  router,
  render: h => h(App)
})

And the auth.js (where the request is done)

import axios from 'axios'
import { API_URL } from '../config/app'

export default {

  user: {
    authenticated: false
  },

  login (email, pass, cb) {
    LoginRequest(email, pass, (res) => {
      this.user.authenticated = res.authenticated
      if (this.user.authenticated) {
        console.log('ok')
        if (cb) cb(true)
      } else {
        console.log('pasok')
        if (cb) cb(false)
      }
    })
  },

  checkAuth () {
    if (getAuth()) {
      this.authenticated = true
    } else {
      this.authenticated = false
    }
  },

  logout (cb) {
    this.user.authenticated = false
    if (cb) cb()
  }
}

function LoginRequest (email, pass, cb) {
  axios.post(API_URL + '/api/login', {
    email: email,
    password: pass
  }).then(response => {
    if (response.status === 200) {
      cb({ authenticated: true })
    } else {
      cb({ authenticated: false })
    }
  }, response => {
    cb({ authenticated: false })
  })
}

function getAuth (cb) {
  axios.get(API_URL + '/me').then(response => {
    return true
  }, response => {
    return false
  })
}

EDIT : my cors use on the backend :

 // allow CORS:
        app.use(function (req, res, next) {
          res.header("Access-Control-Allow-Origin", "*");
          res.header("Access-Control-Allow-Methods", "GET,HEAD,OPTIONS,POST,PUT$
          res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With,$
          next();
        });

Thank !

arckosfr
  • 59
  • 1
  • 1
  • 5

2 Answers2

4

In my experience this tends to be an issue arising from CORS ( Cross-Origin Resource Sharing ).

Namely if your API_URL is not on the same domain as your application's auth.js is running Axios will not be able to send cookies by default. You can read more about how to allow Cross Domain credential use to your API here: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Access-Control-Allow-Credentials

Practically speaking you can use the CORS module https://www.npmjs.com/package/cors to apply the necessary headers in some configuration akin to the following on the server side:

var express = require('express')
  , cors = require('cors')
  , app = express()

app.use(cors({
    origin: "myapp.io",
    credentials: true
}))

It is particularly important that you specify the origin url that your auth.js script is running from otherwise an attacker could use a Cross Site Scripting Attack.

Hopefully that helps!

  • I have already try to see on the CORS problem. but why i don't understand is why on postman it work ? The backend is actually hosted under a domain name but the frontend is running on dev mode locally (localhost:8080) with webpack i have added cors config on the backend in first post. and will try with your solution – arckosfr Feb 14 '17 at 10:48
  • 1
    Postman isn't limited by CORS and will send the cookies with the request regardless of the configuration. This is the same for other similar tools like cURL. – Alexander Christie Feb 14 '17 at 11:00
  • So the problem comes from axios ? – arckosfr Feb 14 '17 at 11:10
  • No the problem is from your API not returning the necessary CORS headers for Axios to send cookies. Without the headers neither Axios or any other JS HTTP library will be able to send the cookies. – Alexander Christie Feb 14 '17 at 11:12
  • 1
    i have tested with the code you paste, just changed origin to "*", or "localhost" but i doesn't change anything – arckosfr Feb 14 '17 at 11:17
  • Maybe i don't understand, but the cookie is not present before i sent the get request, normally it create after the post. but no – arckosfr Feb 14 '17 at 11:28
  • Found the problem, By default axios have withcredential at false so the session can't pass, now it ok ! thanks for your help ! – arckosfr Feb 14 '17 at 11:46
4

You could also globally set axios credentials:

axios.defaults.withCredentials = true

From within the docs:

// `withCredentials` indicates whether or not cross-site Access-Control requests
// should be made using credentials
withCredentials: false, // default
Ulysse BN
  • 10,116
  • 7
  • 54
  • 82