re-using ID Token as a source of third party attested user-claims

Issue #1415 open
Kristina Yasuda created an issue

There have been multiple use-cases where ID Token is considered to be used as a mechanism to transport user claims across domains. In other words, RP1 who received an ID Token from IdP1 is reusing it as a source of user claims at RP2.

Yes, as you might already be thinking ID Token as-is cannot be used in this manner. Which is why the implementations considering such use are exploring following extensions.

Assuming that for an artifact to be able to transport user claims across domains, the following three pieces of information need to be included:

  1. claims about the user
  2. information about the user’s control over the private key, that the user can use to prove possession when presenting ID Token to a third party (RP2)
  3. a signature over the above information by an entity (IdP1) that is trusted by the third party receiving an artifact (RP2)

1 and 3 are already in the ID Token. The question becomes how to includes 2.

  • One suggestion might be for an IdP to issue a signed JWT from the userInfo endpoint that includes the user’s (RP1’s)
    public key in a "cnf" claim. RP1 can prove possession of this JWT by signing it over with a private key tied to the public key in cnf claim. (this one is not exactly re-using ID Token)
  • Another is to sign a nonce generated by a RP1 with a private key of the user. This nonce will be opaque to IdP1, but RP2 will be able to verify it using user’s public key passed in the PoP alongside ID Token.

To answer an inevitable question on the use-cases.

  • One use-case is user directly proving her identity to the application using ID Token from the IdP, when the IdP does not want to be involved in the process to avoid knowing when the user is using the app (confirming if I can quote concrete company name).
  • Another use-case is issuance of Verifiable Credentials, where the user wants to present an ID Token from IdP1 to the Issuer as an input information to the VC that is issued. Ideally you would want to use another VC as such an input, but in reality, there are much more ID Token being issued than VCs, so using ID Tokens for such purpose makes more sense.

Yes, as some of you might be thinking, this brings ID Token very close to the functionality Verifiable Credentials have.

