261

I'm trying to implement the following code, but something is not working. Here is the code:

      var session_url = 'http://api_address/api/session_endpoint';
      var username = 'user';
      var password = 'password';
      var credentials = btoa(username + ':' + password);
      var basicAuth = 'Basic ' + credentials;
      axios.post(session_url, {
        headers: { 'Authorization': + basicAuth }
      }).then(function(response) {
        console.log('Authenticated');
      }).catch(function(error) {
        console.log('Error on Authentication');
      });

It's returning a 401 error. When I do it with Postman there is an option to set Basic Auth; if I don't fill those fields it also returns 401, but if I do, the request is successful.

Any ideas what I'm doing wrong?

Here is part of the docs of the API of how to implement this:

This service uses Basic Authentication information in the header to establish a user session. Credentials are validated against the Server. Using this web-service will create a session with the user credentials passed and return a JSESSIONID. This JSESSIONID can be used in the subsequent requests to make web-service calls.*

raaaay
  • 496
  • 7
  • 14
Emmanuel
  • 2,957
  • 3
  • 14
  • 17

10 Answers10

378

There is an "auth" parameter for Basic Auth:

auth: {
  username: 'janedoe',
  password: 's00pers3cret'
}

Source/Docs: https://github.com/mzabriskie/axios

Example:

await axios.post(session_url, {}, {
  auth: {
    username: uname,
    password: pass
  }
});
trademark
  • 565
  • 4
  • 21
andyrandy
  • 72,880
  • 8
  • 113
  • 130
  • 8
    hello, how can I set that into all the axios call? I need to add Basic auth to all ajax calling. axios.defaults.auth = { username: 'dd', password: '##'} this is not working for me. – Lead Developer Feb 20 '18 at 12:53
  • maybe this helps: https://gist.github.com/EQuimper/dc5fe02dcaca4469091729e1313f78d1 – andyrandy Feb 20 '18 at 15:16
  • btw, you can als write a wrapper around axios for those kind of things – andyrandy Feb 20 '18 at 15:17
  • I made wrapper for that. but that api gives me 401 error – Lead Developer Feb 20 '18 at 15:20
  • axios.defaults.headers.common['Authorization'] = "Basic token". I can not use this sir because I don't know the token! I know only username and password for Basic Auth. when I add username password in postman, api is working. at that time, Authorization header is made automatically (maybe calculated?). I don't know the token, so I can not assign that directly. how can I solve this problem? – Lead Developer Feb 20 '18 at 15:22
  • then use a wrapper. if you get an error, you did something wrong - no clue what exactly without knowing the code, but you should create a separate question on stackoverflow for that – andyrandy Feb 20 '18 at 16:03
  • 2
    @hkg328 you need to encode the string username:password to base64 if you want to manually set the header. something like import btoa from 'btoa-lite'; token = btoa(username + ':' + password); then set the header to 'Basic ' + token; – shrumm Mar 19 '18 at 17:25
  • should show the code where this will be used. It is confusing just to show an object, without showing how it will be used – Ravi May 21 '18 at 15:36
  • stackoverflow is not a platform to share full code, everyone who worked with axios would know exactly how to use parameters and there is even a link to the docs. better concentrate on the important things, i dont like to post unneccessary code ;) – andyrandy May 26 '18 at 06:46
104

The reason the code in your question does not authenticate is because you are sending the auth in the data object, not in the config, which will put it in the headers. Per the axios docs, the request method alias for post is:

axios.post(url[, data[, config]])

Therefore, for your code to work, you need to send an empty object for data:

var session_url = 'http://api_address/api/session_endpoint';
var username = 'user';
var password = 'password';
var basicAuth = 'Basic ' + btoa(username + ':' + password);
axios.post(session_url, {}, {
      headers: { 'Authorization': + basicAuth }
}).then(function(response) {
      console.log('Authenticated');
}).catch(function(error) {
      console.log('Error on Authentication');
});

The same is true for using the auth parameter mentioned by @luschn. The following code is equivalent, but uses the auth parameter instead (and also passes an empty data object):

var session_url = 'http://api_address/api/session_endpoint';
var uname = 'user';
var pass = 'password';
axios.post(session_url, {}, {
      auth: {
            username: uname,
            password: pass
      }
}).then(function(response) {
      console.log('Authenticated');
}).catch(function(error) {
console.log('Error on Authentication');
});
0xInfection
  • 2,676
  • 1
  • 19
  • 34
