OIDC Hybrid flow: Not return user's claims in the tokens from Authorization response

31 views
Skip to first unread message

Marek Posolda

unread,
May 17, 2021, 6:45:10 AM5/17/21
to Keycloak Dev
FAPI Advanced specification uses the concept of ID Token used as
"detached signature" [1]. This is for security purposes to makes sure
that authorization response is consistent and it is not possible to
inject individual parameters (EG. code) and replace them with attacker's
values. Some example security concern is in the FAPI specs [2] and in
the OpenID Connect core as well.

The main usage here is to make sure that ID Token returned in the
"Authorization response" is used as a signature with claims like s_hash,
c_hash, nonce. But it is not used as "source of identity" . My
understanding is, that for retrieve user identity claims, client is
supposed to exchange code and return the ID Token from the authorization
response, which is supposed to contain the user's claims
(preferred_username, email, given_name etc). Especially the FAPI
advanced specification has this sentence to especially prohibit of
return user's data in the ID Token from Authorization Response in point
6 of section 5.2.2.1: should not return sensitive PII in the ID Token in
the authorization response, but if it needs to, then it should encrypt
the ID Token.

So far, for hybrid flows, we return all the user's claims in the ID
Token and access token in the OIDC authorization response. I propose
that we stop returning the user's claims in the ID Token and Access
Token from authorization response in case of hybrid flow. In other
words, we won't call the protocolMappers when tokens are built during
authorization response. This won't apply for Implicit flow as that one
does not have additional token request/response and hence it would still
need to have all the user's claims in the tokens of authorization response.

If we go this path, do we need a switch, which will still allow to
return user's claims in the authorization response tokens in hybrid
flow? I suppose that we can add backwards compatibility switch for this
like "Return claims in the Authorization response token". It will be
false by default and it would be visible just if both "Standard flow"
and "Implicit flow" switches are enabled for the client (That is
requirement to have hybrid flow enabled).

WDYT?

[1]
https://openid.net/specs/openid-financial-api-part-2-1_0.html#id-token-as-detached-signature-1
[2]
https://openid.net/specs/openid-financial-api-part-2-1_0.html#authorization-response-parameter-injection-attack

Marek

Pedro Igor Craveiro e Silva

unread,
May 17, 2021, 8:23:42 AM5/17/21
to Marek Posolda, Keycloak Dev
I'm not sure if we should change the current behavior because OIDC core does not define the same conditions as FAPI. Also, ID token as a detached signature is somewhat described here https://openid.net/specs/openid-connect-core-1_0.html#TokenSubstitution

We should expect to return either all claims (from authz endpoint and token endpoint) in ID Token or just a sub-set of them from authz endpoint. See https://openid.net/specs/openid-connect-core-1_0.html#HybridIDToken2. I think the current behavior is OK and should not change.

As expected, FAPI is concerned about adding more security layers on top of OIDC, so I would agree that introducing this additional switch makes sense. At the same time, wouldn't be just a matter of configuring mappers to not include specific claims into the ID Token? Perhaps we are missing here an "Include in ID Token when Frontchannel"  setting in mappers?

It should also be useful outside banking too ...

--
You received this message because you are subscribed to the Google Groups "Keycloak Dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to keycloak-dev...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/keycloak-dev/07c61b24-3700-bf8b-79ef-e30395f61ef3%40redhat.com.

Marek Posolda

unread,
May 17, 2021, 11:06:42 AM5/17/21
to Pedro Igor Craveiro e Silva, Keycloak Dev
Yes, so it is a question if we should have switch at the client-level or at the level of individual protocol mappers as you pointed. Maybe it depends what is the granularity:
1) We need protocol mappers granularity if you need just subset of the user's claims returned in the authorization response ID Token. For example just "preferred_username" and "given_name" will be returned from authorization endpoint, but "email" won't be returned.
2) We need client's level if it is ok to return either all of user's claims or none of them

TBH it seems to me that it is sufficient to have "all-or-none" granularity (option 2) for the ID Token returned from Authorization endpoint (obviously with the exception of metadata claims like iss, *_hash, nonce etc). I am not seeing much use-case for return only subset of user's claims. So to me it looks as slightly better option to have the option on client level.

