Google Workspace IdP not setting email addresses properly #433

Closed
opened 2025-11-20 05:11:17 -05:00 by saavagebueno · 7 comments
Owner

Originally created by @marcbudofsky on GitHub (Aug 30, 2023).

Describe the problem
With a clean install of v0.22.7 and leveraging Google Workspace as the IdP, users are only showing ID's with no email attribute set. Based on #959, NETBIRD_MGMT_IDP="none" has been defined in setup.env to fix the Invalid JWT issue. I'm assuming the lack of email addresses is a side effect.

To Reproduce
Steps to reproduce the behavior:

  1. Pull latest https://github.com/netbirdio/netbird.git
  2. Copy infrastructure_files/setup.env.template to infrastructure_files/setup.env (overwrite existing file from old version)
  3. Fill in correct values as identified in the Google Workspace setup guide: https://docs.netbird.io/selfhosted/identity-providers#google-workspace
  4. Re-run ./configure.sh
  5. Run docker compose pull && docker compose down && docker compose up -d

Expected behavior
Email addresses are set in Netbird when a user entry is created.

Screenshots
users
user-details

Additional context
Setting NETBIRD_MGMT_IDP="google" caused an Invalid JWT error and rendered Netbird unusable.

Originally created by @marcbudofsky on GitHub (Aug 30, 2023). **Describe the problem** With a clean install of v0.22.7 and leveraging Google Workspace as the IdP, users are only showing ID's with no email attribute set. Based on #959, `NETBIRD_MGMT_IDP="none"` has been defined in setup.env to fix the Invalid JWT issue. I'm assuming the lack of email addresses is a side effect. **To Reproduce** Steps to reproduce the behavior: 1. Pull latest https://github.com/netbirdio/netbird.git 2. Copy infrastructure_files/setup.env.template to infrastructure_files/setup.env (overwrite existing file from old version) 3. Fill in correct values as identified in the Google Workspace setup guide: https://docs.netbird.io/selfhosted/identity-providers#google-workspace 4. Re-run ./configure.sh 5. Run docker compose pull && docker compose down && docker compose up -d **Expected behavior** Email addresses are set in Netbird when a user entry is created. **Screenshots** ![users](https://github.com/netbirdio/netbird/assets/104649/6fb0e4c1-f7ef-4523-b2f0-b077f3835c78) ![user-details](https://github.com/netbirdio/netbird/assets/104649/92d097c4-b3c5-4cfe-8fed-d3e4fad0ee08) **Additional context** Setting `NETBIRD_MGMT_IDP="google"` caused an Invalid JWT error and rendered Netbird unusable.
Author
Owner

@mosi0815 commented on GitHub (Sep 2, 2023):

I just found the problem that makes the Google IDP unusable. On the first login with a new user, Netbird tries to set the wt_account_id attribute in the users app_metadata custom schema.
This fails because of an invalid metadata payload in the update query. It contains an additional field that Netbird didn't add to the custom schema beforehand.
I'm neither a GO expert nor very familiar with the Netbird codebase but I got it working by changing the AppMetadata struct in idp.go like this:

type AppMetadata struct {
        // WTAccountID is a NetBird (previously Wiretrustee) account id to update in the IDP
        // maps to wt_account_id when json.marshal
        WTAccountID     string `json:"wt_account_id,omitempty"`
        WTPendingInvite *bool  `json:"wt_pending_invite,omitempty"`
        WTInvitedBy     string `json:"wt_invited_by_email,omitempty"`
}

Google needs a couple of seconds to update the metadata. So the invalid JWT error still appears after the first login but after a refresh of the page a couple of seconds later everything works as expected.

@mosi0815 commented on GitHub (Sep 2, 2023): I just found the problem that makes the Google IDP unusable. On the first login with a new user, Netbird tries to set the wt_account_id attribute in the users app_metadata custom schema. This fails because of an invalid metadata payload in the update query. It contains an additional field that Netbird didn't add to the custom schema beforehand. I'm neither a GO expert nor very familiar with the Netbird codebase but I got it working by changing the AppMetadata struct in idp.go like this: ```go type AppMetadata struct { // WTAccountID is a NetBird (previously Wiretrustee) account id to update in the IDP // maps to wt_account_id when json.marshal WTAccountID string `json:"wt_account_id,omitempty"` WTPendingInvite *bool `json:"wt_pending_invite,omitempty"` WTInvitedBy string `json:"wt_invited_by_email,omitempty"` } ``` Google needs a couple of seconds to update the metadata. So the invalid JWT error still appears after the first login but after a refresh of the page a couple of seconds later everything works as expected.
Author
Owner

@mosi0815 commented on GitHub (Sep 2, 2023):

Update:
I found a workaround without modifying the code.
Adding a custom text field wt_invited_by_email to the app_metadata custom attribute in the admin console also fixes the problem.

@mosi0815 commented on GitHub (Sep 2, 2023): Update: I found a workaround without modifying the code. Adding a custom text field wt_invited_by_email to the app_metadata custom attribute in the admin console also fixes the problem.
Author
Owner

