Device Auth Token requested Org ID not enforced
Hi All,
I recently was testing out Device Auth Token on the latest stable Zitadel (v4) and followed the normal instructions for setting up a Device Auth Project.
When I perform the portion of the user authorizing the Device on their account, I use the scope:
urn:zitadel:iam:org:id:{id}
Regardless of the user's membership (e.g. they aren't part of the organization id specified), the access token is returned and when querying user_info endpoint with that token, the organization id is listed.
I believe this is a bug because the user shouldn't have been issued an access token when they failed the urn:zitadel:iam:org:id:{id} scope assertion? Or atleast that I wouldn't expect that id to be present on the user_info since they aren't a part of the organization.10 Replies
Hi @Dawn, I'm an AI assistant for ZITADEL. While a team member reviews this question, I'll see if I can find relevant sources for your question.
Answer
I wasn't able to find a direct answer, here are some relevant sources:
1. [OpenID Connect Endpoints in ZITADEL] (1) :
Describes how scopes are processed and how tokens are issued, but does not specify enforcement for organization membership in the context of device authorization.
2. [User authentication using zitadel end points] (2) :
Discusses scope usage and token validation, but does not clarify behavior when a user is not a member of the requested organization.
To learn more, see the sources I considered:
[1] OpenID Connect Endpoints in ZITADEL
[2] User authentication using zitadel end points
Feel free to tag @Ask Inkeep with additional questions.
hey @Dawn
The behavior you're describing with the flow is expected and by design, not a bug.
The scope
urn:zitadel:iam:org:id:{orgID}is not an "enforcement" . It’s a "claim selector" (I jjst came up with that word but feel free to lmk of this doesnt makes sense :D), it tells zitadel which org to embed into the token/userinfo, assuming the user has at least one membership somewhere.
The token itself does not restrict access to org resources. It's up to your application logic to enforce these restrictions.@Rajat I guess I’m confused by the saying “assuming the user has at least one membership somewhere”. Does that mean that membership does not need to be in that particular organization that I’m requesting and can be “any organization”?
e.g I can request for Organization A and have organization A embedded in the token/userinfo, even when I don’t have membership in Organization A?
Because that’s the behavior I’m seeing (which begs the question of why have the claim if it’s always embedded, regardless of membership)
I’m even further confused by this from Zitadel docs:
“When requesting this scope ZITADEL will enforce that the user is a member of the selected organization. If the organization does not exist a failure is displayed. It will assert the urn:zitadel:iam:user:resourceowner claims.”
I’m observing that the user does not need to be a member of the selected organization.
hey @Dawn good morning, apologies for my bad wordings but you are right, basically you’re seeing tokens issued even without membership from what I understood, correct?.
are you self hosted or remote?
this could be a bug 🐛
I’m self hosted, but yes I’m seeing tokens issued when there isn’t membership in the organization that I’m requesting the scope for (if that makes sense).
I tested last night outside of Device Code Auth and see similar behavior on then PKCE flow. I can grab you an exact version number in a couple minutes.
I'm current using the image:
ghcr.io/zitadel/zitadel:v4.0.0I observe this too on v4.1.4
What's the pathway towards submitting a bug report and getting this fixed in a release? I'd do it, but I don't have a firm grasp on how the scopes that are custom are processed in Zitadel code-wise (yet)
I guess if this doesn't work either - what is the expected behavior?
Like when we say "will enforce that the user is a member of the selected organization." is that exclusively through resource ownership (the organization owns the user) or can it also be asserted when a user is a member of a project of the organization?
hey @Dawn you can file an issue here and as for "the scopes that are custom are processed in Zitadel code-wise" well, custom scopes are not yet present in zitadel. You can read about scopes here.
this enforcement is based on the user being a member of the org,which means, the user is owned by (belongs to) that org.
@Rajat I assume I’d want to use the “project roles” scope to assert otherwise?
I just meant that I don’t fully understand how the Zitadel specific scopes (not standard OAuth scope) are processed code-wise in Zitadel yet. Didn’t mean to pre-empt any discussion about custom scopes yet 🙂
hey @Dawn zitadel scopes (like
urn:zitadel:iam:org:id:{id}) give you more control over what info is shared in the tokens.
When you ask for these scopes, zitadel checks if you're allowed to get that info.If allowed, zitadel puts extra info in your token.
That is an easy understanding of scopes and how they work in zitadel