About the default option, I am slightly for NOT add the stuff by default to the ID Token from Authorization endpoint as it is safer option and I vote for have safer option by default :) But if you prefer, we can add it by default as long as we have the option to skip it for the purpose of FAPI.

Regarding the default, my thinking is like: Who are the typical users who use hybrid flow? If they need to use ID Token with user's claims included, then they probably don't use TokenEndpoint at all, but just stick to implicit flow. But since they use hybrid flow instead of implicit flow, they likely plan to exchange code for proper ID Token from the token endpoints? Hence maybe they likely already use ID Token returned from Authorization endpoint mostly for "Detached signature" (verifying of signature and claims like c_hash, nonce etc) rather than for "check user claims" purpose? But maybe I am wrong here :)

Marek

Pedro Igor Craveiro e Silva

unread,
May 17, 2021, 12:39:51 PM5/17/21
to Marek Posolda, Keycloak Dev
On Mon, May 17, 2021 at 12:06 PM Marek Posolda <mpos...@redhat.com> wrote:
Yes, so it is a question if we should have switch at the client-level or at the level of individual protocol mappers as you pointed. Maybe it depends what is the granularity:
1) We need protocol mappers granularity if you need just subset of the user's claims returned in the authorization response ID Token. For example just "preferred_username" and "given_name" will be returned from authorization endpoint, but "email" won't be returned.
2) We need client's level if it is ok to return either all of user's claims or none of them 

TBH it seems to me that it is sufficient to have "all-or-none" granularity (option 2) for the ID Token returned from Authorization endpoint (obviously with the exception of metadata claims like iss, *_hash, nonce etc). I am not seeing much use-case for return only subset of user's claims. So to me it looks as slightly better option to have the option on client level. 

I'm not sure either. But as you said, on the mapper you have more granularity and you are not opinionated about what claims should be in or out. It is up to you to decide. Looks like more aligned with the idea behind mappers.

Also, for some use cases, even the `preferred_username` could have some ephemeral (not only add/remove logic). I think the specs mention this use case.
 

About the default option, I am slightly for NOT add the stuff by default to the ID Token from Authorization endpoint as it is safer option and I vote for have safer option by default :) But if you prefer, we can add it by default as long as we have the option to skip it for the purpose of FAPI.

Not sure if safer. IMO, this is use case-specific. Consider an "enterprise" use case where information about the subject is not so sensitive. This is very different than doing FAPI where 3rd parties (e.g.: TPPs) are involved. And you do have very hard privacy/security requirements around it.
 

Regarding the default, my thinking is like: Who are the typical users who use hybrid flow? If they need to use ID Token with user's claims included, then they probably don't use TokenEndpoint at all, but just stick to implicit flow.

Not necessarily. You might return an ID and AT, and both might have only a subset of information due to the nature of hybrid flow. And then the app can get a more complete version of both tokens if necessary using the code.

It is use case specific, I believe. We can not assume anything.

One thing though that makes sense is the idea to restrict the claims that are added to tokens when doing front channel (either #1 or #2). But is Hybrid widely used (see my next comment)?
 
But since they use hybrid flow instead of implicit flow, they likely plan to exchange code for proper ID Token from the token endpoints? Hence maybe they likely already use ID Token returned from Authorization endpoint mostly for "Detached signature" (verifying of signature and claims like c_hash, nonce etc) rather than for "check user claims" purpose? But maybe I am wrong here :)

I don't know why you would want Hybrid because it is basically implicit + code. And considering implicit is kind of deprecated (omitted from OAuth 2.1), is Hybrid still recommended? I mean, looks like the specs are pushing against using the front channel for returning tokens, and favoring authorization code for SPAs and mobile.

If you think about it, PKCE kind of solves the problem with `c_hash` too?

Marek Posolda

unread,
May 18, 2021, 4:43:46 AM5/18/21
to Pedro Igor Craveiro e Silva, Keycloak Dev
On 17. 05. 21 18:39, Pedro Igor Craveiro e Silva wrote:


