OIDC returns empty namespace if id_token doesn't contain email #357

Closed
opened 2025-12-29 01:27:35 +01:00 by adam · 9 comments
Owner

Originally created by @oplik0 on GitHub (Oct 22, 2022).

Bug description

If the OpenID Connect provider doesn't return user email in id_token returned from the token endpoint Headscale doesn't even error out - instead it just creates an empty namespace. Ideally userinfo endpoint would be used to supplement lacking data. I'd however prefer at least failing the registration to the current hard to debug behaviour.

To Reproduce

  • use OIDC provider that doesn't return email in id_token even with email scope
  • register a new device
  • it's successfully registered under a namespace with an empty string as a name

Example reproduction in OCI (free account has access to everything required for this):

  • go to Identity>Federations>OracleIdentityCloudService and go to the IDCS console from the link listed there
  • create a new application with the Confidential Application type
  • after giving it some name configure it as a client with Authorization Code enabled under allowed grant types, headscale callback URL in the Redirect URL field and add Me under Grant the client access to Identity Cloud Service Admin APIs
  • Get the client id and secret into Headscale config
  • Configure your base admin URL as the issuer under Security>Oauth (by default Oracle has a mismatch between issuer and endpoints that headscale doesn't handle but I think this is just how oidc-go works and there is this fix on Oracle side of things). Also use it as the issuer in headscale configuration
  • Try logging in to a tailscale client and see it succeed as an empty user

Context info

The only provider I've seen do this is Oracle Cloud - they seem to return everything correctly to the callback with response_type id_token but not under token endpoint where they ignore everything that could be added from scopes and delegate it to userinfo.

I see that there is already code for utilizing userinfo that is just commented out (ecce82d44a/oidc.go (L161-L166)) - with my understanding being that it was unclear at what point it would be best to use it (presumably with the assumption that it just expanded the information about the user beyond the essentials). But as can be seen here sometimes even the essentials hide there. I think at least attempting to use it in case any of the fields are empty in id_token would be a reasonable idea.

Originally created by @oplik0 on GitHub (Oct 22, 2022). <!-- Headscale is a multinational community across the globe. Our common language is English. Please consider raising the bug report in this language. --> **Bug description** If the OpenID Connect provider doesn't return user email in `id_token` returned from the token endpoint Headscale doesn't even error out - instead it just creates an empty namespace. Ideally userinfo endpoint would be used to supplement lacking data. I'd however prefer at least failing the registration to the current hard to debug behaviour. **To Reproduce** - use OIDC provider that doesn't return email in id_token even with `email` scope - register a new device - it's successfully registered under a namespace with an empty string as a name Example reproduction in OCI (free account has access to everything required for this): - go to Identity>Federations>OracleIdentityCloudService and go to the IDCS console from the link listed there - create a new application with the `Confidential Application` type - after giving it some name configure it as a client with Authorization Code enabled under allowed grant types, headscale callback URL in the` Redirect URL` field and add `Me` under `Grant the client access to Identity Cloud Service Admin APIs` - Get the client id and secret into Headscale config - Configure your base admin URL as the issuer under Security>Oauth (by default Oracle has a mismatch between issuer and endpoints that headscale doesn't handle but I think this is just how oidc-go works and there is this fix on Oracle side of things). Also use it as the issuer in headscale configuration - Try logging in to a tailscale client and see it succeed as an empty user **Context info** The only provider I've seen do this is Oracle Cloud - they seem to return everything correctly to the callback with `response_type id_token` but not under `token` endpoint where they ignore everything that could be added from scopes and delegate it to userinfo. I see that there is already code for utilizing userinfo that is just commented out (https://github.com/juanfont/headscale/blob/ecce82d44a4510d233bda21f70334c49f3877c3e/oidc.go#L161-L166) - with my understanding being that it was unclear at what point it would be best to use it (presumably with the assumption that it just expanded the information about the user beyond the essentials). But as can be seen here sometimes even the essentials hide there. I think at least attempting to use it in case any of the fields are empty in id_token would be a reasonable idea.
adam added the stalebug labels 2025-12-29 01:27:35 +01:00
adam closed this issue 2025-12-29 01:27:36 +01:00
Author
Owner

