Testing authorized API calls on FrontEnd - reactjs

I have a react app, in which I have defined functions for APIs, so that I can call these functions where I need.
Now the thing is I want to write tests for these API calls. My API function use Axios internally for executing requests. In the app I use Axios Interceptors to add auth token to these requests, and now I want a clean way to test such authorized APIs which needs tokens in their headers.
My question is how can I use test these authorized API function without disturbing my design.
Here is a sample API function which I want to test, it needs auth token in the header:
export const delete_store = (id) => {
return Axios.delete(`api/example/url/${id}`);
};

you can pass headers as second argument.
Axios.delete(URL, {headers: { auth: token }})

Related

How to do a HTTP head request in next.js

I want to achieve the same done here but in next.js.
Next.js provides methods to fetch data from a server and using them as props. I don't know whether you want to use it before rendering a page (like getServerSideProps) or when, for example, you click a button, but I suppose its the first case.
My personal preference when doing requests, is axios, so I will use it in this example:
export async function getServerSideProps({ req, res }) {
// Here is where we make the request
const result = await axios({
method: 'HEAD', // here is where we declare that we want to use the HEAD method
url: "your server url", // this is the url where we want to send the request
headers: {} // if you want to add custom headers, you can do it here
})
// Here we are logging the result of the request
console.log(result)
}
You can refer to the next.js documentation on data fetching and the axios documentation
Have a great day and I hope you succeed on your projects

HERE Geocoding API - not working inside my React app

I have a React app in which I use the HERE Geocoding API. I have an axios request to retrieve latitude and longitude and it does not work as well as expected. The request is not working inside my app
return axios.get(`https://geocode.search.hereapi.com/v1/geocode?q=${address}&apiKey=myAPIKey`)
I have a 401 error. Bearer token invalid. Bearer missing or bearer value missing. If I open a new tab in my browser and paste the url https://geocode.search.hereapi.com/v1/geocode?q=${address}&apiKey=myAPIKey it works fine and I get the result I need.
I tried using the Authorization header
const config = {
headers: {
'Accept': 'application/json',
'Authorization': `apiKey myAPIKey`,
}
};
return axios.get(`https://geocode.search.hereapi.com/v1/geocode?q=${address}&apiKey=myAPIKey`,config)
In the Authorization header, I tried with Bearer and Basic instead of apiKey
documentation HERE API
In the documentation about how to create an API Key and how to use it, the only thing I need to do is what I have already done. I have created a project, an API Key and I use it in my request.
HERE Geocoding API Key
I don't know how the HERE api works but the error message is probably the answer you are looking for.
You are likely to provide the api key via the Authorization header with your request. Read about the header on MDN
You just need to pass your API key in the link as a parameter.
Just sign up and you can get your API key.
https://developer.here.com/sign-up
The code should be like this.
return axios.get(`https://geocode.search.hereapi.com/v1/geocode?q=${address}&apiKey=${HERE_MAP_API_KEY}`,config)
The latest request would look like this.
axios.get(`https://geocoder.ls.hereapi.com/search/6.2/geocode.json?languages=en-US&maxresults=${maxResults}&searchtext=${query}&apiKey=${HERE_MAP_API_KEY}`)
.then(res => {
const data = res.data
console.log(data)
})
.catch(err => console.log(err))

Access token appears to be incorrect format using auth0-react library

