Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scopes and claims request parity in CredentialRequestOptions ? #154

Closed
hpsin opened this issue Nov 23, 2021 · 6 comments
Closed

Scopes and claims request parity in CredentialRequestOptions ? #154

hpsin opened this issue Nov 23, 2021 · 6 comments

Comments

@hpsin
Copy link

hpsin commented Nov 23, 2021

Applications can request additional claims in their ID token using the "claims request" pattern in OIDC. This allows for runtime customization of the ID token. Requesting scopes also allows the app to indicate whether or not they need additional standard claims like the email address, phone number, address, or additional tracking elements.

Scopes and claims requests don't appear to fit into the FedCM API, but would be good for apps looking to request least access, or customize their runtime behavior.

Would the credential request options be the place for that?

https://www.connect2id.com/products/server/docs/guides/requesting-openid-claims#claims-parameter

@dj2
Copy link
Collaborator

dj2 commented Nov 23, 2021

We're in the process of updating the API which splits the return of the id_token out of get and into a fetchTokens method. See the fetchTokens section of #145.

My plan was that the FetchTokenOptions could be extended to have different tokens values and a future scopes. The trick with scopes we need to sort out is, how do we present them to the user in a safe and useful way. I think we have to consider the RP untrustworth to explain the scopes they're asking for, so we need the IDP to explain the scopes to us.

The rough, unverified plan in my head was to add a space separated scopes entry into FetchTokenOptions. We'd also add a scopes_endpoint to the .well-known/fedcm file. Now, either scopes_endpoint would take a list of scopes to return, or just return all scopes, haven't thought that part through yet (although, thinking now I think it has to return all and receive no parameters. If we pass the scopes we're opening a data channel from RP -> IDP so I could ask for a scope which is my user_id or some other tracker). But, it's an un-credentialed request which returns scope data:

{
   "email": "Users email address",
   "cal": "Users calendar"
}

On the FedCM side, we'd verify all of the requested scopes are present in the list, display a popup to the user listing the scopes and their descriptions and, if the user consents, run the fetchTokens with the provided scopes. If all the requested scopes aren't present we'd either halt the request completely, or drop the unknown scopes from the request (probably with a console error?) I'm guessing to begin the former is the better path forward and just halt fetchTokens and reject the promise. We could loosen the restriction in the future.

From a UX perspective, should the user be able to turn off individual scopes in the id_token request? Could I say, no you can't have my email but you can read my calendar? If we don't allow that, will the RP be forced to do several serial requests for each of the pieces of information to allow the user to choose?

This all needs a bunch of thinking, spec an implementation work. If you see any glaring holes in the idea though, please let me know.

@dj2
Copy link
Collaborator

dj2 commented Nov 23, 2021

The other question is, does the browser need to verify what's returned? If I ask for the claim of email and the IDP also returns address, does the browser need to detect that? Do we have to restrict what's in the id_token to the set of claims requested by the user. If we don't, the IDP could be providing a lot more user data to the RP then the user has consented.

If we do inspec the token, that means that the id_token can't be encrypted, as we wouldn't be able to inspect it.

If the id_token has unknown claims, do we reject the fetchTokens promise outright as invalid claims?

@hpsin
Copy link
Author

hpsin commented Dec 1, 2021

I would not feel comfortable having a by-design uncredentialed API that allows enumeration of customer created content (PrivateAPI.FooBars.read) - I don't think this would pass our GDPR review or security review.

we'd verify all of the requested scopes are present in the list

Not all scopes can be shown to all users. It will be damaging to ask a consumer user for permission to access their directory, for instance - they do not have one. Moreover, not all apps exist in all tenants, so we'll get into a weird spot of showing consent for things that the user isn't allowed to know about due to client misconfigurations.

we're opening a data channel from RP -> IDP

Will you be the arbiter of api://MyClientIdIs12345AndUserIsFromContoso.read being an acceptable scope name? If not, this is a data channel where the app can pack in a good amount of data that may not be too scary in the consent dialog.

From a UX perspective, should the user be able to turn off individual scopes in the id_token request?

This has the potential to break apps that aren't prepared for this. AAD doesn't offer this today, but Google does, and Facebook does in a limited way. This would certainly break our auth SDK cache. It's also not clear what you're protecting against - do you want a signal to the IdP of what to allow or not? Or are you preventing collusion between IdP and app? If the latter, can't work, but if the former, maybe it could be useful. It would break a lot of apps that just don't function if you don't grant access though.

If you see any glaring holes in the idea though, please let me know.

One core issue is dynamic consent - the idea that you don't need to ask for everything up front. I think Fed CM would support this via repeat invocations, so just calling this out to keep in mind.

If the id_token has unknown claims, do we reject the fetchTokens promise outright as invalid claims?

This just killed so many real privacy features and forced apps to go outside of your vision :)
If you lock ID tokens down to what you consider appropriate, the odds that truly useful information is being pushed out is high. So let's say I want to know what groups the user is a part of. Or if their data residency is in a certain country for legal reasons that I must abide by. Because Chromium doesn't know that "schremsDataLocation" or "groups" is a valid claim in the token, I can't implement that feature until we... get Chromium to approve and ship an update to approved claims in the ID token? That'll go over... poorly with my legal team and many others I imagine.

