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.*
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
}
});
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');
});
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);
});
For some reasons, this simple problem is blocking many developers. I struggled for many hours with this simple thing. This problem as many dimensions:
CORS (if you are using a frontend and backend on different domains et ports.
Backend CORS Configuration
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.
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');
});
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
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
const auth = {
username : 'test',
password : 'test'
}
const response = await axios.get(yourUrl,{auth})
this is work if you use basic auth
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;
},
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();
}
}
Related
New to React and quite confused...trying to access protected Node routes from React...how do I go about setting this authorization header upon login/registration? I have login / registration working fine for React...just kinda stuck here...
Of course I can set the header in Postman and it works...well in straight Node..
const JwtOptions = {
jwtFromRequest: ExtractJwt.fromHeader("authorization"),
secretOrKey: secret
};
const jwtAuth = new JwtStrategy(JwtOptions, function(payload, done) {
User.findById(payload.sub, function(err, user) {
if (err) {
return done(err, false);
}
if (user) {
done(null, user);
} else {
done(null, false);
}
});
});
With axios, you can add the Authorization header to your requests like this:
axios({ method: 'get', url: '/protected_route', headers: { Authorization: token } });
This is my angular configuration for appending keycloak token with every HTTP request.
module.factory('authInterceptor', function($q, Auth) {
return {
request: function (config) {
var deferred = $q.defer();
if (Auth.authz.token) {
Auth.authz.updateToken(5).success(function() {
config.headers = config.headers || {};
config.headers.Authorization = 'Bearer ' + Auth.authz.token;
deferred.resolve(config);
}).error(function() {
deferred.reject('Failed to refresh token');
});
}
return deferred.promise;
}
};
});
module.config(["$httpProvider", function ($httpProvider) {
$httpProvider.interceptors.push('authInterceptor');
}]);
This is the request I sending to the backend. It seems the request not adding keycloak token, so I'm getting 403 forbidden error.
var formData = new FormData(file);
formData.append('file', file);
return $http({
method: 'POST',
url: API_BASE + '/uploadEmployeeDetails/excelUpload',
headers: {
'Content-Type': undefined
},
data: formData,
transformRequest: function(data, headersGetterFunction) {
return data;
}
});
Backend security config
Since you are able to send the token to the back-end as you can see from the network tab of the browser.
The issue is in the api side on handling the csrf token
If the csrf token is enabled by default you should disable it.
Here is the code with your help, to disable it
http.csrf().disable();
http.addFilterBefore(new CORSFilter(), ChannelProcessingFilter.class)
.authorizeRequests().antMatchers("/**")
.hasAnyRole("ORG_ADMIN", "EMPLOYEE", "PARENT", "STUDENT")
.anyRequest().permitAll();
I'm trying to use Angularjs to send a Post request to My Spring Mvc Controller to login User.But I can't get the Parameter from the request.
this is my Angular js code:
$scope.submit = function () {
$http({
url: serviceURL.LoginUrl,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: {
phone: $scope.userName,
password: $scope.userPsw,
}
}).success(function (data) {
if (!data.state) {
alert(data.errorMsg);
} else {
alert('success');
}
console.log(data);
}).error(function (data) {
console.log('服务器错误!');
});
}
and this is the Spring MVC Controller code:
#RequestMapping(value = "/login", method = RequestMethod.POST)
#ResponseBody
public Object loginUser(Model model,User user, HttpSession session, HttpServletRequest request) {
String phone = request.getParameter("phone");
String password = request.getParameter("password");
System.out.println(phone+","+password);
System.out.println(user.getPhone()+","+user.getPassword());
UserDTO u = userService.loginUser(phone, password);
session.setAttribute("loginUser",u.getUser());
return u;
}
I have searched many resource,they said I should change the header and I have set the header:
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
return true;
}
Actually,I can't request the login url,but after I setHeader,I can request the url,but the parameter is null.
Forgive my poor English, I am newbie in StackOverFlow.
I didn't konw is it have the same question in here ,but I can find the same question. Thank you for your view.
There are two points to fix. At first, data should be converted to a URL-encoded string. You can convert data object with $.param() method or set params property instad of data so it will look like this:
$scope.submit = function () {
$http({
url: serviceURL.LoginUrl,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
params: {
phone: $scope.userName,
password: $scope.userPsw,
}
}).success(function (data) {
if (!data.state) {
alert(data.errorMsg);
} else {
alert('success');
}
console.log(data);
}).error(function (data) {
console.log('服务器错误!');
});
}
The second point is server-side controller method. Here you have to annotate method's arguments appropriately. Consider using #RequestParam annotation.
#RequestMapping(value = "/login", method = RequestMethod.POST)
#ResponseBody
public Object loginUser(
#RequestParam String phone,
#RequestParam String password,
HttpSession session,
HttpServletRequest request
) {
System.out.println(phone + ", " + password);
UserDTO u = userService.loginUser(phone, password);
session.setAttribute("loginUser", u.getUser());
return u;
}
<!--In your script-->
var app = angular.module("myApp", [])
.controller("myController", function($http){
var vm= this;
Posting = function(name)
{
var data = 'name=' + name;
var url="example.htm";
$http.post(url, data).then(function (response) {
vm.msg = response.data;
alert(vm.msg);
});
}
});
// Above is same as using GET, but here below is important
//Dont forget to add this config ortherwise http bad request 400 error
app.config(['$httpProvider', function ($httpProvider) {
$httpProvider.defaults.headers.post['Content-Type'] =
'application/x-www-form-urlencoded; charset=UTF-8';
}]);
//In spring controller same as of GET Method
#RequestMapping(value="example.htm", method = RequestMethod.POST)
#ModelAttribute("msg")
public String doingPost(#RequestParam(value="name") String name){
System.out.println(name);
return "successfully Posted";
}
I am trying to login to a website with the following request:
var request = require('request');
var options = {
method: 'POST',
url: 'https://server/EnterpriseController',
params: {a: 1},
form: "actionType=authenticateUser&reqObj=[null,username,password,null,1]",
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
},
withCredentials: true,
rejectUnauthorized: false
};
request(options,
function (error, response, body, data) {
if (request.method === 'POST') {
var body = '';
request.on('data', function (data) {
body += data;
});
request.on('end', function () {
var post = qs.parse(body);
});
}
console.log(body);
}
);
I am always getting an error. I think the form is wrong but I have the same login on an angularjs site without any error. I don't understand why the login works on angularjs site but not in nodejs.
)]}',
{"login_err": true, "resp": [null,null,null,1]
}
I missed the cookie:/ And the Formdata should be an Object.
I am trying to login and make a post to my project on my web host. I have removed the cors issue by adding the cors attribute to my web api 2 controller and my WebApiConfig.cs file. When I make a post with my login information included my console.log message shows the html of my login.cshtml file that is on my web host. And the "Job" information I am trying to post is not being posted as well.
Angular Controller
$scope.submitJob = function () {
var data = {
username: $scope.currentItem.username,
password: $scope.currentItem.password,
JobId: $scope.JobId,
JobNumber: $scope.currentItem.JobNumber,
JobName: $scope.currentItem.JobName,
}
var json = JSON.stringify(data);
// json is the json data you need to post
$http.post('http://www.example.com/api/apiJob', json, { headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' } })
.success(function (data, status) {
console.log(data);
})
.error(function (data, status) {
// error code
});
};
Web Api 2 Controller
[Authorize]
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class apiJobController : ApiController
{
// GET api/<controller>
[AllowAnonymous]
public IEnumerable<JobResult> Get()
{
using (var context = new ApplicationDbContext())
{
return context.Jobs
.ToResults();
}
}
// GET api/<controller>/5
public Job GetJob(int? id)
{
using (var context = new ApplicationDbContext())
{
Job model = new Job();
model = context.Jobs
.FirstOrDefault(j => j.JobId == id);
return model;
}
}
// POST api/<controller>
public async Task<IHttpActionResult> PostnewJob([FromBody]JobViewModel newJob)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
using (var context = new ApplicationDbContext())
{
var job = new Job();
Mapper.CreateMap<JobViewModel, Job>();
Mapper.Map(newJob, job);
context.Jobs.Add(job);
await context.SaveChangesAsync();
return CreatedAtRoute("JobApi", new { job.JobId }, job);
}
}
Screenshot