@braginini commented on GitHub (Sep 3, 2023):

Update: I found a workaround without modifying the code. Adding a custom text field wt_invited_by_email to the app_metadata custom attribute in the admin console also fixes the problem.

Hey @mosi0815
Did you it in the Google IDP admin console?

We could also create a PR modifying the AppMetadata to omit empty values as you did in the code.

https://github.com/netbirdio/netbird/pull/1122

@braginini commented on GitHub (Sep 3, 2023): > Update: I found a workaround without modifying the code. Adding a custom text field wt_invited_by_email to the app_metadata custom attribute in the admin console also fixes the problem. Hey @mosi0815 Did you it in the Google IDP admin console? We could also create a PR modifying the AppMetadata to omit empty values as you did in the code. https://github.com/netbirdio/netbird/pull/1122
Author
Owner

@moserpjm commented on GitHub (Sep 4, 2023):

I manually added it via the Google Workspace Admin Console:
image

I think the root cause of this bug is that the Google Workspace integration doesn't add all the required fields.

@moserpjm commented on GitHub (Sep 4, 2023): I manually added it via the Google Workspace Admin Console: ![image](https://github.com/netbirdio/netbird/assets/137904805/8cddd7fa-8f4b-4141-b260-5b114a342a5f) I think the root cause of this bug is that the Google Workspace integration doesn't add all the required fields.
Author
Owner

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

I am closing without much digging into it, because https://github.com/netbirdio/netbird/pull/1147 probably fixed the issue.

@nazarewk commented on GitHub (Apr 17, 2025): I am closing without much digging into it, because https://github.com/netbirdio/netbird/pull/1147 probably fixed the issue.
Author
Owner

@xrehpicx commented on GitHub (May 28, 2025):

Hosted latest version as of rn and still getting this issue

@xrehpicx commented on GitHub (May 28, 2025): Hosted latest version as of rn and still getting this issue
Author
Owner

@moserpjm commented on GitHub (May 28, 2025):

Don't stress yourself with the Google integration. The whole custom field solution is less than ideal. Install Zitadel or Keycloak and configure Google there. If you want to control access globally you can do it there. In case you want to use your Google Groups its gets a litte bit more difficult. Google is not sending a group claim. If you Google this you will find feature requests from 15 Years ago. They dont watn to do it because its a completely different API which is rather slow.
For Keycloak theres a plugin. Its rather old but works. Uses the Workspace Directory API. So you have to delegate an actual Admin to the service user. It doesnt resolve nested groups btw. Theres no API Method for it and they didn't implement it theirself.
I case of Zitadel its a littel bit more tricky. You can use an Action to Complement your token. It only supports plain Javascript Actions. So calling the new CloudIdentity API to retrieve all groups of a user recursivly is possible but you would have to do it 100% manually. Oauth everything.
So we ended up with a solution lke that.

Image

Thats your IDE BTW :D:

Image

A Spring Boot App with the whole stack of Google API libs gets the email of the user and returns a JSON array with all groups which get added as claim by the JS. We also added a little bit of cache because those API calls can take 5 seconds or more. Sounds complicated but its actually 30 lines of code. Calling HTTP endpoints from actions is only possible on localhost BTW. All other host require a valid SSL certificate. So no calls to anoter Container or a host in your local network without certificate mayhem. But hey if it works you finally get OAuth groups for all your apps not only Netbird. Like EntraID in the free edition :D

@moserpjm commented on GitHub (May 28, 2025): Don't stress yourself with the Google integration. The whole custom field solution is less than ideal. Install Zitadel or Keycloak and configure Google there. If you want to control access globally you can do it there. In case you want to use your Google Groups its gets a litte bit more difficult. Google is not sending a group claim. If you Google this you will find feature requests from 15 Years ago. They dont watn to do it because its a completely different API which is rather slow. For Keycloak theres a plugin. Its rather old but works. Uses the Workspace Directory API. So you have to delegate an actual Admin to the service user. It doesnt resolve nested groups btw. Theres no API Method for it and they didn't implement it theirself. I case of Zitadel its a littel bit more tricky. You can use an Action to Complement your token. It only supports plain Javascript Actions. So calling the new CloudIdentity API to retrieve all groups of a user recursivly is possible but you would have to do it 100% manually. Oauth everything. So we ended up with a solution lke that. ![Image](https://github.com/user-attachments/assets/8d489f7c-ea2c-4036-b063-6e46c528ce13) Thats your IDE BTW :D: ![Image](https://github.com/user-attachments/assets/4d1ab762-174e-4d3c-98ed-4b8450c760cf) A Spring Boot App with the whole stack of Google API libs gets the email of the user and returns a JSON array with all groups which get added as claim by the JS. We also added a little bit of cache because those API calls can take 5 seconds or more. Sounds complicated but its actually 30 lines of code. Calling HTTP endpoints from actions is only possible on localhost BTW. All other host require a valid SSL certificate. So no calls to anoter Container or a host in your local network without certificate mayhem. But hey if it works you finally get OAuth groups for all your apps not only Netbird. Like EntraID in the free edition :D
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: SVI/netbird#433