Here's an incomplete listing of what we put in an ID token, most of which are "optional" released under the profile claim. If I can't put things in the ID token to help apps get their work done correctly, then I'm forced to issue access tokens instead, where the browser can't see anything that's been provided.

@dj2
Copy link
Collaborator

dj2 commented Dec 1, 2021

I would not feel comfortable having a by-design uncredentialed API that allows enumeration of customer created content (PrivateAPI.FooBars.read) - I don't think this would pass our GDPR review or security review.

With fetchTokens happening after the get where consent was granted, this could be a credentialed call as the user has already consented to the communication.

(Although, answering questions further down, we'd have to put more thought into the credentialed version of this. If it's credentialed, the IDP now knows all the scopes the RP wants for the user, so even if the user denied consent for some of them, the IDP could grant them anyway as we told the IDP which ones the RP wanted when getting the scope information. Doing the request uncredentialed would also have the same issue, just harder as it's a timing attack of the scope list being asked for, and then the token fetch and joining those two things in IP address.).

we'd verify all of the requested scopes are present in the list

Not all scopes can be shown to all users. It will be damaging to ask a consumer user for permission to access their directory, for instance - they do not have one. Moreover, not all apps exist in all tenants, so we'll get into a weird spot of showing consent for things that the user isn't allowed to know about due to client misconfigurations.

So, are you saying if the RP asks for scopes (a, b, c) you may not want to show any information for scope (b) to the user? Is it correct that this is an IDP decision which scopes are shown to the user?

To clarify my statement, I was thinking we'd verify the scopes requested by the RP are returned by the IDP. So, if the RP requested (a, b, c) and the IDP returned (a == calendar, c == email) and (b) was missing, we'd ... something? I was originally thinking we'd need to make sure the user is consented for all the scopes, but it sounds like that isn't the case. In that world, if we don't verify, and we just display the IDP returned entries, that would solve the problem of scopes that don't make sense. Need to put more thought into if this opens up privacy issues or not.

we're opening a data channel from RP -> IDP

Will you be the arbiter of api://MyClientIdIs12345AndUserIsFromContoso.read being an acceptable scope name? If not, this is a data channel where the app can pack in a good amount of data that may not be too scary in the consent dialog.

We won't be the arbiter, I just want to make it clear that this channel is opened. It didn't exist before (in the FedCM API) and can be used to send arbitrary data from RP -> IDP. We need to make sure that is included in the privacy section of the spec.

From a UX perspective, should the user be able to turn off individual scopes in the id_token request?

This has the potential to break apps that aren't prepared for this. AAD doesn't offer this today, but Google does, and Facebook does in a limited way. This would certainly break our auth SDK cache. It's also not clear what you're protecting against - do you want a signal to the IdP of what to allow or not? Or are you preventing collusion between IdP and app? If the latter, can't work, but if the former, maybe it could be useful. It would break a lot of apps that just don't function if you don't grant access though.

Yea, I was originally thinking this would be something like the user say "you can share my email, but not my calendar". I realize the consent forms I've seen in the wild are all or nothing, but wanted to pose the question of, is this a good idea? I think if we skipped this completely now, it could be added in the future, we'd just remove the scope from the requested list before sending to the IDP.

If you see any glaring holes in the idea though, please let me know.

One core issue is dynamic consent - the idea that you don't need to ask for everything up front. I think Fed CM would support this via repeat invocations, so just calling this out to keep in mind.

Yup, that was my thinking, you'd make subsequent fetchToken requests with different scopes required as needed.

If the id_token has unknown claims, do we reject the fetchTokens promise outright as invalid claims?

This just killed so many real privacy features and forced apps to go outside of your vision :) If you lock ID tokens down to what you consider appropriate, the odds that truly useful information is being pushed out is high. So let's say I want to know what groups the user is a part of. Or if their data residency is in a certain country for legal reasons that I must abide by. Because Chromium doesn't know that "schremsDataLocation" or "groups" is a valid claim in the token, I can't implement that feature until we... get Chromium to approve and ship an update to approved claims in the ID token? That'll go over... poorly with my legal team and many others I imagine.