pillravi
  • 4,035
  • 5
  • 19
  • 33
  • no need for that Nov 2020: https://github.com/axios/axios#axiosrequestconfigdG9tbzp0b21vOTgy – cikatomo Nov 05 '20 at 07:35
  • Didn`t work with auth object as in second code sample. WOrking fine with base64 conversion as shown in first code sample. – Gaurav Chauhan Apr 01 '21 at 08:39
  • If like me you found this was a valid solution but was still throwing errors, I added `"Content-Type" : "application/x-www-form-urlencoded"` to the header and bingo, finally worked – user1205577 Aug 03 '23 at 18:39
26

Hi you can do this in the following way

    var username = '';
    var password = ''

    const token = `${username}:${password}`;
    const encodedToken = Buffer.from(token).toString('base64');
    const session_url = 'http://api_address/api/session_endpoint';

    var config = {
      method: 'get',
      url: session_url,
      headers: { 'Authorization': 'Basic '+ encodedToken }
    };

    axios(config)
    .then(function (response) {
      console.log(JSON.stringify(response.data));
    })
    .catch(function (error) {
      console.log(error);
    });
raaaay
  • 496
  • 7
  • 14
srijan439
  • 401
  • 5
  • 7
13

For some reasons, this simple problem is blocking many developers. I struggled for many hours with this simple thing. This problem as many dimensions:

  1. CORS (if you are using a frontend and backend on different domains et ports.
  2. Backend CORS Configuration
  3. Basic Authentication configuration of Axios

CORS

My setup for development is with a vuejs webpack application running on localhost:8081 and a spring boot application running on localhost:8080. So when trying to call rest API from the frontend, there's no way that the browser will let me receive a response from the spring backend without proper CORS settings. CORS can be used to relax the Cross Domain Script (XSS) protection that modern browsers have. As I understand this, browsers are protecting your SPA from being an attack by an XSS. Of course, some answers on StackOverflow suggested to add a chrome plugin to disable XSS protection but this really does work AND if it was, would only push the inevitable problem for later.

Backend CORS configuration

Here's how you should setup CORS in your spring boot app:

Add a CorsFilter class to add proper headers in the response to a client request. Access-Control-Allow-Origin and Access-Control-Allow-Headers are the most important thing to have for basic authentication.

    public class CorsFilter implements Filter {

...
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        HttpServletRequest request = (HttpServletRequest) servletRequest;

        response.setHeader("Access-Control-Allow-Origin", "http://localhost:8081");
        response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH");
        **response.setHeader("Access-Control-Allow-Headers", "authorization, Content-Type");**
        response.setHeader("Access-Control-Max-Age", "3600");

        filterChain.doFilter(servletRequest, servletResponse);

    }
...
}

Add a configuration class which extends Spring WebSecurityConfigurationAdapter. In this class you will inject your CORS filter:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
...
    @Bean
    CorsFilter corsFilter() {
        CorsFilter filter = new CorsFilter();
        return filter;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http.addFilterBefore(corsFilter(), SessionManagementFilter.class) //adds your custom CorsFilter
          .csrf()
          .disable()
          .authorizeRequests()
          .antMatchers("/api/login")
          .permitAll()
          .anyRequest()
          .authenticated()
          .and()
          .httpBasic()
          .authenticationEntryPoint(authenticationEntryPoint)
          .and()
          .authenticationProvider(getProvider());
    }
...
}

You don't have to put anything related to CORS in your controller.

Frontend

Now, in the frontend you need to create your axios query with the Authorization header:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://unpkg.com/vue"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="app">
    <p>{{ status }}</p>
</div>
<script>
    var vm = new Vue({
        el: "#app",
        data: {
            status: ''
        },
        created: function () {
            this.getBackendResource();
        },
        methods: {
            getBackendResource: function () {
                this.status = 'Loading...';
                var vm = this;
                var user = "aUserName";
                var pass = "aPassword";
                var url = 'http://localhost:8080/api/resource';

                var authorizationBasic = window.btoa(user + ':' + pass);
                var config = {
                    "headers": {
                        "Authorization": "Basic " + authorizationBasic
                    }
                };
                axios.get(url, config)
                    .then(function (response) {
                        vm.status = response.data[0];
                    })
                    .catch(function (error) {
                        vm.status = 'An error occured.' + error;
                    })
            }
        }
    })
</script>
</body>
</html>

Hope this helps.

Erick Audet
  • 349
  • 5
  • 13
12

The solution given by luschn and pillravi works fine unless you receive a Strict-Transport-Security header in the response.

Adding withCredentials: true will solve that issue.

  axios.post(session_url, {
    withCredentials: true,
    headers: {
      "Accept": "application/json",
      "Content-Type": "application/json"
    }
  },{
    auth: {
      username: "USERNAME",
      password: "PASSWORD"
  }}).then(function(response) {
    console.log('Authenticated');
  }).catch(function(error) {
    console.log('Error on Authentication');
  });
raaaay
  • 496
  • 7
  • 14
Leonard Saers
  • 649
  • 9
  • 28
7

If you are trying to do basic auth, you can try this:

const username = ''
const password = ''

const token = Buffer.from(`${username}:${password}`, 'utf8').toString('base64')

const url = 'https://...'
const data = {
...
}

axios.post(url, data, {
  headers: {
 'Authorization': `Basic ${token}`
},
})

This worked for me. Hope that helps

fotiecodes
  • 460
  • 6
  • 7
4

An example (axios_example.js) using Axios in Node.js:

const axios = require('axios');
const express = require('express');
const app = express();
const port = process.env.PORT || 5000;

app.get('/search', function(req, res) {
    let query = req.query.queryStr;
    let url = `https://your.service.org?query=${query}`;

    axios({
        method:'get',
        url,
        auth: {
            username: 'xxxxxxxxxxxxx',
            password: 'xxxxxxxxxxxxx'
        }
    })
    .then(function (response) {
        res.send(JSON.stringify(response.data));
    })
    .catch(function (error) {
        console.log(error);
    });
});

var server = app.listen(port);

Be sure in your project directory you do:

npm init
npm install express
npm install axios
node axios_example.js

You can then test the Node.js REST API using your browser at: http://localhost:5000/search?queryStr=xxxxxxxxx

Ref: https://github.com/axios/axios

Yuci
  • 27,235
  • 10
  • 114
  • 113
4
const auth = {
            username : 'test',
            password : 'test'
        }
const response =  await axios.get(yourUrl,{auth}) 

this is work if you use basic auth

2

I just faced this issue, doing some research I found that the data values has to be sended as URLSearchParams, I do it like this:

getAuthToken: async () => {
const data = new URLSearchParams();
data.append('grant_type', 'client_credentials');
const fetchAuthToken = await axios({
  url: `${PAYMENT_URI}${PAYMENT_GET_TOKEN_PATH}`,
  method: 'POST',
  auth: {
    username: PAYMENT_CLIENT_ID,
    password: PAYMENT_SECRET,
  },
  headers: {
    Accept: 'application/json',
    'Accept-Language': 'en_US',
    'Content-Type': 'application/x-www-form-urlencoded',
    'Access-Control-Allow-Origin': '*',
  },
  data,
  withCredentials: true,
});
return fetchAuthToken;

},

0

I used axios.interceptors.request.use to configure Basic auth credentials. I have a Backend Springboot(with SpringSecurity) application with a simple GET endpoint. The Frontend VueJs app and Backend runs on different ports.

axios.js

import axios from "axios";

const api = axios.create({
  baseURL: "http://api_address",
  timeout: 30000,
});

api.interceptors.request.use(
  async (config) => {
    const basicAuthCredentials = btoa("xxxx" + ":" + "xxxx");
    config.headers.common["Authorization"] = "Basic " + basicAuthCredentials;
    return config;
  },
  (error) => {
    return Promise.reject(error);
  }
);

export default api;

backend.js

import axios from "@/services/axios";

const BackendAPI = {

  listUsers: async () => {
    return axios({
      url: '/users',
      method: 'GET',
      responseType: 'json',
    });
  },
};

export { BackendAPI };

Followed by the VUE component Users.vue

...
<script>
import { BackendAPI } from '@/services/backend';

export default {
  name: "Users",
  data() {
    return {
      usersList: [],
    }
  },
  methods: {
    async listUsers() {
      const response = await BackendAPI.listUsers();
      this.usersList = response.data;
    },
  },
};
</script>

The backend spring SecurityConfig.java with httpBasic as authentication and both cors and csrf disabled.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests()
        .antMatchers("/actuator/*")
        .permitAll()
        .anyRequest()
        .authenticated()
        .and()
        .httpBasic()
        .and()
        .cors()
        .disable()
        .csrf()
        .disable();
  }
}