Group sync with Zitadel #707

Open
opened 2025-11-20 05:16:18 -05:00 by saavagebueno · 7 comments
Owner

Originally created by @sisumara on GitHub (Mar 15, 2024).

Describe the problem

I've been trying to configure self-hosted Netbird with Zitadel as IDP to use user roles which I've created under the Netbird project in Zitadel, but without any success. I've tried to use the claims as it is described in Zitadel's manual, but without any success. I've tried to use these claims:

  • urn:zitadel:iam:org:projects:roles
  • urn:zitadel:iam:org:project:{projectid}:roles
  • urn:zitadel:iam:org:project🆔{projectid}:aud

To Reproduce

Steps to reproduce the behavior:

  1. Create user roles in Zitadel under Netbird's project.
  2. Add described claims to Settiings -> Groups -> Enable JWT group sync -> JWT Claim
  3. Get error in management logs: JWT claim "urn:zitadel:iam:org:projects:roles" not found

Expected behavior

I expect to get user Roles from Zitadel to assign different groups in Netbird.

Are you using NetBird Cloud?

Self-host NetBird's control plane.

NetBird version

0.26.3

Screenshots
Screenshot 2024-03-15 at 8 54 39 AM
Screenshot 2024-03-15 at 8 56 08 AM
Screenshot 2024-03-15 at 8 55 54 AM

Originally created by @sisumara on GitHub (Mar 15, 2024). **Describe the problem** I've been trying to configure self-hosted Netbird with Zitadel as IDP to use user roles which I've created under the Netbird project in Zitadel, but without any success. I've tried to use the claims as it is described in Zitadel's manual, but without any success. I've tried to use these claims: - urn:zitadel:iam:org:projects:roles - urn:zitadel:iam:org:project:{projectid}:roles - urn:zitadel:iam:org:project:id:{projectid}:aud **To Reproduce** Steps to reproduce the behavior: 1. Create user roles in Zitadel under Netbird's project. 2. Add described claims to Settiings -> Groups -> Enable JWT group sync -> JWT Claim 3. Get error in management logs: JWT claim "urn:zitadel:iam:org:projects:roles" not found **Expected behavior** I expect to get user Roles from Zitadel to assign different groups in Netbird. **Are you using NetBird Cloud?** Self-host NetBird's control plane. **NetBird version** `0.26.3` **Screenshots** <img width="1728" alt="Screenshot 2024-03-15 at 8 54 39 AM" src="https://github.com/netbirdio/netbird/assets/61536902/b6179cdc-562d-41ae-ae88-cc4ab2f5b427"> <img width="1026" alt="Screenshot 2024-03-15 at 8 56 08 AM" src="https://github.com/netbirdio/netbird/assets/61536902/11b2b366-6236-49a7-bc45-707abf3aa139"> <img width="1026" alt="Screenshot 2024-03-15 at 8 55 54 AM" src="https://github.com/netbirdio/netbird/assets/61536902/6347bee4-9727-4fab-b085-f4aacbb994a6">
saavagebueno added the questionidpzitadelself-hosting labels 2025-11-20 05:16:18 -05:00
Author
Owner

@mlsmaycon commented on GitHub (Mar 17, 2024):

hello @sisumara, it seems like the claim is not the correct one. To discover the correct claim, please open your browser's development tools, and get one request to the management API, e.g., /api/users, there you will find an authentication header with a Bearer token, which you can copy and paste into the https://jwt.io/ website, then you will see the claims parsed in the payload view. Choose the one that maps to the roles.

@mlsmaycon commented on GitHub (Mar 17, 2024): hello @sisumara, it seems like the claim is not the correct one. To discover the correct claim, please open your browser's development tools, and get one request to the management API, e.g., /api/users, there you will find an authentication header with a Bearer token, which you can copy and paste into the https://jwt.io/ website, then you will see the claims parsed in the payload view. Choose the one that maps to the roles.
Author
Owner

@sisumara commented on GitHub (Mar 17, 2024):

hello @sisumara, it seems like the claim is not the correct one. To discover the correct claim, please open your browser's development tools, and get one request to the management API, e.g., /api/users, there you will find an authentication header with a Bearer token, which you can copy and paste into the https://jwt.io/ website, then you will see the claims parsed in the payload view. Choose the one that maps to the roles.