Here's an incomplete listing of what we put in an ID token, most of which are "optional" released under the profile claim. If I can't put things in the ID token to help apps get their work done correctly, then I'm forced to issue access tokens instead, where the browser can't see anything that's been provided.

I thought the spec had text around inspecting the id_token, but I don't see it now. Its also been pointed out that this isn't possible if folks start encrypting the id_token. So, I think that means we'll have to treat all the tokens as opaque in to the UA (if we don't, that precludes encryption). This probably also needs to get recorded in the privacy section as the IDP can share anything to the RP in the token and we have no knowledge of it (and possibly the RP shaing to the IDP in the scopes contents).

This, I think, means FedCM is an API to allow the communication between the IDP and RP and controls how that communication happens but has no concept of what is being communicated. That probably also needs to get called out in the privacy part of the spec.

@hpsin
Copy link
Author

hpsin commented Dec 1, 2021

So, are you saying if the RP asks for scopes (a, b, c) you may not want to show any information for scope (b) to the user? Is it correct that this is an IDP decision which scopes are shown to the user?

To clarify my statement, I was thinking we'd verify the scopes requested by the RP are returned by the IDP. So, if the RP requested (a, b, c) and the IDP returned (a == calendar, c == email) and (b) was missing, we'd ... something? I was originally thinking we'd need to make sure the user is consented for all the scopes, but it sounds like that isn't the case. In that world, if we don't verify, and we just display the IDP returned entries, that would solve the problem of scopes that don't make sense. Need to put more thought into if this opens up privacy issues or not.

Yup, the owner of the resource (b may be owned by a third party who only wants their API to be called by people in their organization, let's say) and the IDP acting on their behalf. It is often standard for the app to also pre-register what APIs it may want to have access to, so it could pass in "give me my default scopes" and have the IDP look those up. So you can also have cases where they provide "b.default" and you get back a, b, c.

In general I'm not convinced this provides value to the user, the dev, or the IDP. If we decide suddenly that scope A also needs scope Q (it's happened), and so when we get a, b, c we return a, b, c, q, we should be allowed to do that to ensure that our legally important consent screen remains accurate.

Will you be the arbiter of api://MyClientIdIs12345AndUserIsFromContoso.read being an acceptable scope name? If not, this is a data channel where the app can pack in a good amount of data that may not be too scary in the consent dialog.

We won't be the arbiter, I just want to make it clear that this channel is opened. It didn't exist before (in the FedCM API) and can be used to send arbitrary data from RP -> IDP. We need to make sure that is included in the privacy section of the spec.

It already exists though in the original FedCM prompt - these two sites are going to talk to each other about you. Generic consent text seems fine, we do it too, but I don't think I grok the connection to the scopes then. Seems ok though at end of day so can drop it.

From a UX perspective, should the user be able to turn off individual scopes in the id_token request?

This has the potential to break apps that aren't prepared for this. AAD doesn't offer this today, but Google does, and Facebook does in a limited way. This would certainly break our auth SDK cache. It's also not clear what you're protecting against - do you want a signal to the IdP of what to allow or not? Or are you preventing collusion between IdP and app? If the latter, can't work, but if the former, maybe it could be useful. It would break a lot of apps that just don't function if you don't grant access though.

Yea, I was originally thinking this would be something like the user say "you can share my email, but not my calendar". I realize the consent forms I've seen in the wild are all or nothing, but wanted to pose the question of, is this a good idea? I think if we skipped this completely now, it could be added in the future, we'd just remove the scope from the requested list before sending to the IDP.

Yeah, seems like a nice thing an IDP could opt into. Google does this nicely - their consent documentation indicates that users can pick and choose. Microsoft, on the other hand, indicates that what you request is what you'll get back (or a failure), modulo certain in applicable scopes. If we were to coordinate with our SDKs, update our docs, and then set a flag to enable this in Fed CM, that would be nice.

This, I think, means FedCM is an API to allow the communication between the IDP and RP and controls how that communication happens but has no concept of what is being communicated. That probably also needs to get called out in the privacy part of the spec.

I think that's good from our perspective. There are flows that won't even return tokens, just an opaque authorization code, so having a hard dependency on tokens even being present would be hard.

@cbiesinger
Copy link
Collaborator

We think this is addressed by a combination of the parameters API (#556), continuation API (#555) and fields API (#559).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants