I am using React with auth0-spa-js, and I am having issues trying to get/set user metadata.
I’ve followed the sample react code to create a basic application which works great. I am trying to add a page which allows users to update their profile data (change picture, meta data and stuff), but if I try to get or set the user profile, it comes back with a 400 error:
I think this is because you haven’t declared the management api as an audience for the token. The managment API is seperate from the authentication API.
Take a look at this doc:
If you toggle to the node implementation you can probably just use that, if you use request instead of axios. Or just tailor it to axios, whatever you are comfortable with. Let me know if that does it.
Thanks,
Dan
P.S. as a reminder, SPAs are limited in the scopes they can request from the management api
Thanks dan. As you’ve pointed out, my requests weren’t authorized to access the management api.
I fixed this by requesting a token silently with the scope as the audience. This sample demonstrates:
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { useAuth0 } from "./Auth0Wrapper";
import { stringIsNullOrEmpty } from '../utils/strings.js';
/**
* definitions for each api that i want to use
*/
const apiConfig = {
custom:{
baseURL: "https:// [actual api path] .com",
audience: "https:// [custom api audience]",
scope: null
},
management:{
baseURL: "https:// [custom domain or {tenant}.{region}.auth0.com] .com/api/v2/",
audience: "https:// [management api audience]",
scope: "openid profile email read:current_user update:current_user_metadata"
}
}
/**
* creates an API and applies to token
*/
const createApi = (baseURL, token) => axios.create({
baseURL,
headers: {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
/**
* gets a token silently. If this fails, get it with a popup. then use it to create the api
*/
const createLazyTokenizedApi = (getTokenSilently, getTokenWithPopup, apiConfig) => {
let options = {
audience: apiConfig.audience
};
if(!stringIsNullOrEmpty(apiConfig.scope))
options.scope = apiConfig.scope;
return () => getTokenSilently(options).then(accessToken =>
{
console.log('silently retrieved token', accessToken);
return createApi(apiConfig.baseURL, accessToken);
},
fail => {
console.log('failed to get token', fail);
return getTokenWithPopup(options).then(
accessToken => {
console.log('popup retrieved token', accessToken);
return createApi(apiConfig.baseURL, accessToken);
},
fail => {
console.error('cannot get token', fail);
});
}
);
}
/**
* creates all apis that I want to use in the application
*/
const createApiLookup = (getTokenSilently, getTokenWithPopup) => {
return {
getManagementApi: createLazyTokenizedApi(getTokenSilently, getTokenWithPopup, apiConfig.management),
getCustomApi: createLazyTokenizedApi(getTokenSilently, getTokenWithPopup, apiConfig.custom),
};
}
/**
* main application
*/
export default () => {
const { getTokenSilently, getTokenWithPopup, user } = useAuth0();
const apiLookup = createApiLookup(getTokenSilently, getTokenWithPopup);
let [userProfile, setUserProfile] = useState({});
useEffect(() => {
apiLookup.getManagementApi().then(api => {
const path = `/users/${user.sub}`;
return api.get(path).then(
({ data }) => setUserProfile(data),
fail => console.log('failed', fail)
)
});
}, []);
return (
<div>
<h1>My Auth0 React Application</h1>
<h3>user profile:</h3>
<pre>{JSON.stringify(userProfile, null, 2)}</pre>
</div>
);
}