I am trying to understand this code. And also how to use it
https://stackoverflow.com/a/53294310/2897115
createAxiosResponseInterceptor() {
const interceptor = axios.interceptors.response.use(
response => response,
error => {
// Reject promise if usual error
if (errorResponse.status !== 401) {
return Promise.reject(error);
}
/*
* When response code is 401, try to refresh the token.
* Eject the interceptor so it doesn't loop in case
* token refresh causes the 401 response
*/
axios.interceptors.response.eject(interceptor); <---- What does this do
return axios.post('/api/refresh_token', {
'refresh_token': this._getToken('refresh_token')
}).then(response => {
saveToken();
error.response.config.headers['Authorization'] = 'Bearer ' + response.data.access_token;
return axios(error.response.config); <--- what does this do
}).catch(error => {
destroyToken();
this.router.push('/login');
return Promise.reject(error);
}).finally(createAxiosResponseInterceptor);
}
);
}
Generally i use axios script with access_token is as:
const url = "dj-rest-auth/password/change/";
const auth = {
headers: {
Authorization: "Bearer " + localStorage.getItem("access_token"),
Accept: "application/json",
"Content-Type": "application/json",
},
};
const data = {
old_password: old_password,
new_password1: new_password1,
new_password2: new_password2,
};
const promise = axios.post(url, data, auth);
promise
.then((res) => {
console.log(res)
})
.catch((err) => {
if (err.response) {
console.log(`${err.response.status} :: ${err.response.statusText}`)
console.log(err.response.data)
}
})
And in this code how to use the interceptor
Eject interceptor
axios.interceptors.response.eject(interceptor); <---- What does this do
Internally, interceptors.response is an array of interceptors, the method axios.interceptors.response.use return the id of the new interceptor. Calling eject passing the id of the interceptor will set the corresponding item in the array to null, and the interceptor has no effect anymore.
When we receive the response code 401, we use the interceptor to send another request to get the token. To avoid the infinity loop if the latter also receives the response code 401, we eject the interceptor in this case.
Resend original request
return axios(error.response.config); <--- what does this do
After receiving the token, we want to resend the original request, its configuration is stored in error.response.config according to the response schema
To use the function, call it before sending the request. (People talk about it in the thread of the accepted answer.)
Related
I am in a next-js app and my auth token is stored in cookies.
For some raisons i use Swr and Api route to fetch my secured api backend.
i am trying to find a way to put my auth token in all api request.
During login cookie is set
res.setHeader(
'Set-Cookie',
cookie.serialize('token', data.access_token, {
httpOnly: true,
secure: process.env.NODE_ENV !== 'development',
maxAge: data.expires_in, // 1 week
sameSite: 'strict',
path: '/',
}),
);
This is an example of a page using swr fetch
//page/test.ts - example of my test route
const { data, error } = useFetchContent(id);
if (error) {
showError('error');
replace('/');
}
return <DisplayContent content={data} />
This is a swrFetchHook
// fetchContentHook
function useFetchContent(id: string): ContentDetail {
return useSWR<any>(`/api/content/${id}`, fetcherApiRoute);
}
const fetcherApiRoute = (url: string): Promise<any> => {
return axios(url)
.then((r) => r.data)
.catch((err) => {
console.info('error is ', err)
throw err
});
};
export default useFetchContent;
inside api route
export default async (req, res): Promise<ContentDetail> => {
const { id } = req.query;
if (req.method === 'GET') {
const fetchRealApi = await apiAxios(url);
if(fetchRealApi) {
// here depending on result of fetchRealApi i add some other fetch ...
return res.status(200).json({ ...fetchRealApi, complement: comp1 });
}
return res.status(500)
}
return res.status(500).json({ message: 'Unsupported method only GET is allowed' });
};
and finally api axios configuration
const apiAxios = axios.create({
baseURL: '/myBase',
});
apiAxios.interceptors.request.use(
async (req) => {
// HERE i am trying to get token from cookies
// and also HERE if token is expired i am trying to refresh token
config.headers.Authorization = token;
req.headers['Content-type'] = 'application/x-www-form-urlencoded';
return req;
},
(error) => {
return Promise.reject(error);
},
);
export default apiAxios;
I am stuck here because i cant find token during apiAxios.interceptors.request.use...
Did you know what i am doing wrong, and am i on a correct way to handle this behavior ?
To allow sending server cookie to every subsequent request, you need to set withCredentials to true. here is the code.
const apiAxios = axios.create({
baseURL: '/myBase',
withCredentials: true,
});
Nilesh's answer is right if your API is able to authorize requests based on cookies. Also it needs the API to be in the same domain as your frontend app. If you need to send tokens to the API (the one which is in the cookie), then you will need a small backend component often called BFF or Token Handler. It can extract the token from the cookie and put in an Authorization header.
At Curity we've created a sample implementation of such a Token Handler, of which you can inspire: https://github.com/curityio/kong-bff-plugin/ You can also have a look at an overview article of the Token Handler pattern.
I'm working on my very first nextjs application. I'm using an axios instance to handle my calls to backend
export const httpClient = axios.create({
baseURL: `${process.env.BASE_URL}`,
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
});
I'm also using next-auth to handle my authentication and authorization
const callbacks = {
async jwt(token, user) {
if (user) {
token.accessToken = user.access_token;
}
return token;
},
async session(session, token) {
session.accessToken = token.accessToken;
return session;
},
};
The call to the authentication endpoint is working correctly. If I console.log() the api response I can see the returned JWT token.
I'm now trying to attach that JWT token to every axios request but the call await getSession() is always null. I wrote following request interceptor
httpClient.interceptors.request.use(
async (config) => {
const session = await getSession();
if (session) { // this never evaluates to true. Session is always `null`
console.log(session);
config.headers.Authorization = `Bearer ${session?.accessToken}`;
}
return config;
},
(error) => {
return Promise.reject(error);
},
);
Following the docs, I wrapped my _app.js <Component> with
<Provider session={pageProps.session}>
<Component {...pageProps} />
</Provider>
Any ideas what I could try next?
Edit:
I call const [session, loading] = useSession(); on another part of the code (in the nextjs frontend) and there everything seems to be working
The problem is that if the axios call is made on the server side, then the interceptor will also be executed on the server side.
If that is the case, when calling getSession() on the server side, you also have to pass it the request or the context (see the note at the bottom of the manual entry for getSession)
I'm trying to make HTTP POST request to consume Mailchimp API (From Angular7 code)
but i'm getting this response:
Access to XMLHttpRequest at 'https://us12.api.mailchimp.com/3.0/lists/ddddddd/members' from origin 'http://localhost:4200' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
From REST client i'm able to make insert in Mailchimp without having this CROS issue
export class MyService {
constructor(public httpRequestsService: HttpRequestsService) { }
private async getHttpHeader() {
const rheaders = new HttpHeaders({
'Content-Type': 'application/json' ,
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'POST, GET, OPTIONS',
'Access-Control-Allow-Headers':'X-Requested-With',
'Authorization': 'apikey ' + MailchimpSettings.API_KEY
});
return { headers: rheaders };
}
public async AddNewMember(email: string, language = 'en', status = , mergeFields?: any) {
var url = MailchimpSettings.URL;
var body = {
"email_address": email,
"status": MailchimpSettings.SUBSCRIBED_STATUS,
"language": language
};
var httpOptions = await this.getHttpHeader();
var _body = JSON.stringify(body);
var result = await this.post(url, _body, httpOptions);
}
public async post(url: string, body: string | {} = {}, requestHeaders?: any): Promise<Response> {
return this.http.post(url, body, requestHeaders).toPromise()
.then((res: any) => {
return res;
})
.catch((err) => {
return this.handleErrorPromise(err);
});
}
}
Anyone who can help me with right HTTP headers (or any required change) to reproduce exactly REST client behavior and be able to make a successful POST.
Thanks for your help
Unfortunately, the answer is you can't. Mailchimp does not support CORS because that would require passing API credentials, and that is not secure.
The option is to make requests from another server like you mentioned from the REST client or make a custom signup form that will use more restricted API call.
Or use jsonp request for mailchimp form clients.
See this
I've got working backend in Spring Boot with JWT-secured endpoint for modifying avatar of current user. The following request from Insomnia with correct Bearer works fine:
But this code
updateAvatar(context, avatar) {
const fd = new FormData();
fd.append('file', avatar.data);
return new Promise((resolve, reject) => {
axios.post('/saveavatar',
{file: fd},
{headers: {'Authorization': 'Bearer ' + localStorage.getItem('access_token')}})
.then(response => {
resolve(response)
})
.catch(error => {
reject(error)
})
})
},
fails with error
the request was rejected because no multipart boundary was found
What am I doing wrong?
The second argument to post should be the actual FormData, fd in your case.
axios.post('/saveavatar',
fd,
{headers: {'Authorization': 'Bearer ' + localStorage.getItem('access_token')}})
The reason it works in Insomia is that it takes care of your request and figures out that it needs to ads a boundary, axios will do the same, but needs a valid FormData.
I am trying to upload a photo to a webservice and the documentation clearly specifies that the request type is Multipart/files so I am trying this request with axios which always fails.
HTTP.put(`/employees/${response.data.data.id}/photo`, { photo: this.image }, {headers: { put: { 'Content-Type': 'multipart/files' }}})
.then((profilePictureResponse) => {
console.log(profilePictureResponse);
})
.catch((error) => {
console.log(error.response);
});
HTTP is an axios instance with default configurations but the default content-type is set to application/json