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' }
});
Related
I want to use Trustpilot API to send email review invitation. Before making that call, I need to get an access token. I'm following Trustpilot's documentation in the function below. I keep getting this error of Unknown grant_type. According to the documentation, it is supposed to be set to "password" to get the token and it is not working. I tried this solution but it is not working for me. I can't seem to know what's causing the error especially that it is very general.
trustPilot.getAuthToken = async () => {
let apiKey = process.env.TRUSTPILOT_API
let secrect = process.env.TRUSTPILOT_SECRET
let baseEncoded = Buffer.from(`${apiKey}:${secrect}`).toString('base64')
console.log(baseEncoded, 'base')
let authToken = null
try {
authToken = await axios({
method: 'POST',
url: `https://api.trustpilot.com/v1/oauth/oauth-business-users-for-applications/accesstoken`,
headers: { Authorization: 'Basic ' + baseEncoded, 'Content-Type': 'application/x-www-form-urlencoded' },
content: `grant_type=password&username=${process.env.TRUSTPILOT_EMAIL}&password=${process.env.TRUSTPILOT_PASSWORD}`,
})
console.log(authToken, 'auth')
} catch (error) {
console.log(error.response, 'err')
throw { code: '404' }
}
return authToken
}
Please take a look at axios documentation. You are passing content: instead of data:. Axios call should be like this:
authToken = await axios({
method: 'POST',
url: `https://api.trustpilot.com/v1/oauth/oauth-business-users-for-applications/accesstoken`,
headers: { Authorization: 'Basic ' + baseEncoded, 'Content-Type': 'application/x-www-form-urlencoded' },
data: `grant_type=password&username=${process.env.TRUSTPILOT_EMAIL}&password=${process.env.TRUSTPILOT_PASSWORD}`,
})
I'm reaching out to an endpoint with fetch to get a bearer token that will then be used in another fetch request for authentication. I've used Postman first and verified that the endpoints I'm accessing are working, however with my fetch requests below I get a 401.
I have checked in the console that the Authorization is updated after the first fetch and it's passed to the second however I continue to get a 401.
The first call reaches to ./auth and a bearer token is returned. That token is passed off to the next fetch request and but I am getting a 401.
What am I missing or doing wrong, a second pair of eyes could help.
const token = "./auth";
const listings = "./listings";
let clientHeaders = new Headers();
let raw = JSON.stringify({
email: "fake#account.com",
password: "12345",
});
clientHeaders.append("Authorization", "");
clientHeaders.append("Content-Type", "application/json");
clientHeaders.append("Cookie", "");
let req = {
method: "POST",
headers: clientHeaders,
body: raw,
redirect: "follow",
};
fetch(token, req)
.then((response) => response.json())
.then((result) => {
return fetch(listings, {
method: "GET",
headers: {
Authorization: result.token,
"Content-Type": "application/json",
},
});
})
.then((response) => {
return response.json();
})
.then((data) => {
console.log(JSON.parse(data));
})
.catch((error) => {
console.log("error: ", error);
});
You likely need to include the literal word "Bearer" and a space preceding the token in the header:
{
Authorization: `Bearer ${result.token}`
}
// or
{
Authorization: "Bearer " + result.token
}
So I have a service worker for fetch:
self.addEventListener('fetch', (event) => {
const requestProcessor = (idToken) => {
let req = event.request;
// For same origin https requests, append idToken to header.
if ((self.location.protocol === 'https:' ||
self.location.hostname === 'localhost') &&
idToken) {
// Clone headers as request headers are immutable.
const headers = new Headers();
for (let entry of req.headers.entries()) {
headers.append(entry[0], entry[1]);
}
// Add ID token to header.
headers.append('Authorization', self.location.origin === getOriginFromUrl(event.request.url) ? `Bearer ${idToken}` : idToken);
try {
req = new Request(req.url, {
method: req.method,
headers: headers,
mode: self.location.origin === getOriginFromUrl(event.request.url) ? 'same-origin' : req.mode,
credentials: req.credentials,
cache: req.cache,
redirect: req.redirect,
referrer: req.referrer,
body: req.body,
bodyUsed: req.bodyUsed,
context: req.context
});
} catch (e) {
console.error(e);
}
}
return fetch(req);
};
event.respondWith(getIdToken().then(requestProcessor));
});
It is being called in another file like so:
export const makePostRequest = (url = '', params = {}) => {
return fetch(url, {
method: 'POST',
body: JSON.stringify(params),
headers: {
'Content-type': 'application/json'
}
}).then((res) => res).catch((err) => console.log(err));
};
For some reason, the req.body is always undefined inside of the service worker. Furthermore, it looks like the fetch request happens twice. When I put a breakpoint and step through the code, I can see that nothing from the fetch is being picked up by the service worker. I don't understand.
Okay, so this isn't obvious. So after some research this solved my issue:
self.addEventListener('fetch', (event) => {
if (getOriginFromUrl(event.request.url) === 'https://app.example.com') {
const requestProcessor = (idToken) => {
let newRequest = null;
// For same origin https requests, append idToken to header.
if ((self.location.protocol === 'https:' || self.location.hostname === 'localhost') && idToken) {
try {
newRequest = new Request(event.request, {
headers: new Headers({
...event.request.Headers,
'Content-Type': 'application/json',
Authorization: 'Bearer ' + idToken,
})
})
} catch (e) {
console.log(e);
}
}
return fetch(newRequest);
};
/* Fetch the resource after checking for the ID token.
This can also be integrated with existing logic to serve cached files
in offline mode.*/
event.respondWith(getIdToken().then(requestProcessor, requestProcessor));
}
});
I also had to set the mode:
export const makePostRequest = (url = '', params = {}) => {
return fetch(url, {
method: 'POST',
mode: 'cors',
headers: {
'Content-type': 'application/json'
},
body: JSON.stringify(params)
}).then((res) => res).catch((err) => console.log(err));
};
There were two issues:
By default the header's mode was set to no-cors. According to a previous SO answer, I had to set the mode to cors to allow for non-basic headers which would also include body.
The other issue had to do with the headers being immutable. This had to be changed to copy properly.
The Request object will implement methods like .blob().
await req.blob()
I create the chrome extension in React . During request url delete, I received an error: Error: DELETE chrome-extension://ldkflkflkfklfkfksfk/[object%20Object] net::ERR_FILE_NOT_FOUND
I tried to do the Get method earlier. This method works. Also token, url are good.
In tab network in response headers I have Provisional headers are shown
delete = (id) => {
const url = `https://applic.com/api/v1/todos/${id}?expand=createdBy`;
const token = '12345';
axios.delete({
url: url,
headers: { 'Authorization' : `Bearer ${token}` }
}).then(function(response) {
console.log(`Deleted: ${id}` );
}).catch(function (error) {
console.log(`error: ${id}`);
});
const filter = this.state.items.filter(item=> item.id !== id);
this.setState({
items: filter,
isOpen: false
});
}
The syntax for axios.delete is axios.delete(url[, config])
The API call should be:
axios.delete(
url,
{
headers: { 'Authorization' : `Bearer ${token}`
}
})
Docs
How to update an axios instance while intercept a response using data from this response without second request? New token can be received in any response after any request. Last received token should be used in any new request.
const request = (axios as any).create({
baseURL: mainConfig.apiBaseUrl,
headers: {
'Content-Type': 'application/json',
},
});
// Check token relevance and update if not relevance.
request.interceptors.response.use(response => {
if (response.headers.token !== undefined) {
response.config.headers.token = response.headers.token;
}
return response;
});
Here, you can't set it for further requests like this.
You should use globalStorage or any other store for storing this token.
import Store from "Store";
const {token} = Store;
const request = (axios as any).create({
baseURL: mainConfig.apiBaseUrl,
headers: {
'Content-Type': 'application/json',
'Authorization': token
},
});
// Set token
request.interceptors.response.use(response => {
const {token} = response.headers;
if (token) {
Store.setToken(token);
}
return response;
}