@kradalby commented on GitHub (Apr 19, 2023):

I will close this as it might have been fixed in newer version, please try a new release and reopen if it still does not work.

@kradalby commented on GitHub (Apr 19, 2023): I will close this as it might have been fixed in newer version, please try a new release and reopen if it still does not work.
Author
Owner

@github-actions[bot] commented on GitHub (Oct 18, 2023):

This issue is stale because it has been open for 180 days with no activity.

@github-actions[bot] commented on GitHub (Oct 18, 2023): This issue is stale because it has been open for 180 days with no activity.
Author
Owner

@fredrikekre commented on GitHub (Oct 20, 2023):

I just ran in to this so I don't think it is fixed. I used 0.22.3 though, but it looks like the relevant code hasn't changed as compared to current main branch. I think it comes down to: fb4ed95ff6/hscontrol/oidc.go (L581-L584) where there is no check if the resulting username is empty. Perhaps the empty email should be caught earlier though, perhaps when extracting the claims in fb4ed95ff6/hscontrol/oidc.go (L356) ? I am happy to attempt a PR with the option maintaners like best. It was pretty confusing to end up with an empty user.

@fredrikekre commented on GitHub (Oct 20, 2023): I just ran in to this so I don't think it is fixed. I used 0.22.3 though, but it looks like the relevant code hasn't changed as compared to current main branch. I think it comes down to: https://github.com/juanfont/headscale/blob/fb4ed95ff63b96249bef5c8070daac07f0e52016/hscontrol/oidc.go#L581-L584 where there is no check if the resulting username is empty. Perhaps the empty email should be caught earlier though, perhaps when extracting the claims in https://github.com/juanfont/headscale/blob/fb4ed95ff63b96249bef5c8070daac07f0e52016/hscontrol/oidc.go#L356 ? I am happy to attempt a PR with the option maintaners like best. It was pretty confusing to end up with an empty user.
Author
Owner

@kc2idb commented on GitHub (Oct 28, 2023):

I am also experiencing the same bug.

@kc2idb commented on GitHub (Oct 28, 2023): I am also experiencing the same bug.
Author
Owner

@github-actions[bot] commented on GitHub (Jan 27, 2024):

This issue is stale because it has been open for 90 days with no activity.

@github-actions[bot] commented on GitHub (Jan 27, 2024): This issue is stale because it has been open for 90 days with no activity.
Author
Owner

@github-actions[bot] commented on GitHub (Feb 4, 2024):

This issue was closed because it has been inactive for 14 days since being marked as stale.

@github-actions[bot] commented on GitHub (Feb 4, 2024): This issue was closed because it has been inactive for 14 days since being marked as stale.
Author
Owner

@fredrikekre commented on GitHub (Feb 4, 2024):

I believe this is still an issue judging by the code I linked above (which hasnt changed AFAICT).

@fredrikekre commented on GitHub (Feb 4, 2024): I believe this is still an issue judging by the code I linked above (which hasnt changed AFAICT).
Author
Owner

@KristofferC commented on GitHub (Feb 4, 2024):

If a bug is reported and there has been no activity then presumably the bug report is still valid so how could automatically closing based on inactivity ever make sense..?

@KristofferC commented on GitHub (Feb 4, 2024): If a bug is reported and there has been no activity then presumably the bug report is still valid so how could automatically closing based on inactivity ever make sense..?
Author
Owner

@almereyda commented on GitHub (Feb 4, 2024):

As a side note, because you were asking when this would ever be useful, I think it makes sense in heavy traffic issue trackers, where actual issues will resurface, when previous instances were already closed. This also encourages active participation in an issue, because it else times out without it, and prevents a fire-and-forget mentality, where issues are just left for the maintainers to solve. Closing inactive issues makes sure that the open ones always have an active case in which the documented regression appears.

@almereyda commented on GitHub (Feb 4, 2024): As a side note, because you were asking when this would _ever_ be useful, I think it makes sense in heavy traffic issue trackers, where actual issues will resurface, when previous instances were already closed. This also encourages active participation in an issue, because it else times out without it, and prevents a fire-and-forget mentality, where issues are just left for the maintainers to solve. Closing inactive issues makes sure that the open ones always have an active case in which the documented regression appears.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/headscale#357