I'm curious about the difference between axios interceptor and default header.
I want to add authorization in header.
I know I can manage authorization header with axios interceptor and default header.
(Attach Authorization header for all axios requests)
I'm not sure when to use the interceptor and default header respectively.
Is it simply that axios provides two methods?
Default headers are assigned statically. The values you place into them must be known at the time your code executes.
axiosOrInstance.defaults.headers.common["x-value"] = "some value you must know";
Interceptors are functions that execute per request / response. This means they can access values that might not have been available earlier or even values specific to the current request.
axiosOrInstance.interceptors.request.use(config => ({
...config,
headers: {
...config.headers,
"x-value": "whatever"
}
}), null, {
synchronous: true,
runWhen: config => config.url === "only/run/for/this/url"
})
They can also be asynchronous and make other async calls before resolving
axiosOrInstance.interceptors.request.use(async config => {
const someValue = await getSomeAsyncValue()
return {
...config,
headers: {
...config.headers,
"x-value": someValue
}
};
});
Related
Here's my axios config:
const axiosApi = axios.create({
baseURL: process.env.NEXT_PUBLIC_API_URL
})
axiosApi.interceptors.response.use(
response =>
response
,
error => {
if (error.response.status === 404) {
throw new Error(`404\nService does not exist\n${error.request.path}`)
}
}
)
export async function get(url) {
console.log(url)
return await
axiosApi.get(url, {
crossDomain: true
}).then(response => {
return response?.data
})
}
The problem is that when I try to get /path?key=value, I get the /pathkey=value does not exist error.
While console.log(url) shows me the true URL with the question mark and query string, the response interceptor strips the question mark out and that causes 404.
Any idea why this happens?
This is an Axios bug in v1.0.0
Issue reported here: https://github.com/axios/axios/issues/4999
Fixed in v1.1.0
You should pass the query params like below:
axios.get('/path', { params: { key: value} });
Try limit the version in dependency.
"dependencies": {
"axios": "~0.27.2",
},
may help.
Personally I don't even get why Axios developer decide to do this.
Basically according to HTTP Protocol both path and query parameters is considered URI.
Axios.get() should accept everything that is considered URI to conform with HTTP specifications.
And project which let user input its URL for fetch the data will just broken out of the box.
I seem to get empty body content of a Go http.Request if the method is DELETE. But if I change the method to POST, then the body content gives me the content I expect.
The relevant code from my golang looks like this:
import(
"github.com/gorilla/handlers"
"github.com/gorilla/mux"
)
func Delete(w http.ResponseWriter, r *http.Request) {
r.ParseForm()
qs := r.Form
log.Println(qs)
}
func main() {
router := mux.NewRouter()
router.HandleFunc("/profile", Delete).Methods("POST")
router.HandleFunc("/profile", Delete).Methods("DELETE")
}
Now when I run this JavaScript code form my browser:
fetch(sendurl,{
method:"POST",
headers:{
'Content-Type': 'application/x-www-form-urlencoded'
},
body:"data="+project.encodeFormURIComponent(JSON.stringify({"ids":[1032,1033]}))
})
.then(response=>{
if(response.ok)
return response.json();
})
.then(result=>{
console.log(result);
})
I see a nice array of numbers in my qs[ids] in my Golang code. But if I change my method:"POST" to method:"DELETE" in the JavaScript, then qs is empty.
What am I doing wrong?
UPDATE
This JavaScript with the DELETE method can populate the Go qs variable the way one would normally expect:
fetch(sendurl+"?data="+project.encodeFormURIComponent(JSON.stringify({"ids":[1032,1033]})),{
method:"DELETE",
headers:{
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(response=>{
if(response.ok)
return response.json();
})
.then(result=>{
console.log(result);
})
So it seems Go will ignore JavaScript body argument when DELETE method is used, but it will respect the query string content in the API endpoint url? Why is it like that?
https://www.rfc-editor.org/rfc/rfc7231#section-4.3.5
A payload within a DELETE request message has no defined semantics; sending a payload body on a DELETE request might cause some existing implementations to reject the request.
The query string is part of the target-uri of the request; in other words, the query string is part of the identifier, not an incidental modifier of it. But the message-body of the request is not part of the identifier.
So your local framework, or any of the other general purpose components forwarding your request, are not required to provide support for the message-body.
Think "undefined behavior" in C.
As the title explains, I pretend to retrieve in console.log a custom header named "count" inside a map from an http.get request. The browser shows that the count value exists. How can I retrieve that value?
This is what I have tried, the problem is that this returns null.
import { Http } from "#angular/http";
constructor (public http: Http) {}
myFunction() {
return this.http.get(url)
.map((response: Response) => {
console.log(response.headers.get('count')); // returns null
});
}
response.headers only gets this
Nevermind, I fixed it adding count to the Access-Control-Expose-Headers on the website that provides the service.
# Sets the Access-Control-Expose-Headers header.
exposedHeaders: ['count']
** I'm doing as following, I already created a custom rule.**
componentDidMount() {
console.log(token)
let response = fetch('https://DOmain.eu.auth0.com/userinfo', {
method: 'GET',
headers: {
Authorization: 'Bearer ' + token,
},
}).then((response) => response.json())
.then(responseJson => data = responseJson).then(console.log(data.nickname));
const metadata = data["https://Domain.eu.auth0.com/user_metadata"]
console.log(metadata);
}
My rule:
The Rule you have setup looks good, but will not work as the namespace is an Auth0 domain
Any non-Auth0 HTTP or HTTPS URL can be used as a namespace identifier,
and any number of namespaces can be used
Give it a shot with an alternate namespace, example 'https://myapp.example.com/', and you should be good to go!
As a side note, I would try to avoid adding all the usermetadata to the idtoken which can cause the generated token to be too large. You should also ensure that the data being included is not sensitive and can be disclosed. Some items that may be helpful, a quick read here: https://auth0.com/docs/metadata and here: https://auth0.com/docs/scopes/current/custom-claims to help you along the way!
I'm in the process of building a new AngularJS frontend for a Drupal 7 website. This is using the Services module with session-based authentication, across two domains using CORS. I am able to authenticate with Drupal, retrieve the user object and session data, and then get the CSRF token from the services module. What I'm having trouble with is setting all this up in the header so that subsequent requests are authenticated. I understand the overall concept but am new to both AngularJS and preventing CSRF attacks.
From what I have gathered reading about this set-up with AngularJS and RubyOnRails, there can be inconsistencies between platforms concerning what the token is named and how it is processed. There also seems to be a number of suggestions on how to set this token in the header. However, I'm having trouble in finding a solid example of how to get these platforms speaking the same language.
The only thing I'm doing with my $httpProvider in app.js is:
delete $httpProvider.defaults.headers.common['X-Requested-With'];
The login controller, in controller.js:
.controller('LoginCtrl', ['$scope', '$http', '$cookies', 'SessionService', function($scope, $http, $cookies, SessionService) {
$scope.login = function(user) {
//set login url and variables
var url = 'http://mywebsite.com/service/default/user/login.json';
var postDataString = 'name=' + encodeURIComponent(user.username) + '&pass=' + encodeURIComponent(user.password);
$http({
method: 'POST',
url: url,
data : postDataString,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}
}).success(function (data, status, headers, config) {
var sessId = data.sessid;
var sessName = data.session_name;
$cookies[sessName] = sessId;
var xsrfUrl = 'http://mywebsite.com/services/session/token';
$http({
method: 'GET',
url: xsrfUrl
}).success(function (data, status, headers, config) {
$cookies["XSRF-TOKEN"] = data;
SessionService.setUserAuthenticated(true);
}).error(function (data, status, headers, config) {
console.log('error loading xsrf/csrf');
});
}).error(function (data, status, headers, config) {
if(data) {
console.log(data);
var msgText = data.join("\n");
alert(msgText);
} else {
alert('Unable to login');
}
});
};
The solution has to do with how the cookies need to be set and then passed through subsequent requests. Attempts to set them manually did not go well but the solution was simpler than I expected. Each $http call needs to set the options:
withCredentials: true
Another change I made was to use the term CSRF instead of XSRF, to be consistent with Drupal. I didn't use any built-in AngularJS CSRF functionality.
addItem: function(data)
{
return $http.post('api/programs/'+$stateParams.id+'/workouts', {item:data},{
headers:
{
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'X-CSRF-Token': $('meta[name="xxtkn"]').attr('content')
}
});
}
since it has been a year of this topic! not sure still encountering the same problem but for the ones who comes to search for answers here is how i handle it!
Pay attention the headers{} part i define a new header and call it X-CSRF-Token and grab value from the DOM of (serverside) generated html or php. It is not a good practise to also request the csrf token from the server.Cuz attacker could somehow request that as well. Since you save it as a cookie. Attacker can steal the cookie! No need to save it in a cookie! send the token with header and read it in the serverside to match it!
and for multitab of a same page issue. I use the same token thruout the whole session.
Only regenerate on login, logout and change of major site or user settings.
There is a great library callse ng-drupal-7-services. If you use this in you project it solves authentication / reauthentication and file / node creation aut of the box and you can fokuse on the importent stuff in your project.
So Authentication is there solved like this:
function login(loginData) {
//UserResource ahndles all requeste of the services 3.x user resource.
return UserResource
.login(loginData)
.success(function (responseData, status, headers, config) {
setAuthenticationHeaders(responseData.token);
setLastConnectTime(Date.now());
setConnectionState((responseData.user.uid === 0)?false:true)
setCookies(responseData.sessid, responseData.session_name);
setCurrentUser(responseData.user);
AuthenticationChannel.pubLoginConfirmed(responseData);
})
.error(function (responseError, status, headers, config) {
AuthenticationChannel.pubLoginFailed(responseError);
});
};
(function() {
'use strict';
AuthenticationHttpInterceptor.$inject = [ '$injector'];
function AuthenticationHttpInterceptor($injector) {
var intercepter = {
request : doRequestCongiguration,
};
return intercepter;
function doRequestCongiguration (config) {
var tokenHeaders = null;
// Need to manually retrieve dependencies with $injector.invoke
// because Authentication depends on $http, which doesn't exist during the
// configuration phase (when we are setting up interceptors).
// Using $injector.invoke ensures that we are provided with the
// dependencies after they have been created.
$injector.invoke(['AuthenticationService', function (AuthenticationService) {
tokenHeaders = AuthenticationService.getAuthenticationHeaders();
}]);
//add headers_______________________
//add Authorisation and X-CSRF-TOKEN if given
if (tokenHeaders) {
angular.extend(config.headers, tokenHeaders);
}
//add flags_________________________________________________
//add withCredentials to every request
//needed because we send cookies in our request headers
config.withCredentials = true;
return config;
};
There is also some kind of kitchen sink for this project here: Drupal-API-Explorer
Yes, each platform has their own convention in naming their tokens.
Here is a small lib put together hoping to make it easy to use with different platforms. This will allow you to use set names and could be used across all requests. It also works for cross-domain requests.
https://github.com/pasupulaphani/angular-csrf-cross-domain