I'm trying to make an API call to Zendesk's API and I keep getting a 401 auth code even though the same thing works when I do a cURL in terminal. How can I make this work in Angular?
function dataservice($http) {
var service = {
getMacros: getMacros
};
return service;
/////////////////////
function getMacros() {
var client = {
username: window.btoa('myEmail'),
token: window.btoa('/token:myToken'),
remoteUri: 'https://myCompany.zendesk.com/api/v2/macros.json'
};
console.log('Loading...');
return $http({
method: 'GET',
url: client.remoteUri,
headers: {
'Authorization': client.username + client.token
}
})
.then(getMacrosComplete)
.catch(function (message) {
exception.catcher('Failed to getMacros')(message);
});
function getMacrosComplete(response) {
console.log('Done');
var data = response.data;
return data;
};
};
The code above always returns a 401 while this works:
curl myEmail/token:myToken https://myCompany.zendesk.com/api/v2/macros.json
Seems to work well. Probably something obvious.
The thing is you need to set Authorization headers properly, they should be Base64 encoded and you have to state "Basic" authentication (this is the main part most people miss).
So this should work:
function dataservice($http) {
var service = {
getMacros: getMacros
};
return service;
/////////////////////
function getMacros() {
var client = {
username: 'myEmail',
token: 'myToken',
remoteUri: 'https://myCompany.zendesk.com/api/v2/macros.json'
};
console.log('Loading...');
return $http({
method: 'GET',
url: client.remoteUri,
headers: {
'Authorization': 'Basic ' + window.btoa(client.username + '/token:' + client.token)
}
})
.then(getMacrosComplete)
.catch(function (message) {
exception.catcher('Failed to getMacros')(message);
});
function getMacrosComplete(response) {
console.log('Done');
var data = response.data;
return data;
};
};
Of course you have to have token authentication enabled in your Zendesk account, otherwise you can authenticate via user + password by setting up a password instead and doing:
'Authorization': 'Basic ' + window.btoa(client.username + ':' + client.password)
Related
I am new to using Axios and struggling to display anything from a response function. I'm mainly interested to see see at least the response status. The only output I can see is when there is a 4xx code returned, but nothing when the call is successful.
Below is my code, any help would be appreciated:
setServiceGroupPromise(){
//Read data from ./data/sourcingRules.txt
let filePath = './data/sourcingRules.txt';
var fileData = fs.readFileSync(filePath, 'utf8');
console.log(fileData);
let postURL = `${siteConfig}`;
const config = {
method: 'post',
url: postURL,
params: {
'apiKey': process.env.SHIPPING_SERVICE_API_KEY
},
headers: {
'content-type': 'application/xml',
},
data: fileData
};
console.log(`Post request going to: ${postURL}`);
axios(config)
.then(function (response) {
console.log(response.data);
console.log(response.status);
})
.catch(function (error) {
console.log('The following error occurred : ' + error.message);
});
}
If you are not seeing anything from the console.log(response.data), try logging something like console.log({response}), or console.log('show me something', response.data)
I'm trying to test rest endpoint 'http://xxxxxxx/j_spring_security_check' to get authentication with frisby npm package.
I am able to work in postman, by selecting request body as 'x-www-form-urlencoded' tab and given my app credentials like key-value, its working fine as expected. But in frisby npm I am unable to set request body as 'x-www-form-urlencoded'.
I'm unable to login with this script.
Please help me in this or any other alternative suggestions would be great.
Here is my code:
var frisby7=require('frisby');
const qs = require('qs');
describe('API reference', function() {
var baseURL='http://xxxxxx/j_spring_security_check';
it('Simple Test with post url-encode form body request ', function() {
console.log("**********")
frisby7.globalSetup({
request: {
headers:{'Content-Type':'application/x-www-form-urlencoded'}
// headers: { 'X-Ms-Source':'api','X-Ms-Format':'xml','Authorization':'Basic c2hyZXlhIGdveWFsOm0jbWY4cDlMZ2ZAMU1xUTg='}
}
});
return frisby7.post(baseURL,
{
form: { j_username:'xxxx#xxxxx.com', j_password:'xxxx' }
}).then(function (res) { // res = FrisbyResponse object
console.log('status '+res.status);
console.log('body '+res.body);
//return res;
});
});
You are currently sending the object in the body as if you were using 'multipart/form-data'.
To send the request as 'application/x-www-form-urlencoded' you need to URI encode each property and then post them as a querystring
Try it like this
var objToSend = { j_username:'xxxx#xxxxx.com', j_password:'xxxx' };
var uriObj = Object.keys(objToSend).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(objToSend[key])).join('&');
var url = baseURL + '?' + uriObj
frisby7.post(url);
Try something like this:
var frisby = require("frisby");
const Joi = frisby.Joi;
var req1 = {
method: "get",
url: "pass url here",
headers : {
"Accept": "application/json",
"content-type" : "application/json",
'Authorization': 'Basic ' + Buffer.from(username + ":" + password).toString('base64') // pass username and password for //validation
},
body: {}
};
describe('spec file name', function () {
it("spec file name" + dateTime, function(){
return frisby
.setup({ request: { headers : req1.headers } })
.get(req1.url)
.expect("status", 200)
.expect("header", "Content-Type", "application/json; charset=utf-8")
.expect("jsonTypes", {
"message": Joi.string()
})
.then(function(res) {
var body = res.body;
body = JSON.parse(body);
expect(body.message).toBeDefined();
})
.then(function(res) {
var body = res.body;
body = JSON.parse(body);
var req2 = {
method: "put",
url: "pass url here",
headers : {
"Accept": "application/json",
"content-type" : "application/json",
"Authorization": "JWT " + Token // anything that you using to authenticate
},
body: {}
};
return frisby
.setup({ request: { headers : req2.headers } })
.put(req2.url)
.expect("status", 200)
.expect("header", "content-type", "application/json; charset=utf-8")
.expect("jsonTypes", {
"message": Joi.string()
})
.then(function(res) {
var body = res.body;
body = JSON.parse(body);
expect(body.message).toBeDefined();
})
});
});
});
I'm trying to pass data back to my controller from my service with no success. I am able to invoke my service from my controller, and I know the service itself works because I can console log the response from within the service (but not back in the controller).
This is my service:
(function () {
angular
.module('app')
.service('testService', testService);
testService.$inject = ['$http'];
function testService($http, url) {
var baseUrl = "http://getjsondata.com/" + url;
this.getData = function (url) {
$http({
method: 'GET',
url: baseUrl + url,
headers: {'Content-Type': 'application/json'}
})
.then(function (response) {
console.log(response); // THIS WORKS
return response;
})
.catch(function (error) {
return error;
});
};
}
}());
This is inside my controller:
vm.getTestData = function (url) {
vm.response = testService.getData(url);
console.log(vm.response);
};
I've tried passing the data back as a callback in testService.getData but with no success. I have also tried using a factory instead of a service but I'm not able to access the data back in my controller. I have also tried defining my function in the service differently (getData: function()...) and so on.
I'm guessing my return statement in the service is behaving differently than the way I am expecting. I would appreciate any help!
getData never returns. add return in front of $http and use .then in your controller.
this.getData = function (url) {
return $http({
method: 'GET',
url: baseUrl + url,
headers: {'Content-Type': 'application/json'}
})
};
In ctrl
vm.getTestData = function (url) {
testService.getData(url).then(function (response) {
vm.response = response;
return response;
})
.catch(function (error) {
return error;
});
};
I'm building a VueJS application and I'm using JSON web tokens as my auth system. When I log the user, I store the token with localStorage and works fine. I check the headers and it's in the 'Authorization' param.
I pass with axios.defaults.headers.common['Authorization'] = localStorage.getItem('token')
I see the headers and it's okay. But when I execute a get request to an protected route in my API, return 'unauthorized'. But when I pass the header with token manually in the request, works fine.
Somebody know how to pass the header automatically when executing some request?
try this..
//in get request
const auth = {
headers: {Authorization:'JWT ' + localStorage.getItem('token')}
}
axios.get('http://yourapi.com',auth).then(result => {
console.log(result.data)
})
//in post request
const auth = {
headers: {Authorization:'JWT ' + localStorage.getItem('token')}
}
//note:auth will be 3rd parameter in post request
axios.post('http://yourapi.com',{somekey:'some value'},auth).then(result => {
console.log(result.data)
})
You can use axios.create to create a new axios instance with a config object, including the headers. The configuration will be used for each subsequent calls you make using that instance.
Something like this worked for me:
var App = Vue.component('app', {
mounted () {
this.response = null
this.axiosInstance = axios.create({
baseURL: 'http://localhost:5000/',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
}
})
},
data () {
return {
response: this.response,
}
},
methods: {
login () {
this.axiosInstance.post('login', {username: 'test', password: 'test'})
.then(resp => {
this.accessToken = resp.data.access_token
this.axiosInstance.defaults.headers['Authorization'] = 'Bearer ' + this.accessToken
})
.catch(err => this.response = err.response.status + ' ' + err.response.statusText)
},
protected () {
this.axiosInstance.get('protected')
.then(resp => this.response = resp.data)
.catch(err => this.response = err.response.status + ' ' + err.response.statusText)
}
},
template: '<div><button #click="login">Connect</button><button #click="protected">Protected</button></div>'
})
interceptor which includes your auth token in every request as an Authorization header:
axios.interceptors.request.use(
function(config) {
const token = localStorage.getItem('token')
if (token) config.headers.Authorization = `Bearer ${token}`
return config
},
function(error) {
return Promise.reject(error)
}
)
you could place it in the main file, for example main.js
Check whether server get token from header of "Authorization"
axios.defaults.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('token')
if No. 2 works, then you may want to execute apis even if web is refreshed, then follow:
axios.interceptors.request.use(function (config) {
const token = 'Bearer ' + localStorage.getItem('token');
config.headers.Authorization = `Bearer ${token}`;
return config;
});
For me issue was with capital Headers vs headers.
Should be lower case. My IDE got me the wrong autocomplete (i.e. with capital H)
This works:
await axios.get(url, {
headers: { 'x-custom-header': 'super header value' }
});
This doesn't!
await axios.get(url, {
Headers: { 'x-custom-header': 'super header value' }
});
I have an AngularJS (v1.5) client that is used to schedule an Operating Room at a hospital. The app has a single controller and two functions within that controller. These two functions are both $http POST requests.
The first method called (requestAccessToken) passes a username, password, and grant_type to receive back an OAuth 2 access token which is then assigned to a variable on the scope. This works fine.
The second method (scheduleORSuite) makes an API call passing the access token obtained from the first method (requestAccessToken) . The problem is that when the method () executes the access token is null. I know I am receiving back a valid access token because when I call the method requestAccessToken directly I get back a valid access token. When I step through the debugger in Chrome it looks like the method (scheduleORSuite), that uses the access token, does not even wait for the method that obtains the access token to return.
<script type="text/javascript">
var scheduleORSuiteApp = angular.module('scheduleORSuiteApp', []);
scheduleORSuiteApp.controller('ScheduleORSuiteController', function ($scope, $http) {
var viewModel = this;
viewModel.accessToken = null;
viewModel.userName = 'theUserName';
viewModel.password = 'thePassword';
// This method requests the access token
viewModel.requestAccessToken = function () {
$http({
method : 'POST',
url: 'https://api.myserver.net/oauth/token',
data: 'username=' + viewModel.userName + '&password=' + viewModel.password + '&grant_type=password',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(_requestAccessTokenSuccess, _requestAccessTokenError);
};
// This method contacts the API endpoint the schedule an OR suite
viewModel.scheduleORSuite = function() {
viewModel.requestAccessToken();
if (viewModel.accessToken) {
return; // viewModel.accessToken is null. Exit the method
}
$http({
method : 'POST',
url: 'https://api.myserver.net/api/scheduleOrSuite',
data : angular.toJson(viewModel.form),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + viewModel.accessToken
}
}).then(_scheduleORSuiteSuccess, _scheduleORSuiteError);
};
// Called when request for access token is successful
function _requestAccessTokenSuccess(response) {
viewModel.tokenDisplay = response.data;
};
// Called when request for access token results in error
function _requestAccessTokenError(response) {
viewModel.tokenDisplay = 'An error occured: ' + response.status;
};
// Called when scheduling of operating suite is successful
function _scheduleORSuiteSuccess(response) {
viewModel.accessToken = response.data.access_token;
};
// Called when scheduling of operating suite results in error
function _scheduleORSuiteError(response) {
viewModel.tokenDisplay = 'An error occured: ' + response.data;
};
});
</script>
Here is the HTML form that makes use of the controller.
<form ng-submit="viewModel.scheduleORSuite()" novalidate>
...
...
</form>
Is there a way to make the second method (scheduleORSuite) wait until the first method (requestAccessToken) completes? The access token is required in order to call the API to schedule an OR suite.
$http is an async method, so you need to use callbacks
var scheduleORSuiteApp = angular.module('scheduleORSuiteApp', []);
scheduleORSuiteApp.controller('ScheduleORSuiteController', function($scope, $http) {
var viewModel = this;
viewModel.accessToken = null;
viewModel.userName = 'theUserName';
viewModel.password = 'thePassword';
viewModel.requestAccessToken = function() {
viewModel._requestAccessToken().then(_requestAccessTokenSuccess, _requestAccessTokenError);
};
viewModel.scheduleORSuite = function() {
if (viewModel.accessToken) {
viewModel._scheduleORSuite.then(_scheduleORSuiteSuccess, _scheduleORSuiteError);
} else {
viewModel._requestAccessToken().then(function(response) {
viewModel.tokenDisplay = response.data;
viewModel._scheduleORSuite.then(_scheduleORSuiteSuccess, _scheduleORSuiteError);
}, _requestAccessTokenError);
}
};
// This method contacts the API endpoint the schedule an OR suite
viewModel._scheduleORSuite = function() {
return $http({
method: 'POST',
url: 'https://api.myserver.net/api/scheduleOrSuite',
data: angular.toJson(viewModel.form),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + viewModel.accessToken
}
});
};
// This method requests the access token
viewModel._requestAccessToken = function() {
return $http({
method: 'POST',
url: 'https://api.myserver.net/oauth/token',
data: 'username=' + viewModel.userName + '&password=' + viewModel.password + '&grant_type=password',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
};
// Called when request for access token is successful
function _requestAccessTokenSuccess(response) {
viewModel.tokenDisplay = response.data;
};
// Called when request for access token results in error
function _requestAccessTokenError(response) {
viewModel.tokenDisplay = 'An error occured: ' + response.status;
};
// Called when scheduling of operating suite is successful
function _scheduleORSuiteSuccess(response) {
viewModel.accessToken = response.data.access_token;
};
// Called when scheduling of operating suite results in error
function _scheduleORSuiteError(response) {
viewModel.tokenDisplay = 'An error occured: ' + response.data;
};
});
It's because your requestAccessToken() method contains a promise, and JavaScript won't wait for this to complete before carrying on with the rest of the code.
The best thing to do would be to return the promise from requestAccessToken() for use in scheduleORSuite()
viewModel.requestAccessToken = function () {
return $http({
method : 'POST',
url: 'https://api.myserver.net/oauth/token',
data: 'username=' + viewModel.userName + '&password=' + viewModel.password + '&grant_type=password',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
};
viewModel.scheduleORSuite = function() {
viewModel.requestAccessToken().then(function(response) {
viewModel._requestAccessTokenSuccess(response);
if (viewModel.accessToken) {
return; // viewModel.accessToken is null. Exit the method
}
$http({
method : 'POST',
url: 'https://api.myserver.net/api/scheduleOrSuite',
data : angular.toJson(viewModel.form),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + viewModel.accessToken
}
}).then(_scheduleORSuiteSuccess, _scheduleORSuiteError);
}, _requestAccessTokenError);
};
I've also noticed though that the variable you're checking for your access token, viewModel.accesstoken, is being set until the _scheduleORSuiteSuccess() function? I'm presuming this is an error and it should be set in _requestAccessTokenSuccess() instead?
What you want todo is make sure the request returns with the access token first, then make the second request. Todo that, use a promise. the $q library works well for this. See viewModel.requestAccessTokenfor the changes I made.
<script type="text/javascript">
var scheduleORSuiteApp = angular.module('scheduleORSuiteApp', []);
scheduleORSuiteApp.controller('ScheduleORSuiteController', function($scope, $http, $q) {
var viewModel = this;
viewModel.accessToken = null;
viewModel.userName = 'theUserName';
viewModel.password = 'thePassword';
// This method requests the access token
viewModel.requestAccessToken = function() {
var defer = $q.defer();
$http({
method: 'POST',
url: 'https://api.myserver.net/oauth/token',
data: 'username=' + viewModel.userName + '&password=' + viewModel.password + '&grant_type=password',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then(function(response) {
viewModel.tokenDisplay = response.data;
defer.resolve(); //fullfills the promise
}, function(err) {
viewModel.tokenDisplay = 'An error occured: ' + response.status;
defer.reject(); //rejects the promise
});
return $q; //returns a promise
};
// This method contacts the API endpoint the schedule an OR suite
viewModel.scheduleORSuite = function() {
viewModel.requestAccessToken().then(function() {
//On fullfillment of the promise from requestAccessToken...
if (viewModel.accessToken) {
return; // viewModel.accessToken is null. Exit the method
}
$http({
method: 'POST',
url: 'https://api.myserver.net/api/scheduleOrSuite',
data: angular.toJson(viewModel.form),
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + viewModel.accessToken
}
}).then(_scheduleORSuiteSuccess, _scheduleORSuiteError);
}, function() {
//Error occured in requestAccessToken();
})
};
// Called when scheduling of operating suite is successful
function _scheduleORSuiteSuccess(response) {
viewModel.accessToken = response.data.access_token;
};
// Called when scheduling of operating suite results in error
function _scheduleORSuiteError(response) {
viewModel.tokenDisplay = 'An error occured: ' + response.data;
};
});
</script>