Django doesn't check for a csrf token with Ajax post - ajax

According to the Django docs, Django should have csrf token validation enabled by default, using a middleware. When I look in my settings file I indeed see the middleware being included.
However, when I do a post request without a csrf token using Ajax, Django will just allow it. Should it not return an error saying the csrf token is invalid? I am seeing a lot of questions from people who can't get their csrf token validated, but I can't get it INvalidated.
This is my Ajax post function (I collect the data from my inputs with js, and pass it to this function):
function ajaxPost(url, data, success) {
fetch(url, {
method: 'POST', // or 'PUT'
body: JSON.stringify(data),
headers: new Headers({
'Content-Type': 'application/json'
})
}).then(res => res.json())
.then(response => {
if (response.status !== success) {
//errors
}
updateView(response);
})
.catch(error => console.error('Error:', error))
}
And this is my view function:
#api_view(['POST'])
# API endpoint for posting bulk properties
def bulk(request):
new_properties = []
if request.method == 'POST':
for obj in request.data:
discipline = Discipline.objects.get(pk=obj['discipline.id'])
root_function = Function.objects.get(pk=obj['root_function'])
new_property = Property(name=obj['name'], value=obj['value'], unit=obj['unit'],
discipline_id=discipline)
new_property.save()
new_property.function.add(root_function)
new_properties.append(new_property)
new_properties = json.loads(serializers.serialize('json', new_properties))
return JsonResponse({'status': 201, 'new_properties': new_properties})

Assuming api_view is the one from django-rest-framework, it disables CSRF protection for that view.
This is because API endpoints are frequently used for external requests that won't have a CSRF token; there's no point checking for it in these cases.

Related

How to override cy.request() and set up bearer authorization header globally?

I need to set the authorization bearer header for cy.request() globally to avoid setting it up multiple times.
Here I found some potential way to do it.
So in my support/commands.ts I have:
Cypress.Commands.overwrite('request', (originalFn, ...options) => {
const optionsObject = options[0];
if (optionsObject === Object(optionsObject)) {
optionsObject.headers = {
authorization: `Bearer ${Cypress.env('authorizationToken')}`,
...optionsObject.headers,
};
return originalFn(optionsObject);
}
return originalFn(...options);
});
And in the test I have:
cy.request({
method: 'POST',
url: '/someEndpoint',
body: someBody
}).then(response => {
expect(response.status).eq(200);
return response.body;
});
And unfortunately, I get 401: Unauthorized error and it looks like the authorization bearer token was not added to headers:
What do I do wrong here? I use Cypress v 10.10.0

Axios JWT doesn't send

I have a project divided in two layers. The back-end is developed in spring boot, secured by Sprint security and JWT, and the front-end is developed in Vue.js, using Axios library for communication between layers.
I receive the "Bearer token" authentication properly, and all the authentication process is done correctly. The issue appears when I try to send a request with a token header to access content but the token doesn't send, and the Spring boot returns null without the content.
Here is the code
getOffers: function () {
if (localStorage.getItem("userSession")) {
this.aux = JSON.parse(localStorage.getItem("userSession"));
this.token = this.aux.token;
this.tokenHeader = "Bearer "+this.token;
alert(this.tokenHeader)
};
console.log(`Bearer ${this.token}`)
axios.
get('http://localhost:8080/api/v1/offer', {'Authorization' : `Bearer ${this.token}`})
.then(response => {
console.log(response);
this.offers = response.data
}).catch(e => console.log(e))
}
P.S: When I make a request in Postman, it works fine and returns the desired object. Here is a postman example:
postman
Correct way to pass header is :
axios.get(uri, { headers: { "header1": "value1", "header2": "value2" } })
In your case try this:
axios.get('http://localhost:8080/api/v1/offer', { headers:{Authorization : `Bearer ${this.token}`} })
Also, check in console if this gives correct Bearer token:
console.log(`Bearer ${this.token}`)
Register the Bearer Token as a common header with Axios so that all outgoing HTTP requests automatically have it attached.
window.axios = require('axios')
let bearer = window.localStorage['auth_token']
if (bearer) {`enter code here`
window.axios.defaults.headers.common['Authorization'] = 'Bearer ' + bearer
}
And no need to send bearer token on every request.

