Hi!
I’m curious what is a working way to get my SPA (front-end) + Node (back-end) setup to call the Management API using an M2M token without generating a CORS error?
Using the Auth0 tutorials, I can authenticate with Auth0 and also get the M2M token without problem. However, when I try to call the Management API using the received M2M token, I get a CORS error:
This occurs both when testing locally (with React-UI running on port 3000, and Node server running on port 5000) as well as after building and running it from Heroku, which is strange. I have put the origin domain into the Allowed Web Origins
and Allowed Origins (CORS)
boxes in the applications Auth0 settings. I also put the domain in the Access-Control-Allow-Origin
headers.
Here is the GET route I set up in my server.js (backend) file:
app.get(“/M2M”, async (req, res) => {
try {
const apiResponse = await fetch(
“https://dev-7-8i89hb.us.auth0.com/api/v2/”,
{
method: “POST”,
headers: { “content-type”: “application/json” },
body: ‘{“client_id”:“6J2cpQGzD456WzodmDHXj4Kot4y84bgI”,“client_secret”:“XXXXXXXXXXXXXXXXXXXXXXXXXXX”,“audience”:“https://dev-7-8i89hb.us.auth0.com/api/v2/",“grant_type”:"client_credentials”}’,
}
);
const apiResponseJson = await apiResponse.json();
console.log(apiResponseJson);
res.send(“Done – check console log”);
} catch (err) {
console.log(err);
res.status(500).send(“Something went wrong”);
}
});
And here is my setup to call the API from the frontend after receiving the M2M token (src/app.js):
const GetM2Mdata = () => {
const { user, isAuthenticated } = useAuth0();const [visible, setVisible] = useState(“false”);
var request = require(“request”);
var options = {
method: “POST”,
url: “https://dev-7-8i89hb.us.auth0.com/oauth/token”,
headers: { “content-type”: “application/json”,
“Access-Control-Allow-Origin”: “http://localhost:3000”,
},
body: ‘{“client_id”:“6J2cpQGzD456WzodmDHXj4Kot4y84bgI”,“client_secret”:“XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX”,“audience”:“https://dev-7-8i89hb.us.auth0.com/api/v2/",“grant_type”:"client_credentials”}’,
};const optionsM2M = {
method: “GET”,
url: “https://dev-7-8i89hb.us.auth0.com/api/v2/”,
headers: {
“content-type”: “application/json”,
authorization: “Bearer ACCESS_TOKEN”,
“Access-Control-Allow-Origin”: “http://localhost:3000/”
},
};request(options, function (error, response, body) {
if (error) throw new Error(error);console.log(body);
});
const getUsersData = function () {
axios
.request(optionsM2M)
.then(function (response) {
console.log(response.data);
})
.catch(function (error) {
console.error(error);
});
};return isAuthenticated ? (
<button class="buttonProfile" onClick={() => getUsersData()}> Get Users </button> </div>
) : (
“”
);
};
export default GetM2Mdata;
Again, the M2M token is received appropriately. On clicking the button in app.js, I would expect my back-end route to be called and using the received M2M token, to receive data from the Management API.
Other things I’ve tried include writing Actions/ Rules to automate getting the M2M token or using the M2M token to call the Management API. However, setting up and using a Rule get the M2M token still results in the CORS error (even when building from Heroku), while Actions doesn’t seem to be able to handle external modules. Hence, I can’t seem to use Fetch/Axios/etc. with Actions.
Also, as a further side question- but how is it possible to have both regular a Management API as well as an M2M client installed in the same SPA? It would appear that wrapping the root with more than one Auth0 clientId would almost certainly cause problems?
Any help would be sincerely appreciated; I’ve been stuck on this issue for a few days now.
Thanks,
Rob
No worries! Good to know that was helpful
You will need both - The SPA app configured in Auth0 will be specific to your React App/client side. On the other hand, you will have a M2M app configured in Auth0 specific to your own API/backend. The flow would look like this:
- User logs in to your React/SPA app.
- User goes to perform something (get all users for instance) that requires Management API use.
- This is really where the magic happens - Instead of your React app communicating directly with the Management API, it will communicate with your own API/Backend instead. Your API/Backend should take the query, make the necessary call to the Management API and then pass that response back to your React/SPA app.
The key here is that the backend process (M2M/Client Credentials Exchange) allows the Client Credentials to be abstracted from the SPA (public) app and safely used against the Management API.
Again, if all you need from the Management API is to get info about the current user and/or update the current user metadata, this can be accomplished from the React/SPA app directly as outlined here.
Hope this helps!