Comments (37)

  1. Michael Jones

    Having a signed JWT with user claims that the RP can present to others seems to be a recurring pattern lately. Others can decide to trust the claims because they are signed by the original issuer. Others can trust that the claims are about me because the JWT is proof-of-possession bound to a key that I control (an action that must be performed by the issuer at my request).

    Whether the signed JWT is an ID Token or a signed UserInfo response is just a protocol choice detail.

  2. Giuseppe De Marco

    The flow that Kristina described brilliantly, and which I thank for doing so, considers that the id_token is forwarded through the user agent.

    This, if I’m not mistaken, can be done with auth code flow and with Implicit flow, so as to transport the id_token through the browser (with id_token_hint).

    We may consider that the id_token would be involved in another kind of flow, which does not compete strictly the purpose of this list dedicated to OIDC, such as a flow of Token Exchange (rfc8693) where as subject_token we MAY use the id_token relative to the user and as actor_token the access token relative to the RP. Being the STS endpoint a protected endpoint (for example with private_key_jwt) the receiving part can check the proof of possession by checking that the private_key_jwt sub and the client_id contained in the access_token (actor_token) are identical, and that the jwk used for the private_key_jwt signature is related to the sub/client_id being validated. This is proof that the RP is the actual owner of that access token and that id_token. The Token Exchange flow, for example, is a machine-to-machine (m2m) interaction that does not involve the user agent.

    Beyond the mode of the flow, of how we choose to transport the data if m2m or through the user-agent, I believe that the problem of the forwarding of a token, like of any information, to a third entity is the object of our analysis and the problem to focus on.

    An OP issues to a RP one or more tokens, by means of the user’s explicit consent, which is the subject of the data processing. The RP obtains tokens on behalf of the user.

    At a later time the RP sends the id_token to a third RS, without the consent of the user. This should not be possible, the RS itself should prevent the release of information of a subject without proof of his consent.

    If rather the RP sent the id_token along with a proof of the user’s consent for this release, this would be useful, but I can’t think of a safe method to get this without involving a trusted third party or a digital signature from the user (probably the wallets will help this kind of user interaction).

    For this reason I am considering Token Exchange, with access_token + id_token, with the requirement to get within the access token also the audience at the RS involved, as proof of consent by the user. In this case the consent is managed in a single moment, during the release page served by the OP. On this consent page page, the OP acquires the consent of the user to release an access_token that can be used by the RP at N RS. The RP using STS gives proof of possession to the RS, this latter takes the claims from the id_token, verify that the access_token has not expired (token introspection request to OP) and that it has a valid url/path/uid in aud claim, and this should stand still.

  3. Tom Jones

    sounds to me like a privacy nightmare - where is user consent and minimal disclosure supported.

    I suggest that is violates the principles of VC as well as the GDPR and CA privacy regulations.

  4. Giuseppe De Marco

    Tom did you reply to my post or generally on the topic?

    If it was for me, I can say that a more complex user consent management would implement the possibility, to the user, to manually select (UI checkboxes) the RS that he want to enable in the access token.

    The access token would be only enabled to do STS on the RS, that’s a protected endpoint (private_key_jwt). In this way the access_token won’t work as a bearer token but only as actor_token in a token exchange flow, the id_token would carry the user claims as subject_token.

    In this last post I’m talking about the difference between and simple consent (that only informs the user about what’s happening) and a complex consent, where the user can enable, by hand and with awareness, all the extra resources that a RP can be query. The result is to have extended aud (and scopes) in the access token to enable, later on, the token exchange for the allowed purposes

  5. Kristina Yasuda reporter

    User is asked for the consent to which information to share (including selective disclosure) in both flows - when the ID Token is obtained and when it is re-used. I have seen prototypes. it is not a privacy nightmare any more than other flows.

  6. Tom Jones

    How, exactly, would any consent query distinguish between the data that was required for the transaction when the ID token carries information that is not required? And what would happen when the user wanted to allow some, but not all, of the data in the ID token to be forwarded?

  7. Kristina Yasuda reporter

    How would any consent query distinguish between the data that was required for the transaction when the ID token carries information that is not required?

    In the use-cases I am familiar with, ID Token with re-use in mind, so the information in the ID Token matches to the information requested during the re-use. so no need to distinguish, there are two separate consents, they are just aligned in scope.

    what would happen when the user wanted to allow some, but not all, of the data in the ID token to be forwarded?

    That transaction would fail.

  8. Tom Jones

    So here we get to an issue that is bugging me.

    In core or in federation, should we describe any uses that are not shared by all users of the spec?

    What i have seen is that later nitpickers come along and ask for details of an issue that are unique to their interests.

    The result is that the “standard” is no longer generally applicable. Torston does this all the time saying “my customer want to do this.”

    Now i have an issue with the definition of trust mark that causes me to recommend that a reference to OIDC federation be removed.

    Is that what OIDF wants to see happen? Just because one user wants to do something, that is not a reason to inflict it on everyone.

  9. Giuseppe De Marco

    I am extremely grateful to you for the questions and contributions with which you are enriching the inspiration I have wished to share. Here some base assumptions:

    1. The user is completely unaware about tokens and protocols. The user is informed about the personal information that would be release to the RP and RS.
    2. I didn't tell you that, by default in our use case, the id_token won't contains any user attributes. The claims paramenter in the authz request MAY enable some of them in the id_token, explicitly.
    3. This hypothetical Attribute Authority profile with many RSs would enable, if the consent of the user cover the RSs, a unique identifier of the user that MUST be included in the requested claims of the id_token, upon which the RS can apply its lookup upoun its internal definitions. If this is missing in the RP's request, the OP would exclude RSs in the consent page and also it doesn't extends aud and scopes in the access token released
    4. yes, if any required attribute by RS is absent the transaction would fail with an explicit message (during the validation in STS endpoint)
    5. We MAY define which claims the RS requires. For the public services the tax payer's identification number or better a unique opaque value of this, would be the best choice.
    6. Considering Private RP, that don't belong to any public service, well, the RS MUST, in addition, send a notification to the user's digital delivery box.

    regarding 5 and 6 keep in mind that by default:

    a) id_token wouldn't have any user claims in it
    b) id_token MUST be explicitly requested in the claims parameter of the authz
    c) the user is informed of which of his attributes will be allowed to be released to the RS, considering only those required in the id_token
    d) each RS, during the onboarding phase regulated by a federation authority responsible for the control, must define which attributes it needs and obviously these must not exceed its purposes

    having said that, without prejudice to any possible element of weakness on which we are reasoning, the weakness of this design we can identify is in the evidence that, if an RS requires claims A,B and C and another RS requires only A ... well the latter will receive more of the necessary claims.

    This latter issue is covered by the user’s conscious consent BUT must be considered as a weakness of this solution.
    There would be remedies to alleviate this problem but I feel the risk of inflating too much this thread!

  10. Giuseppe De Marco

    I left the last incomplete message and hours later I submitted it, then I read your speech @Tom Jones .
    I’m really mortified, I was keen to talk about a use case with the sole intention of listening to you

  11. Tom Jones

    not to worry - please.

    I admit to taking a strong case for the user and the user’s choice. I worry that passing a token meant for one rp to another rp is problematic.

    Here is the way i approach such cases (that is where i suspect you are coming from - If i am mistake, please feel free to disabuse me.)

    I have created a series of use cases which are linked below. In each case, one RP will create a packet of some sort that will be passed to another or to an authorization end point where a policy decision is being made. I prefer that these tokens or tickets as they are sometime called are either just a credential to be giving to the user’s wallet, or are highly specific authorization access tokens. Reusing an ID token for another purpose seems wrong to me.

    https://kantarainitiative.org/confluence/display/PEMCP/Credential+Aggregation

    https://kantarainitiative.org/confluence/display/PEMCP/Generic+Presentation+Exchange

    https://kantarainitiative.org/confluence/display/PEMCP/Biometric+Pre+Check

  12. Giuseppe De Marco

    Thank you first of all,

    the proposal to remove the weakness of the passage of user attributes within the id_token would see:

    1. the OP that releases an id_token with no user attributes inside it
    2. an STS endpoint exposed by OP
    3. a chain of STS such that the RS in turn makes STS at the OP and gets an access token for the consumption of userinfo endpoint

    The set of attributes that an OP must issue on behalf of the user and on the basis of the consent previously collected would be

    a) exposed to the user in the consent page, for each RS for ehich the user make selective disclosure
    b) arbitrarily defined during onboarding in the federation of the RS or ... It is not a joke, based on the claim attribute within a trust mark

  13. Tom Jones

    While that solutions removes my objection from a UX perspective, it seems that the resultant JWS may be syntactically an ID Token, semantically it is not.

  14. Giuseppe De Marco

    Following the elements I acquired from this thread https://bitbucket.org/openid/connect/issues/1395/usage-of-id_token_hint-in-oidccore and without further delay, I have received all the elements necessary to reach the clear conclusion that id tokens should not be understood as an object of exchange to third parties

    @tom I think I answered you summarily before, anyway a possible exchange flow, to date, I would think only using access_tokens with appropriate purposes and audience, including the STS Chain that I hypothesized

  15. Kristina Yasuda reporter

    @Giuseppe De Marco There is a difference between these two issues, and for a reason.

    #1395 (id_token_hint) talks about using ID Tokens as being issued right now to be used to re-authenticate the user at the same OP that issued it. (used as credential as defined in OIDC)

    #1415 (this one) talks about adding some elements to the ID Token so that it can be re-used as a source of claims at another OP2 than the OP1 that issued it. (used more like credential as defined in vc-data-model).

    I agree ID Tokens as being issued right now should not be passed to the third parties, hence this issue. I just don’t think comments for #1395 automatically apply for this issue too

  16. Giuseppe De Marco

    I understand and I start from your position @Kristina Yasuda , however the answers of Vittorio and Brian seemed so clear and peremptory that I came to the conclusion that in addition to id_token_hint also Token Exchange is not to be considered a mode of sending to third parties an id_token.

    So I’d consider that a Token exchange implementation with id_token may be removed from the purpose of this issue and we should start over on the scope of id_token in relation of SIOP needs

    Unless someone had other ideas for forwarding id_token within traditional infrastructure (not SSI oriented), and with arguments strong enough to counterbalance what Brian told us, that would be interesting

  17. Tom Jones

    quite frankly sending an ID token between sites sounds to me exactly like the user tracking problem that the cross-origin limitations are designed to prevent. AFAIK according to the GDPR any such transfer of user data requires the the user be informed and consent to the involvement of any data controller. Also that would apply to vc’s as well.

  18. Giuseppe De Marco

    the user Will be Always informed and he Always have to give his consent, that's covered by my use case

  19. Brian Campbell

    was discussed some during the call https://lists.openid.net/pipermail/openid-specs-ab/2022-January/008827.html

    John said that the wielder would need some kind of proof-of-possession mechanism
    John asked whether this should even be called an ID Token
    Brian said that this would be a misuse, requiring ignoring RFC-level REQUIRED security validation actions
    He thought that having a different token intended for this purpose would be far better
    David said that the thing we're talking about feels more like a Verifiable Credential
    Kristina said that there are far more issuers of ID Tokens than VCs at this point
    John said that what you want is some kind of federated access token - not an ID Token

  20. Giuseppe De Marco

    @Brian Campbell

    @Brian Campbell

    from the bottom of my experience I have always felt advantageous to divide tokens for purposes,

    access_token has as its subject the RP
    id_token has as its subject the user

    I do not believe that including the user’s claims in the token that has as its subject the RP can be an appropriate solution. Mine is a mere design reasoning, we know for sure that the proposal of having user claims in the access_token "could work".

    Rather I wonder what potential id_token could have, especially in the context of SIOP, and what instead we would like to prevent, by design, at the expense of its evolution as a token carrying information about a user (even anonymous!).

  21. Torsten Lodderstedt

    I agree with David. The proposed solution to me seems to turn an ID Token into a Verifiable Credential by introducing the holder binding to the ID Token. That allows replay detection in cases where the RP wants to present the ID Token someplace (without the protection provided by “aud” and “nonce”). That’s just an observation, no assessment.

    I’m not sure how the use cases presented differ from the OP (as OAuth AS) issuing (audience restricted and sender constrained) access token to be used someplace (one or more RSs).

  22. Michael Jones
    • changed status to open

    This was discussed on the 31-Jan-22 working group call. The working group felt that the discussion has been valuable. Given that no one expressed support for reusing ID Tokens in the manner described, and that the issue proposes no changes to any specifications, we proposed closing the issue in another week unless reasons are raised to leave it open.

  23. Kristina Yasuda reporter

    Given that no one expressed support for reusing ID Tokens in the manner described

    I don’t think that is entirely true. I think the outcome of the discussion is “ID Token as-is cannot be used in that way. When holder binding is introduced, it could be“.

    , and that the issue proposes no changes to any specifications.

    Not exactly, what the issue proposed is defining additional mechanisms that could enable “reuse“ of ID Token.

  24. Giuseppe De Marco

    I think we could overcome all the critical issues that emerged during this thread by applying a different logic.

    The purpose was to use the id_token as an attribute claim that could be used for various purposes. The constraint is to adhere to good practices which do not allow a RP to send a token to third parties and for other purposes.

    Well, I would like to ask if you were aware of any standard that defines how tokens can be embed, of various kinds (the header[typ]) within a JWT.

    In this case we could transport a list of embedded tokens inside the id_token. I can’t and I don’t want to use the term "nested" because nested token means JWE(JWS) and currently I can’t think of anything other than "embedded" that doesn’t sound fancy at all.

    However, a RP, identifying a specific claim, would get a list of tokens minted for other purposes than the id_token, and owned by a RP on behalf of a resource owner.

    Example:

    {
                "sub": "<https://that-s.ub",>
                "nonce": "that-nonce",
                "at_hash": left_hash(jwt_at, "HS256"),
                "c_hash": left_hash(authz.auth_code, "HS256"),
                "aud": "https///that-audien.ce",
                "iss": iss_sub
                "jti": uuid.uuid4(),
                "exp": exp_from_now(),
                "iat": iat_now()
    
                # here the embedded tokens in an array
                "ejwt": [ .... ]
    }
    

    Creativity aside, do you think it’s something worth working on?
    It’s nothing strictly required for oidc-core but more in a general specs for oauth2 that then may be then used in all the oidc ecosystem.

  25. Giuseppe De Marco

    my previous proposal can also be considered in relation to how we adopted trust marks, precisely as an arrqy of json objects, within which the claim trust_mark contains a signed JWT

    I seem to understand that in the ecosystem oauth2 to date lacks a specification on how to transport so many JWT within a single

  26. Jeremie Miller Account Deactivated

    What use cases does this approach address that cannot be accomplished with OIDC4VP/VCI?

  27. Giuseppe De Marco

    These embedded tokens will be issued by the OPs on the basis of the consent given by the user, for the attribute authorities that the RP may use on behalf of the user and in its stead.

    These tokens, transported in a JWT type Token (excluding access_token that may be not a JWT, the choice falls on id_token), would be encrypted with the public of the AA for which they are intended, with aud and scope ad hoc.

    These tokens would be used exclusively on the AA Token Exchange endpoint. In this way, the AA would obtain proof of both the identity of the resource owner (through the claims contained in these tokens, according to the principle of data manimization for each audience) and of the RP that uses it.

  28. Tobias Looker

    I agree with Jeremie here, an identity assertion that features a pop binding to the relying party is essentially what is being defined as a credential in OIDC4VCI, we shouldn’t define two ways to do this.

  29. Giuseppe De Marco

    It sounds good indeed, thank you

    We never used a VC/VP to a Token Exchange Endpoint (STS).
    In our requirements we need a client authentication of the RP, the Token/VP alone is not enough to consumes the RS API, and also we need also that the VC would be encrypted with the public key of the RS.

    the trust between RP, OP and RS is being made with OIDC Federation and in a VC or a VP is not a problem, using a https:// url in the issuer claim (we would avoid a did resolution and a ledger)

    the presentation would be sumbitted to the STS in JWE format.

    the missing piece is that we don’t have a scheme to add in the presentation the ACR value of the authentication made by the user.

  30. Kai Lehmann

    The use cases described here looks similar to what we want to achieve: We have an OP (OP1) managing an account for an End-User. A client wants verified credentials of the End-User. OP1 only possesses verified email and phone number, but unverified data for the rest. The client may now invoke a provider which supports End-User identification services including storing the verified data in a Wallet for later re-use Let’s call this provider OP2. In order to have a complete verified set in the Wallet, the client first queries OP1 for the verified email/phone using standard OIDC protocol and passes this along to OP2. The ID Token seems a nice fit here as it can be verified by OP2 and it does not require OP1 to implement any VC/VP specifics.

    That said, it requires OP2 to retrieve the key material from OP1 to verify the ID Token. Also OP2 may alternatively take the role of an RP towards OP1 and request verified email/phone information which does have the benefit of involving the End-User giving consent to releasing the data to OP2. This requires OP2 to register as RP at OP1, though, which can be a problem whenever a RP decides to integrate a new OP.

  31. Giuseppe De Marco

    I agree with you Kai, but I assume that:

    1. I have no guarantees that the user’s claims are in the id token, they should be there but problably not, or a minimum set, or all or nothing
    2. The ID Token was issued for a specific audience and it’s not intended for interop, ideally the id token should not go out from the RP that has received it

    We have the userinfo endpoint and this latter give anytime the updated user claims. The userinfo response may be encrypted also with the RP’s public key and this represent a good strategy to mitigate the steal of access tokens. Even if the AT would be stolen the userinfo response is only readable by the RP that’s the owner of the AT. so, a sort of PoP of the AT reflected in the response of the protected resource.

    With these assumptions I see more interesting passing the AT between RP1 and RP2. RP2 should exchange the AT on the OP2 STS endpoint and obtain its AT and with this reach the userinfo endpoint.

    Another assumption is that the id token should be issued after a traditional OIDC user authentication, while this process doesn’t represent any user authentication but an interop flow that allow RP2 to create a local user session with the proof of the identity of the user, binded to the user-agent that issued the SSO request.

    So the RP2 should have the proof that the user-agent, binded to the RP1 asks/allows the login on RP2 and also the RP1 before passing the token … I have to work for a while on the native sso profile to explore the bounduaries and all the possibilities I might have. Thank you for sharing Kai!

  32. Kai Lehmann

    Re your item 1: I assume you mean that even if the RP requested the ID token to include specific information (i.e. via claims parameter {"id_token":{"email": {"essential": true},…}} ), the OP may issue an ID token without that data?

    In regards to transporting the information from RP1 to RP2 (or OP2), I also agree that it is not the intended purpose of the ID token as of the current specification. Token Exchange would be a reasonable approach, although it must be supported by OP1, and OP2/RP2 must still be registered at OP1 to access the userinfo endpoint or receive an ID token which is including the necessary data and proper audience.

  33. Log in to comment