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
Related
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.
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
I am trying to refresh the access token for a user following this tutorial.
However, I am getting
{
"error":"unauthorized",
"error_description":"Full authentication is required to access this resource"
}
and I do not see what's missing.
The following is how I am constructing the oauth/refresh request in my Angular application:
refreshToken() {
this.logger.info('Attempting to refresh access token');
const headers = new HttpHeaders()
.set('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8')
// CLIENT_ID:CLIENT_SECRET
.set('Authorization', 'Basic Q0xJRU5UX0lEOkNMSUVOVF9TRUNSRVQ=');
const payload = {
refresh_token: AuthenticationService.getRefreshToken(),
grant_type: 'refresh_token'
};
return this.http.post(environment.apiUrl + '/oauth/refresh',
payload, {headers: headers})
.pipe(map(r => r));
}
What am I missing here?
Okay, I was almost right.
First, I did use the wrong endpoint /oauth/refresh - I don't know why I thought this existed. It has to be /oauth/token.
Also payload gets send via URL parameters:
const payload = `refresh_token=${AuthenticationService.getRefreshToken()}&grant_type=refresh_token`;
So in the end I got this working with:
refreshToken() {
this.logger.info('Attempting to refresh access token');
const headers = new HttpHeaders()
.set('Content-Type', 'application/x-www-form-urlencoded; charset=utf-8')
.set('Authorization', 'Basic Q0xJRU5UX0lEOkNMSUVOVF9TRUNSRVQ=');
const payload = `refresh_token=${AuthenticationService.getRefreshToken()}&grant_type=refresh_token`;
return this.http.post(environment.apiUrl + '/oauth/token',
payload, {headers: headers})
.pipe(map(r => r));
}
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));
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.