On Mon, May 17, 2021 at 12:06 PM Marek Posolda <mpos...@redhat.com> wrote:
Yes, so it is a question if we should have switch at the client-level or at the level of individual protocol mappers as you pointed. Maybe it depends what is the granularity:
1) We need protocol mappers granularity if you need just subset of the user's claims returned in the authorization response ID Token. For example just "preferred_username" and "given_name" will be returned from authorization endpoint, but "email" won't be returned.
2) We need client's level if it is ok to return either all of user's claims or none of them 

TBH it seems to me that it is sufficient to have "all-or-none" granularity (option 2) for the ID Token returned from Authorization endpoint (obviously with the exception of metadata claims like iss, *_hash, nonce etc). I am not seeing much use-case for return only subset of user's claims. So to me it looks as slightly better option to have the option on client level. 

I'm not sure either. But as you said, on the mapper you have more granularity and you are not opinionated about what claims should be in or out. It is up to you to decide. Looks like more aligned with the idea behind mappers.

Also, for some use cases, even the `preferred_username` could have some ephemeral (not only add/remove logic). I think the specs mention this use case.

Thanks, TBH I still prefer the client switch.

There is another limitation related to mappers. The most of the mappers are added to clients through the client scopes (We still have ability to define protocol mappers directly on the client, but it is not a preferred option). So mappers for user's claims are added through the OIDC mappers like "profile", "email" etc. In case you want for FAPI client to not return the claims in the Authorization Endpoint ID Token, but for some other non-FAPI client with hybrid flow, you would want to return the claims, you won't be able to re-use the mappers. As for FAPI client, you would want "Return in Authz Endpoint token" OFF, but for other client ON. You will need to either define mappers on the client or define new client scope, but then it won't be standard OIDC client scope "profile" etc...

 

About the default option, I am slightly for NOT add the stuff by default to the ID Token from Authorization endpoint as it is safer option and I vote for have safer option by default :) But if you prefer, we can add it by default as long as we have the option to skip it for the purpose of FAPI.

Not sure if safer. IMO, this is use case-specific. Consider an "enterprise" use case where information about the subject is not so sensitive. This is very different than doing FAPI where 3rd parties (e.g.: TPPs) are involved. And you do have very hard privacy/security requirements around it.
 

Regarding the default, my thinking is like: Who are the typical users who use hybrid flow? If they need to use ID Token with user's claims included, then they probably don't use TokenEndpoint at all, but just stick to implicit flow.

Not necessarily. You might return an ID and AT, and both might have only a subset of information due to the nature of hybrid flow. And then the app can get a more complete version of both tokens if necessary using the code.

It is use case specific, I believe. We can not assume anything.

One thing though that makes sense is the idea to restrict the claims that are added to tokens when doing front channel (either #1 or #2). But is Hybrid widely used (see my next comment)?
 
But since they use hybrid flow instead of implicit flow, they likely plan to exchange code for proper ID Token from the token endpoints? Hence maybe they likely already use ID Token returned from Authorization endpoint mostly for "Detached signature" (verifying of signature and claims like c_hash, nonce etc) rather than for "check user claims" purpose? But maybe I am wrong here :)

I don't know why you would want Hybrid because it is basically implicit + code. And considering implicit is kind of deprecated (omitted from OAuth 2.1), is Hybrid still recommended? I mean, looks like the specs are pushing against using the front channel for returning tokens, and favoring authorization code for SPAs and mobile.

If you think about it, PKCE kind of solves the problem with `c_hash` too?

Yes, exactly. Hybrid is in fact "implicit + code". But since you have "code", then you probably don't need implicit tokens for user identity purpose, but rather for "detached signature" . As you pointed, maybe I am just doing assumptions and it may not be great to assume usage. But still, I don't see much other value of hybrid flow besides "detached signature"... Use-case with the application using both ID Tokens from Authz-endpoint and Token-endpoint is something, which I would personally never use as it might likely cause more troubles than added value. But maybe I am wrong here..

Yes, PKCE is another way of protection.

Marek

Reply all
Reply to author
Forward
0 new messages