async function getAccessToken() {
const url = 'https://kettleon.kinde.com/oauth2/token';
const clientId = process.env.KINDE_CLIENT_M2M_ID
const clientSecret = process.env.KINDE_CLIENT_M2M_SECRET
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id:
${clientId},
client_secret:
${clientSecret},
audience: 'http://localhost:3000'
})
};
const response = await fetch(url, options);
const data = await response.json();
console.log(data)
console.log("token", data.access_token)
return data.access_token;
}
const addUser = async (e : any) => {
e.preventDefault();
const accessToken = await getAccessToken()
const inputBody =
{;
const headers = {
'Content-Type':'application/json',
'Accept':'application/json',
'Authorization':
Bearer ${accessToken},
'Access-Control-Allow-Origin':'https://kettleon.kinde.com'
};
await fetch('https://kettleon.kinde.com/api/v1/user',
{
method: 'POST',
body: inputBody,
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
}
audience
parameter in your getAccessToken
function is currently set to 'http://localhost:3000'
. This is not correct. The audience parameter should be set to the identifier for the Kinde Management API, not your local development URL. Based on the provided code and context, it should likely be 'https://kettleon.kinde.com/api'
. This is crucial for obtaining a valid access token that can be used to authenticate your API requests.'Access-Control-Allow-Origin':'https://kettleon.kinde.com'
header in your addUser
function is not necessary and might be incorrect in this context. This header is used by servers to indicate which origins are allowed to read the response in a cross-origin request, and it's not something you set on the request from the client side. The server (in this case, Kinde) dictates this policy. You can remove this line from your headers object.inputBody
, you're using template literals incorrectly inside a JSON string. This will not automatically convert the values to strings or escape them as needed. Instead, consider constructing your JSON object as an actual JavaScript object and then stringify it when making the fetch call. This approach also makes it easier to handle dynamic values correctly.addUser
function with these adjustments:const addUser = async (e) => { e.preventDefault(); const accessToken = await getAccessToken() const inputBody = { profile: { given_name: e.target.given_name.value, family_name: e.target.family_name.value, }, organization_code: props.organisation, identities: [ { type: "email", details: { email: e.target.email.value } } ] }; const headers = { 'Content-Type':'application/json', 'Accept':'application/json', 'Authorization':`Bearer ${accessToken}` }; await fetch('https://kettleon.kinde.com/api/v1/user', { method: 'POST', body: JSON.stringify(inputBody), headers: headers }) .then(function(res) { return res.json(); }).then(function(body) { console.log(body); }); }
KINDE_CLIENT_M2M_ID
and KINDE_CLIENT_M2M_SECRET
) are correctly set to the values for your machine-to-machine application in Kinde. This is essential for the getAccessToken
function to work properly.Our app is full-stack NextJS using app routing with TypeScript, so I looked through the NextJS SDK documentation. I first got very stuck looking at the code snippets there as I couldn't find any documentation for how to use the API with createKindeManagementAPIClient especially trying to use the createUser method on the usersApi.I will pass on this feedback, there is definitely an opportunity to make our NextJS docs better.
const addUser = async (e : any) => {
e.preventDefault();
const accessToken = await getAccessToken()
const inputBody = {
"profile": {
"given_name": e.target.given_name.value,
"family_name": e.target.family_name.value,
},
"organization_code": props.organisation,
"identities": [
{
"type": "email",
"details": {
"email": e.target.email.value
}
}
]
};
const headers = {
'Content-Type':'application/json',
'Accept':'application/json',
'Authorization':
Bearer ${accessToken},
};
await fetch('https://kettleon.kinde.com/api/v1/user',
{
method: 'POST',
body: JSON.stringify(inputBody),
headers: headers
})
.then(function(res) {
return res.json();
}).then(function(body) {
console.log(body);
});
}