I am following this blog post on how to use the auth0-react library.
The post describes using the getAccessTokenSilently from the useAuth0 hook to get the access token which is used as the bearer token
const callSecureApi = async () => {
try {
const token = await getAccessTokenSilently();
const response = await fetch(`${apiUrl}/api/private-message`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
const responseData = await response.json();
setMessage(responseData);
} catch (error) {
setMessage(error.message);
}
};
The issue I'm having is the token doesn't appear to be a JWT token - it looks like:
RJq7USOcszn7rpyI5iDjbYAKp9pK60Ap
Does anyone know why getAccessTokenSilently isn't returning a JWT token?
The same task took me a while as well, the docs are neither very clear nor up-to-date there I feel. Here is what you need to do:
For Auth0, you need both a Single Page Application under "Applications", and an API under "APIs"
Your React App gets wrapped with something like the below. Note the audience parameter from your API, this is the crucial part, without it, I also got the same small and useless access token you got!
<Auth0Provider
domain={AUTH0_DOMAIN} // taken from the SPA application in Auth0
clientId={AUTH0_CLIENT_ID} // taken from the SPA application in Auth0
authorizationParams={{
audience={AUTH0_AUDIENCE} // taken from your API in Auth0
redirectUri={window.location.origin}
}}
useRefreshTokens={true}
cacheLocation={"localstorage"}
>
Wherever you want to call your Backend (e.g. Spring Boot), you add the following to the component:
const {user, getAccessTokenSilently} = useAuth0();
...
// this will now be a JWT token, BUT ONLY if you specified the API audience in the Auth0Provider
// looks something like this:
/* eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlFqZEVNMEU1TnpWRE0wTkRSRVEzUkVFMFFVSkJOamMwUmtGRE1qZzNPVGxCTURNMk56UTJSZyJ9.eyJpc3MiOiJodHRwczovL3JhcGlkbWluZXIuYXV0aDAuY29tLyIsGnN1YiI6ImF1dGgwfDUzNDc5YzMwNmU5Yjc4YTU3MzAwMDVjNSIsImF1ZCI6WyJodHRwczovL2VuZ2luZWVyaW5nLXRvb2xzLnJhcGlkbWluZXIuY29tL2FwaSIsImh0dHBzOi8vcmFwaWRtaW5lci5hdXRoMC5jb20vdXNlcmluZm8iXSwiaWF0IjoxNTk2ODM2MDMyLCJleHAiOjE1OTY5MjI0MzIsImF6cCI6IllldWhoS29JV1lTV2FYUmExNU1sNTFMZUExYkp4bjVlIiwic2NvcGUiOiJvcGVuaWQgcHJvZmlsZSBlbWFpbCJ9.zI74HHd1pCzz-xBQEDDKby9z_Ue9_AIz-r05_my1wvLQ0U94u9WrwWmSxd9BQ-2XOHKa1KgnaaxsX2aiSHil7a4YjMnrYo9f0jgMmlxcllqZJgeb0AhLQNfYQEr6nAKP_8PgN0D7QFjIxiFTpDndTcD_2nG9DEsxbraT7dDy0pf1KTGmhQnNyBuyReAEUFhlxd1LAd63ED14nCPmEehl5rLNUwClTRFQ5q4ERLjM8cX0GLLy5F-I7UjpDOBnrL_qMqfuHyuChxs-k0fHhhEfV8xE2nEV00cXcAp3zvpJ_Ox9U0OBaVUbf1vi9v1Wl6jaMZpgqRZ1bZcfDXWjoEBVlQ */
const accessToken = await getAccessTokenSilently();
Now you can pass the accessToken along via Authorization header:
headers: {
"Authorization": `bearer ${accessToken}`
}
Your BE can now validate the regular JWT token.
From Auth0 docs:
id_token: contains an ID Token and is present if the request parameter response_type included the value id_token, or the scope request parameter the value openid
From various Auth0 employees in the Auth0 forums:
How to get an access token in JWT format?
if you update the scope parameter to specify openid ... then you should receive a response containing an id_token parameter that would indeed be a signed JWT
OIDC Access Token (mine is opaque, but docs say it should be JWT)
In addition to specifying openid:
If you specify an audience, and the audience is a custom API you built, then you’ll get a JWT token
So, in the options object of getAccessTokenSilently, make sure:
the scope parameter includes openid
the audience parameter refers to your API

Is it possible to make a pseudo-global promise rejection handler?

fetch() is a great improvement over the classic XMLhttpRequest() However I was wondering if I add window.addEventListener('unhandledrejection', event => ···); to my index.android.js and index.ios.js could I theoretically remove all of my .catch() from my promise chains and make a pseudo global promise rejection handler? I am building a react native app that relies heavily on api calls, many of which are authenticated with user tokens. When a user logs in a token is stored in asynchronous storage, but each token will expire after a certain amount of time. if a user opens the app and unwittingly attempts to make a call that requires authentication with an expired token I would like the user to be routed to the login page regardless of what call was made, or what component the call is in. I currently have each individual promise chain handling unauthenticated calls on their own. Is there a better way to do it?
You could make a custom abstraction on top of fetch, which will provide a way of communicating with API and also have some business logic, which for you case is to request an auth token or make a redirect. Then you use this abstraction in the rest of the code to make API calls. Here is a small example to demonstrate the idea:
export default function request(url, options = {}) {
const req = fetch(url)
.then((response) => {
// Global response handler
// ...
// Hand response down the promise chain
return response;
})
.catch((err) => {
// Global error handler
// Check error status and (make redirect/request auth token)
// Throw error down the promise chain if needed
throw err;
});
// Returns a promise
return req;
}
Then you use it in your code like fetch(), but instead you'll be able to modify and extend it for you needs any time.
request('http://example.com/api/post/1')
.then((response) => {
// "response" has whatever you returned from global handler
})
.catch((err) => {
// "err" is whatever you've thrown from global handler
});

Token API and Backend Google OAuth in Node and Angular

We are transitioning from an API using cookies for state (ExpressJS sessions) to a stateless (token) API.
We use a single PassportJS authentication strategy (GoogleStrategy). When the OAuth flow completes, Google calls back to a backend route with an access token.
Previously, we would set a cookie at this point using req.session and redirect the user to our dashboard.
With a token API, we generate a token based on the email (acting as a username) and access token (acting as password) when Google calls back to the backend route.
How do we pass this token to the front-end (Angularjs) so that it can make authenticated requests?
Do we need to switch to Google's front-end OAuth APIs?
One way to pass the token to a client-side web application is to put the signed JSON web token into the cookie , which your client-side app can access and use (either appending the token to every GET request or using it in your web socket authentication). Just to be clear, you're no longer using cookies as a reference for server-recorded state, instead you're are simply using them as a storage mechanism that both client and server can access, where you can store your encoded token.
Here's a great example from the generator-angular-fullstack:
In the router, receiving the callback from the google authentication:
.get('/callback', passport.authenticate('google', {
failureRedirect: '/signup',
session: false
}), auth.setTokenCookie);
And the setTokenCookie function:
function setTokenCookie(req, res) {
if (!req.user) return res.json(404, { message: 'Something went wrong, please try again.'});
var token = signToken(req.user._id, req.user.role);
res.cookie('token', JSON.stringify(token));
res.redirect('/');
}
And the signToken function:
function signToken(id) {
return jwt.sign({ _id: id }, config.secrets.session, { expiresInMinutes: 60*5 });
}

Resources