I've tried that approach, but this the only one Bearer token which I've found in there and there is no any mentions about groups. Here is how it looks like:

Screenshot 2024-03-17 at 11 12 18 AM

What am I doing wrong?

@sisumara commented on GitHub (Mar 17, 2024): > hello @sisumara, it seems like the claim is not the correct one. To discover the correct claim, please open your browser's development tools, and get one request to the management API, e.g., /api/users, there you will find an authentication header with a Bearer token, which you can copy and paste into the https://jwt.io/ website, then you will see the claims parsed in the payload view. Choose the one that maps to the roles. I've tried that approach, but this the only one Bearer token which I've found in there and there is no any mentions about groups. Here is how it looks like: <img width="622" alt="Screenshot 2024-03-17 at 11 12 18 AM" src="https://github.com/netbirdio/netbird/assets/61536902/58341ea1-8031-4385-b2dd-0b39d669d06b"> What am I doing wrong?
Author
Owner

@sisumara commented on GitHub (Mar 18, 2024):

I've found that Zitadel includes information about the roles if you enable "Assert Roles on Authentication" option in Project settings.
Screenshot 2024-03-17 at 9 10 41 PM

Then the token includes information about user roles like this:

"urn:zitadel:iam:org:project:256448444641310477:roles": {
    "netbird-admin": {
      "356409606912278797": "my-idp-domain"
    },
    "netbird-user": {
      "356409606912278797": "my-idp-domain"
    }
  },
  "urn:zitadel:iam:org:project:roles": {
    "netbird-admin": {
      "356409606912278797": "my-idp-domain"
    },
    "netbird-user": {
      "356409606912278797": "my-idp-domain"
    }
  }
}

But when I try to add the claim urn:zitadel:iam:org:project:256448444641310477:roles or urn:zitadel:iam:org:project:roles to the dashboard I see this error in log - DEBG management/server/account.go:1677: JWT claim "urn:zitadel:iam:org:project:roles" is not a string array

@sisumara commented on GitHub (Mar 18, 2024): I've found that Zitadel includes information about the roles if you enable "Assert Roles on Authentication" option in Project settings. <img width="727" alt="Screenshot 2024-03-17 at 9 10 41 PM" src="https://github.com/netbirdio/netbird/assets/61536902/25cae4a7-6344-4908-92ca-8232aa186a2b"> Then the token includes information about user roles like this: ``` "urn:zitadel:iam:org:project:256448444641310477:roles": { "netbird-admin": { "356409606912278797": "my-idp-domain" }, "netbird-user": { "356409606912278797": "my-idp-domain" } }, "urn:zitadel:iam:org:project:roles": { "netbird-admin": { "356409606912278797": "my-idp-domain" }, "netbird-user": { "356409606912278797": "my-idp-domain" } } } ``` But when I try to add the claim ```urn:zitadel:iam:org:project:256448444641310477:roles``` or ```urn:zitadel:iam:org:project:roles``` to the dashboard I see this error in log - DEBG management/server/account.go:1677: JWT claim "urn:zitadel:iam:org:project:roles" is not a string array
Author
Owner

@chris-si commented on GitHub (Mar 29, 2024):

Hi,

I'm also having trouble syncing the groups via JWT. The claims exist in the access token like @sisumara already described but NetBird somehow cannot read them correctly.

With the claim urn:zitadel:iam:org:project:<netBirdProjectId>:roles which exists inside the access token, I also get the following error with NetBird v0.26.6:
DEBG management/server/account.go:1721: JWT claim "urn:zitadel:iam:org:project:<netBirdProjectId>:roles" is not a string array

@chris-si commented on GitHub (Mar 29, 2024): Hi, I'm also having trouble syncing the groups via JWT. The claims exist in the access token like @sisumara already described but NetBird somehow cannot read them correctly. With the claim `urn:zitadel:iam:org:project:<netBirdProjectId>:roles` which exists inside the access token, I also get the following error with NetBird `v0.26.6`: `DEBG management/server/account.go:1721: JWT claim "urn:zitadel:iam:org:project:<netBirdProjectId>:roles" is not a string array`
Author
Owner

@1ndef1n1te commented on GitHub (Jul 24, 2024):

