K
Kinde11mo ago
ooi cat

Need help with roles (setPermission(s), setRole(s))

Hey. I want to programmatically set roles/permissions for users, is this in any way possible, or should I use a seperate db to implement this. The Kinde next app router v2 server/clientside libs give me getters for a lot of stuff but it seems that a lot of stuff can be set only manually. My motivation for doing this is that I would like to give user some perm(s)/role(s) when they subscribe with stripe. Dont know yet how I'm implementing that. Just would love to use kinde + subscriptions in my next app Also see that you guys are working on the "Billing" feature 👏 . How should one do billing currently in kinde next environment?
20 Replies
ooi cat
ooi catOP11mo ago
After careful search through this server, gooby is now enhanced with the knowledge that there exists a Kinde Management API
ooi cat
ooi catOP11mo ago
maybe on the right path?
No description
Oli - Kinde
Oli - Kinde11mo ago
Hi @gooby.wooby, Yes you can programmatically set roles and permissions of users (within an organization) via the following 2 API calls: 1. Add Organization User Role 2. Add Organization User Permission Let me know if you have any questions. With our upcoming Billing feature, you can create plans and set the features under each plan. So that when a user signs-up to a plan, they will get entitled to the features under that plan, and those features will be claims in the user tokens. I cannot provide concrete information yet on how to do Billing with Kinde on a NextJS environment, but we are on-track to release a private beta of our Billing feature by the end of March. It would be great if you could explain a bit more about: 1. What you are building 2. Is your product B2B? B2C? Something else? 3. Ideally what pricing plans and models (e.g. $10/month) do you wish to offer your customers?
ooi cat
ooi catOP11mo ago
Hey. I tried through basic rest calls with the fetch library and it seemed to work, at that point I found out about the existence of clientAPI and tried to use that to give organization user a role, it gave 400 bad request. I had all 3 params, roleId, orgCode and userId existing and I checked the types matched your defs. Then I realized that the clientApi way doesn't ask for bearer access_token like the rest way of interacting with the API does, but I don't think that's it because the clientApi worked and gives me users, roles, perms with the gets, just like in the n.js app v2 example docs. I also tried using clientApi in server side component, in route handler and in form action that is exported from actions.ts, and I get this error about "setting cookies is only allowed on request handlers/form actions", but thats another story. But basically, getting 400 bad req when calling clientApi.organizationApi.methodThatCreatesUserARole() Sorry, I'm at bed, I'll get back to it when I wake up and form a proper answer + test more. Probably just still misscalling because I get 400. Thank you for reaching
Oli - Kinde
Oli - Kinde11mo ago
Hey @gooby.wooby, I'm sorry to hear that you're having trouble with assigning roles to users. The 400 Bad Request error usually indicates that the server could not understand the request due to invalid syntax. Here are a few things you could check: 1. Make sure you're using the correct method. The method to assign a role to a user in an organization is addOrganizationUserRole(), not methodThatCreatesUserARole(). 2. Ensure that the parameters you're passing to the method are correct. The addOrganizationUserRole() method requires three parameters: orgCode, userId, and roleId. Make sure these are all valid and exist in your database. 3. Check the order of the parameters. The order should be orgCode, userId, roleId. 4. Make sure you're using the correct instance of the Kinde Management API. If you're calling this method in a server-side component or route handler, you should be using createKindeManagementAPIClient() to create the API client. 5. Regarding the error about setting cookies, this is because cookies can only be set in request handlers or form actions in Next.js. If you're trying to set a cookie in a server-side component, you'll need to move this logic to a request handler or form action. If you're still having trouble, could you please provide the exact code you're using to call the addOrganizationUserRole() method? This will help me understand the issue better and provide a more accurate solution. Let me know if you have any other questions! I'm here to help.
ooi cat
ooi catOP11mo ago
I called it like this:
const response = await apiClient.organizationsApi.createOrganizationUserRole({
createOrganizationUserRoleRequest: {
roleId: roleId
},
orgCode: orgCode,
userId: userId
})
const response = await apiClient.organizationsApi.createOrganizationUserRole({
createOrganizationUserRoleRequest: {
roleId: roleId
},
orgCode: orgCode,
userId: userId
})
in the libs its:
export interface CreateOrganizationUserRoleOperationRequest {
orgCode: string;
userId: string;
createOrganizationUserRoleRequest: CreateOrganizationUserRoleRequest;
}
export interface CreateOrganizationUserRoleOperationRequest {
orgCode: string;
userId: string;
createOrganizationUserRoleRequest: CreateOrganizationUserRoleRequest;
}
export interface CreateOrganizationUserRoleRequest {
/**
* The role id.
* @type {string}
* @memberof CreateOrganizationUserRoleRequest
*/
roleId?: string;
}
export interface CreateOrganizationUserRoleRequest {
/**
* The role id.
* @type {string}
* @memberof CreateOrganizationUserRoleRequest
*/
roleId?: string;
}
ooi cat
ooi catOP11mo ago
No description
Oli - Kinde
Oli - Kinde11mo ago
Ah you are totally right. In that case, here are a few things you could check: 1. Make sure the roleId, orgCode, and userId are valid and exist in your database. 2. Ensure that the roleId is a string. If it's a number, you might need to convert it to a string before passing it to the method. 3. Check if the roleId is optional in your database. If it's not, you need to provide a valid roleId. 4. Make sure you're using the correct instance of the Kinde Management API. If you're calling this method in a server-side component or route handler, you should be using createKindeManagementAPIClient() to create the API client. If you're still having trouble, could you please provide the exact error message you're getting? This will help me understand the issue better and provide a more accurate solution. Let me know if you have any other questions! I'm here to help.
ooi cat
ooi catOP11mo ago
I'll ensure the types I use this:
import { createKindeManagementAPIClient, getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server"

// in React server-component: ...
const apiClient = await createKindeManagementAPIClient();
import { createKindeManagementAPIClient, getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server"

// in React server-component: ...
const apiClient = await createKindeManagementAPIClient();
Missed this. 1. Drafting tool for a game called League of Legends 2. B2C 3. We are going to have 2-3 paid tiers, eg 5$ 10$ and one more It's usable at https://www.drafter.lol but it's still under heavy work It's going to be fairly small application / userbase (probably) just a passion project really
ooi cat
ooi catOP11mo ago
Here is the error I get
No description
ooi cat
ooi catOP11mo ago
Not quite sure what the "Check if the roleId is optional in your database" means. I'm using the roleId from kinde:
const roles = await apiClient.rolesApi.getRoles()
...then get role id I want
const roles = await apiClient.rolesApi.getRoles()
...then get role id I want
Oli - Kinde
Oli - Kinde11mo ago
Exciting! Thanks for explaining the details above. I will have to pass on your issue to my expert nextjs teammate on Monday
ooi cat
ooi catOP11mo ago
I could create organizations with the apiClient for example maybe I'll just try fetch + bearer token thanks for quick reach mate!
Oli - Kinde
Oli - Kinde11mo ago
No worries. I'll get back to you on Monday
ooi cat
ooi catOP11mo ago
gooby thank Ok, got it working using fetch and bearer tokens: would like to use the api though
/**
* @returns access_token for accessing Kinde management API
*/
export const getKindeAccessToken = async (): Promise<any> => {
const response = await fetch("https://riku.kinde.com/oauth2/token", {
method: "POST",
headers: {
"content-type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
audience: "https://riku.kinde.com/api",
grant_type: "client_credentials",
client_id: process.env.KINDE_CLIENT_ID as string,
client_secret: process.env.KINDE_CLIENT_SECRET as string,
})
})

return response.json()
}


/**
* @param roleId role to give to the Kinde user
* @param userId id of the user to update
* @param orgCode Kinde organization where the update happens in
*/
export const kindeAddRoleToUser = async (roleId: string, userId: string, orgCode: string): Promise<any> => {
if(!roleId || !userId) { return }
const { access_token: accessToken } = await getKindeAccessToken()
console.log("using accessToken:", accessToken)
const inputBody = JSON.stringify({
"role_id": roleId
})
const headers = {
"Content-Type":"application/json",
"Accept":"application/json",
"Authorization":`Bearer ${accessToken}`
};
const response = await fetch(`https://riku.kinde.com/api/v1/organizations/${orgCode}/users/${userId}/roles`, {
method: "POST",
headers: headers,
body: inputBody
})
return response.json()
}
/**
* @returns access_token for accessing Kinde management API
*/
export const getKindeAccessToken = async (): Promise<any> => {
const response = await fetch("https://riku.kinde.com/oauth2/token", {
method: "POST",
headers: {
"content-type": "application/x-www-form-urlencoded",
},
body: new URLSearchParams({
audience: "https://riku.kinde.com/api",
grant_type: "client_credentials",
client_id: process.env.KINDE_CLIENT_ID as string,
client_secret: process.env.KINDE_CLIENT_SECRET as string,
})
})

return response.json()
}


/**
* @param roleId role to give to the Kinde user
* @param userId id of the user to update
* @param orgCode Kinde organization where the update happens in
*/
export const kindeAddRoleToUser = async (roleId: string, userId: string, orgCode: string): Promise<any> => {
if(!roleId || !userId) { return }
const { access_token: accessToken } = await getKindeAccessToken()
console.log("using accessToken:", accessToken)
const inputBody = JSON.stringify({
"role_id": roleId
})
const headers = {
"Content-Type":"application/json",
"Accept":"application/json",
"Authorization":`Bearer ${accessToken}`
};
const response = await fetch(`https://riku.kinde.com/api/v1/organizations/${orgCode}/users/${userId}/roles`, {
method: "POST",
headers: headers,
body: inputBody
})
return response.json()
}
edit: (feel free to tag or even directly dm. dm has higher chance of quick response)
Oli - Kinde
Oli - Kinde11mo ago
Hey @gooby.wooby, I'm glad to hear that you were able to get it working using fetch and bearer tokens! If you want to use the Kinde Management API client, you can do so by creating an instance of the client and setting the access token in the headers. Here's how you can do it:
import { KindeManagementAPIClient, CreateOrganizationUserRoleRequest } from '@kinde/management-api-client';

// Create an instance of the Kinde Management API client
const apiClient = new KindeManagementAPIClient({
basePath: 'https://riku.kinde.com/api/v1',
headers: {
'Authorization': `Bearer ${accessToken}`
}
});

// Create a request to add a role to a user
const request: CreateOrganizationUserRoleRequest = {
roleId: roleId
};

// Call the method to add a role to a user
const response = await apiClient.organizationsApi.createOrganizationUserRole({
orgCode: orgCode,
userId: userId,
createOrganizationUserRoleRequest: request
});
import { KindeManagementAPIClient, CreateOrganizationUserRoleRequest } from '@kinde/management-api-client';

// Create an instance of the Kinde Management API client
const apiClient = new KindeManagementAPIClient({
basePath: 'https://riku.kinde.com/api/v1',
headers: {
'Authorization': `Bearer ${accessToken}`
}
});

// Create a request to add a role to a user
const request: CreateOrganizationUserRoleRequest = {
roleId: roleId
};

// Call the method to add a role to a user
const response = await apiClient.organizationsApi.createOrganizationUserRole({
orgCode: orgCode,
userId: userId,
createOrganizationUserRoleRequest: request
});
In this example, accessToken is the access token you obtained from getKindeAccessToken(). Please note that you'll need to install the @kinde/management-api-client package to use the Kinde Management API client. You can install it using npm:
npm install @kinde/management-api-client
npm install @kinde/management-api-client
I hope this helps! Let me know if you have any other questions. I'm here to help. Sounds like you are building LoL project. Thanks for sharing these details.
We are going to have 2-3 paid tiers, eg 5$ 10$ and one more
Is it going to be like, e.g. $5/month, $10/month, etc...?
ooi cat
ooi catOP11mo ago
Yup! Good morning and thanks for reaching back I'm trying to integrate Stripe to the app now and I'm doing it by making customers database table to our database, which only includes users who have subscribed to our service via stripe.
Oli - Kinde
Oli - Kinde11mo ago
Sounds like a good approach. Our initial Billing feature v1 will handle plans e.g. $5/month, $10/month, etc...
I'm trying to integrate Stripe to the app now and I'm doing it by making customers database table to our database, which only includes users who have subscribed to our service via stripe.
We will handle syncing your user data with Stripe in our Billing feature.
ooi cat
ooi catOP11mo ago
Yup. Definitely switching to billing when it comes. Comes is a wrong word, it doesn't come, it has to be made Thank you Oli
Oli - Kinde
Oli - Kinde11mo ago
Pleasure
Want results from more Discord servers?
Add your server