Adding multiple headers to graphql client (apollo-boost)

const client = new ApolloClient({
uri,
onError: (e: any) => {
console.log('error: ', e); // Failed to fetch
console.log(e.operation.getContext()); // it does show it has x-abc-id
},
request: operation => {
const headers: { [x: string]: string } = {};
const accessToken = AuthService.getUser()?.accessToken;
const activeClientId = UserService.getActiveClientId();
headers['x-abc-id'] = activeClientId;
if (accessToken) headers['Authorization'] = `Bearer ${accessToken}`;
operation.setContext({ headers });
}
});
The problem here is when i just add Authorization header it makes the POST call and shows the expected error.
But when i add x-abc-id header which is also expected by backend it only makes OPTIONS call (no post call)
P.S. On postman adding both headers works completely fine.
Found what the issue was, thought to share if it help.
Postman does not perform OPTIONS call before sending request to backend.
In OPTIONS call, 👇represents what client call contains: [authorization, content-type, x-abc-id]
BUT what does server expects: 👇
Just authorization, content-type
So it's a calls headers mismatch (nothing related to Apollo).
x-abc-id header explicitly has to be allowed in CORS configuration on backend.
Thanks to Pooria Atarzadeh

Apollo Client: Send different headers relative to authentication/authorization

I will often have an expired authorization token in my app.
I do not, however, want this error to block requests that do not require authorization. What is the work around?
I'd like to customize my headers for requests to simply view a page (which doesn't require token, so send with an empty header) and for requests to edit data (add token and allow error to block request).
An invalid token, with headers set like below for every request, is now blocking the simple fetching of open data:
const client = new ApolloClient({
uri: "http://localhost:8000/graphql",
request: operation => {
const token = sessionStorage.getItem('jwtToken');
operation.setContext({
headers: {
'x-token': token || '',
},
});
},
});

Request header field X-CSRF-TOKEN is not allowed by Access-Control-Allow-Headers

I'm making a get request to embed.rock using vue and axios.
axios({
method: 'get',
url: 'https://api.embed.rocks/api?url=' + this.url,
headers: {
'x-api-key': 'my-key'
}
})
When I use a CDN to get vue and axios with an inline script my code works fine and I get a response back.
When I reference the installed vue and axios scrpts with an external script the code no longer runs and I get the following error:
Failed to load https://api.embed.rocks/api?url=https://www.youtube.com/watch?v=DJ6PD_jBtU0&t=4s: Request header field X-CSRF-TOKEN is not allowed by Access-Control-Allow-Headers in preflight response.
When I click on the error in the console it just brings me to:
<!DOCTYPE html>
Laravel is setting a global configuration to include automatically the X-CSRF-TOKEN in the headers of the request in your bootstrap.js file.
let token = document.head.querySelector('meta[name="csrf-token"]');
if (token) {
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}
Therefore, if you want to remove the token, you can achieve it like this:
var instance = axios.create();
delete instance.defaults.headers.common['X-CSRF-TOKEN'];
instance({
method: 'get',
url: 'https://api.embed.rocks/api?url=' + this.url,
headers: {
'x-api-key': 'my-key'
}
});
the problem is that by default the CSRF Token is register as a common header with Axios so
to solve this issue :
1- replace these lines in bootstrap.js
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
let token = document.head.querySelector('meta[name="csrf-token"]');
if (token) {
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-
token');
}
by this line
window.axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
2- install qs module by npm ..... using thie link : https://www.npmjs.com/package/qs
3- define const of qs like below :
const qs = require('qs');
4- use axios by defult like this :
axios.post('your link here ',qs.stringify({
'a1': 'b1',
'a2 ':'b2'
}))
.then(response => {alert('ok');})
.catch(error => alert(error));

Resources