Hello @sisumara @chris-si , u can do the following steps for configure IdP(Zitadel) auto-groups with Netbird:

Zitadel configuration:

  1. Netbird need list of groups for auto-group working when zitadel default claims return objects, because of that u need to create custom action in Zitadel with following content:
function flatRoles(ctx, api) {
  if (ctx.v1.user.grants == undefined || ctx.v1.user.grants.count == 0) {
    return;
  }

  let grants = [];
  ctx.v1.user.grants.grants.forEach(claim => {
    claim.roles.forEach(role => {
        grants.push(role)  
    })
  })

  api.v1.claims.setClaim('groups', grants)
}

Select Flow: Complement token, Triggers: Pre Userinfo creation, Pre access token creation
Note that name of action need to be the same like function in this action
2) Create Role in Zitadel: Project -> Netbird project -> Roles -> + New
3) Go to the Authorizations -> Select user -> Select Netbird project and choose the correct roles for the user

Netbird configuration

  1. Go to the Settings -> Groups -> Enable JWT group sync and JWT claim should be the same like in action (In this example groups)

After that configuration users should sync roles with Zitadel. but we still fight with SYNCING because in our setup Netbird only add groups from IdP but not delete groups when when delete it in IdP, could u @mlsmaycon help me with this problem?

UPDATE: our problem seems to be solved

@1ndef1n1te commented on GitHub (Jul 24, 2024): Hello @sisumara @chris-si , u can do the following steps for configure IdP(Zitadel) auto-groups with Netbird: ## Zitadel configuration: 1) Netbird need **list** of groups for auto-group working when zitadel default claims return **objects**, because of that u need to create custom action in Zitadel with following content: ```javascript function flatRoles(ctx, api) { if (ctx.v1.user.grants == undefined || ctx.v1.user.grants.count == 0) { return; } let grants = []; ctx.v1.user.grants.grants.forEach(claim => { claim.roles.forEach(role => { grants.push(role) }) }) api.v1.claims.setClaim('groups', grants) } ``` Select Flow: `Complement token`, Triggers: `Pre Userinfo creation`, `Pre access token creation` **Note that name of action need to be the same like function in this action** 2) Create Role in Zitadel: `Project` -> `Netbird project` -> `Roles` -> `+ New` 3) Go to the `Authorizations` -> `Select user` -> `Select Netbird project` and choose the correct roles for the user ## Netbird configuration 1) Go to the `Settings` -> `Groups` -> `Enable JWT group sync` and `JWT claim` should be the same like in action (In this example `groups`) After that configuration users should sync roles with Zitadel. but we still fight with SYNCING because in our setup Netbird only add groups from IdP but not delete groups when when delete it in IdP, could u @mlsmaycon help me with [this](https://github.com/netbirdio/netbird/issues/2322) problem? UPDATE: our problem seems to be solved
Author
Owner

@nazarewk commented on GitHub (Apr 23, 2025):

@sisumara @chris-si were you able to resolve your issues with the informations provided? Can we close this?

@nazarewk commented on GitHub (Apr 23, 2025): @sisumara @chris-si were you able to resolve your issues with the informations provided? Can we close this?
Author
Owner

@MichaelUray commented on GitHub (Jul 27, 2025):

To add the flatRoles function fixed it for me.
As JWT claim you have to set groups in Netbird.

This is how it looks in Zitadel:
Image

There is a similar description with more details from another project how to setup such an action:
https://doc.psono.com/admin/configuration/oidc-zitadel.html#zitadel

It probably would be a good idea to add this function in the quick start script.

@MichaelUray commented on GitHub (Jul 27, 2025): To add the `flatRoles` function fixed it for me. As JWT claim you have to set `groups` in Netbird. This is how it looks in Zitadel: <img width="1306" height="1168" alt="Image" src="https://github.com/user-attachments/assets/708f8bea-0243-4171-b1fe-104892b59fe1" /> There is a similar description with more details from another project how to setup such an action: https://doc.psono.com/admin/configuration/oidc-zitadel.html#zitadel It probably would be a good idea to add this function in the [quick start script](https://github.com/netbirdio/netbird/blob/main/infrastructure_files/getting-started-with-zitadel.sh).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: SVI/netbird#707