[Openid-specs-ab] OpenID Connect Key Binding vs OpenID Connect UserInfo Verifiable Credentials

Dick Hardt dick.hardt at gmail.com
Tue Sep 9 18:03:28 UTC 2025


> And then add new code for presentation of the id_token to RP2 using DPoP

why would this be DPoP?

This would be protocol specific between RP1 and RP2

On Tue, Sep 9, 2025 at 6:49 PM <george at practicalidentity.com> wrote:

>
>
> On Sep 9, 2025, at 12:54 PM, Dick Hardt <dick.hardt at gmail.com> wrote:
>
> I agree there is potential for RP1 to share info it should not share with
> RP2
>
> It is unclear that the extra complexity of asking for a new token is
> going to prevent that any better than an OP deciding it won't issue an
> id_token with key binding. IE the OP making a decision about what is in an
> id_token and not in another token seems complicated for most OPs.
>
>
> Maybe I’m missing the complexity. If the spec defines the claims of the
> new token, then it can limit the privacy implications of the issued tokens
> (e.g. the token contains ’iss’, ’sub’, ‘amr’, …). It doesn’t have to
> include email address or other PII claims as the receiving entity just
> wants proof of the user’s authentication status. In fact you might not even
> need ’sub’ and could potentially use a ’session id’ instead. Though this
> probably depends on the deployment requirements.
>
> More importantly to me, I am concerned about the lift to educate
> implementers about a new token and a new way to ask for it. I suspect the
> lack of interest in the OpenID Connect UserInfo Verifiable Credentials is
> due to the complexity.
>
>
> Won’t we need to communicate to implementors a new scope to pass as part
> of the authentication request? And then add new code for presentation of
> the id_token to RP2 using DPoP? We also need to communicate to the OPs the
> special logic they need to consider based on the PII claims being issued
> into the id_token as to whether it should add the ‘cnf’ claim or not?
>
>
> I also don't think we are overloading the id_token -- but we can agree to
> differ in our opinion on that.
>
> 👍 😀
>
>
>
>
> On Tue, Sep 9, 2025 at 1:51 PM <george at practicalidentity.com> wrote:
>
>> Hi Dick,
>>
>> Thanks for answering my question (again) :)
>>
>> I don’t feel like the argument of “the OP can’t prevent the RP from doing
>> X” is a viable one for specifications. The spec should
>> encourage/push/require the RP to “do the right thing”. I believe the
>> current model makes is easy for the RP to “do the WRONG thing”.
>>
>> Use cases where the id_token flows across trust boundaries make no sense.
>> The ’sub’ claim, in many cases, has no relevance in the second trust domain
>> as the identifier for the user is different (GUID in trust domain A does
>> NOT equal the user in trust domain B). This is why the identity chaining
>> spec leveraged the JSON Authorization Grant to allow the AS in trust domain
>> A to correctly identify the user in trust domain B.
>>
>> Also, trying to leverage user consent as a way to solve this is really a
>> “user experience dark pattern”. What the user is trying to do will NOT work
>> if they don’t consent. What if the RP requesting the id_token also needs to
>> know some personal health information and wants that in the id_token. Now
>> the user is sharing that data with whoever the RP decides? Or has to make
>> the choice between sharing or reduced functionality?
>>
>> I’m still confused why a dedicated token for authentication/status is not
>> a viable option? If the RP is a web based RP, then requesting this token
>> from the AS either during the authentication front channel flow, or via a
>> backchannel flow like ID-JAG shouldn’t be an issue. For me, just because
>> the RP is already getting the id_token doesn’t mean we should overload the
>> id_token semantic.
>>
>> Thanks,
>> George
>>
>> George Fletcher
>> Identity Standards Architect
>> Practical Identity LLC
>>
>>
>>
>> On Sep 9, 2025, at 1:16 AM, Dick Hardt <dick.hardt at gmail.com> wrote:
>>
>> Hi George
>>
>> My answer to your question:
>>
>> If RP1 requests claims that MUST NOT be sent to RP2, then what is the OP
>> supposed to do? Reject the request? Send back an id_token that is
>> insufficient for the client (RP1) but good for RP2? Send back an id_token
>> that works for both the client and RP2 which has leaked privacy claims?
>>
>>
>> Is that the OP can't prevent RP1 from sending whatever it wants to RP2.
>> If the OP does not trust RP1 to do the right thing, then perhaps the OP
>> should not issue an id_token to RP1?
>>
>> I have added the following content to the Privacy Considerations and
>> added you to the acknowledgements:
>>
>> > Public key bound ID Tokens will often contain personal (PII). The RP
>> SHOULD obtain user consent before sharing a Public key bound ID Token that
>> contains PII with a third party.
>>
>> On Tue, Sep 9, 2025 at 1:57 AM <george at practicalidentity.com> wrote:
>>
>>> Ok, let me restate. RP1 is an OpenID Connect Relying Party acting as an
>>> OAuth 2.0 client. This is exactly how OpenID Connect defines the Relying
>>> Party term.
>>>
>>> Relying Party (RP)OAuth 2.0 Client application requiring End-User
>>> Authentication and Claims from an OpenID Provider.
>>> The point is not what RP1 can or cannot do with data it receives. Just
>>> because RP1 CAN send the id_token to another party doesn’t mean is SHOULD.
>>> The point is to define a mechanism that maximizes the likelihood RP1 will
>>> “do the right thing”. Which from what I understand, is that RP1 needs to
>>> communicate information about the authentication status/context with
>>> another entity. This information needs to be authorized by the OP and MUST
>>> NOT leak PII about the subject that the receiving entity should not receive.
>>>
>>> Also, I didn’t see an answer to my question…
>>>
>>> If RP1 requests claims that MUST NOT be sent to RP2, then what is the OP
>>> supposed to do? Reject the request? Send back an id_token that is
>>> insufficient for the client (RP1) but good for RP2? Send back an id_token
>>> that works for both the client and RP2 which has leaked privacy claims?
>>>
>>>
>>> George Fletcher
>>> Identity Standards Architect
>>> Practical Identity LLC
>>>
>>>
>>>
>>> On Sep 8, 2025, at 7:27 AM, Dick Hardt <dick.hardt at gmail.com> wrote:
>>>
>>> > Finally, to Dick’s points about RP1 (really the OAuth client) sending
>>> it to RP2, I believe that creates a mutually exclusive decision for the OP.
>>> If the client requests claims that MUST NOT be sent to RP2, then what is
>>> the OP supposed to do? Reject the request? Send back an id_token that is
>>> insufficient for the client (RP1) but good for RP2? Send back an id_token
>>> that works for both the client and RP2 which has leaked privacy claims?
>>>
>>> RP1 is not an OAuth client -- it is an RP. It does not want
>>> authorization, it wants authentication. The OP cannot prevent RP1 from
>>> sending any information it wants to RP2 independent of it being in an
>>> id_token or in another part of the communication -- what RP1 shares with
>>> RP2 is going to be based on business decisions, not a technical barrier of
>>> it not being in an id_token.
>>>
>>> On Mon, Sep 8, 2025 at 12:17 PM <george at practicalidentity.com> wrote:
>>>
>>>> I’m going to  respond to a couple points from different emails here as
>>>> it’s easier to do it in one post :)
>>>>
>>>> Dick asked why I didn’t object to ID-JAG as the ‘aud’ rule isn’t
>>>> applied by the OP in that draft.
>>>>
>>>> For me, the reason is that back when we did OpenID Connect Core, there
>>>> was the issue of the id_token_hint parameter which meant sending the
>>>> id_token back to the issuer that issued it. We had the discussion at that
>>>> time and the way I remember it, we all agreed that it was ok for the
>>>> id_token to be sent back to its issuing OP. I believe Karl makes the same
>>>> point. I don’t see any privacy risks here either as the OP put all the
>>>> claims into the id_token.
>>>>
>>>> Now regarding the comment about the Native SSO spec, in that spec also,
>>>> the id_token is ONLY sent to the OP that issued it. Sending the id_token to
>>>> a different OP would be outside the intent of that spec. As for clients
>>>> written by the same company sharing the id_token, you could say that is an
>>>> abuse of the ’aud’ rules and in fact there has been push back against the
>>>> Native SSO spec for it’s use of the id_token.
>>>>
>>>> Regarding the Kubctl use of the id_token, I worked with my colleague at
>>>> Capital One to get this changed to using a JWT based access token as the
>>>> purpose of the token in the K8 use case was for authorization NOT
>>>> authentication context.
>>>>
>>>> Finally, to Dick’s points about RP1 (really the OAuth client) sending
>>>> it to RP2, I believe that creates a mutually exclusive decision for the OP.
>>>> If the client requests claims that MUST NOT be sent to RP2, then what is
>>>> the OP supposed to do? Reject the request? Send back an id_token that is
>>>> insufficient for the client (RP1) but good for RP2? Send back an id_token
>>>> that works for both the client and RP2 which has leaked privacy claims?
>>>>
>>>> I still believe the best path forward is a dedicated token for this
>>>> purpose. The ID-JAG model is fine, send the id_token back to the OP to
>>>> request an authentication assertion for RP2 and get back the token to
>>>> share. If there is concern that the OP then knows who the client is
>>>> communicating with, then make the authentication assertion usable for
>>>> everyone (though I daresay many enterprise IDPs would not want this
>>>> feature).
>>>>
>>>> Future responses today will be limited. I’ll check back this evening or
>>>> tomorrow morning :)
>>>>
>>>> George Fletcher
>>>> Identity Standards Architect
>>>> Practical Identity LLC
>>>>
>>>>
>>>>
>>>> On Sep 7, 2025, at 5:07 PM, Karl McGuinness <me at karlmcguinness.com>
>>>> wrote:
>>>>
>>>> There are several widely deployed infrastructure use cases that already
>>>> take an id_token as a bootstrap credential
>>>>
>>>>    -
>>>>    https://kubernetes.io/docs/reference/access-authn-authz/authentication/#openid-connect-tokens
>>>>    -
>>>>    https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithWebIdentity.html
>>>>    -
>>>>    https://cloud.google.com/iam/docs/workload-identity-federation-with-other-providers
>>>>
>>>> It's common for a CLI tool for example to to use something like device
>>>> authorization grant to obtain an id_token from an enterprise IdP end
>>>> exchange the the id_token for a backend session with a control plane.  In
>>>> fact Okta uses OpenID Native SSO
>>>> https://openid.net/specs/openid-connect-native-sso-1_0.html for its
>>>> AWS CLI implementation to SSO to different AWS Accounts. These use cases
>>>> are attempting to use the ID Token similar to a X.509 as would benefit from
>>>> a key binding for an ID Token IMHO.  From a deployment perspective it's so
>>>> much easier to get an ID Token from an Enterprise IdP than an X.509 for
>>>> these scenarios.  The security benefits of supporting dynamic issued
>>>> credentials from an IdP that can implement zero-trust security controls
>>>> including MFA outweighs the privacy risks.
>>>>
>>>> There are also cross-client identity scenarios
>>>> https://developers.google.com/identity/protocols/oauth2/cross-client-identity
>>>> where a native app for example may have its own identity and the backend a
>>>> different client identity but to the end-user they are the same client.
>>>>  These deployments are a single trust domain and don't have the same
>>>> privacy risks as cross-domain deployments
>>>>
>>>> With ID-JAG the id_token issuer is the processor of the token exchange
>>>> request.  The assertion is something it issued so there wasn't a concern
>>>> for the same party to also validate it.  We didn't want the IdP to have to
>>>> maintain the state with a refresh token so decided to use the serialized
>>>> authentication context in the id_token for the request as the goal was a
>>>> chained authentication.  There is also interest to flow these claims also
>>>> in the ID-JAG to downstream AS.  I could see ID-JAG also supporting a key
>>>> binding for the id_token if supported by the IdP.
>>>>
>>>> -Karl
>>>>
>>>>
>>>>
>>>> On Sun, Sep 7, 2025 at 10:19 AM Dick Hardt via Openid-specs-ab <
>>>> openid-specs-ab at lists.openid.net> wrote:
>>>>
>>>>> Hey George
>>>>>
>>>>> I see you (and many others) were supportive for adoption of the
>>>>> Identity Assertion Authorization Grant
>>>>>
>>>>>
>>>>> https://datatracker.ietf.org/doc/draft-parecki-oauth-identity-assertion-authz-grant/
>>>>>
>>>>> Where a client presents the id_token back to the OP/AS to get an
>>>>> ID-JAG token. Clearly the "aud" in the id_token is not the OP / AS. If
>>>>> presenting a token to a party that is not the "aud" is problematic, why did
>>>>> you not push back on that proposal?  The AS could return a special token
>>>>> that the client could present back later to the OP to get an ID-JAG
>>>>> according to your logic below.
>>>>>
>>>>> I think some of the difference of opinion here is evident in how you
>>>>> are describing what is happening. You are using the terms client and AS for
>>>>> the parties, which are OAuth / authorization terms -- and suggesting the
>>>>> id_token is being presented to an RS.
>>>>>
>>>>> I would agree that using the id_token for authorization is problematic
>>>>> -- but that is not what we are proposing.
>>>>>
>>>>> The RP1 gets an id_token that has a bound key from the OP.
>>>>>
>>>>> RP1 then presents the id_token to RP2, with some proof of possession
>>>>> mechanism specific to the RP1 -> RP2 protocol.
>>>>>
>>>>> All the claims in the id_token are expected to be relevant in the
>>>>> presentation to RP2.
>>>>>
>>>>> As Jacob notes -- the "auth_time", "acr",  and "amr" claims could be
>>>>> very useful to RP2.
>>>>>
>>>>> In other words, RP1 -> RP2 is a chained authentication event.
>>>>>
>>>>> /Dick
>>>>>
>>>>>
>>>>> On Sat, Sep 6, 2025 at 4:02 PM <george at practicalidentity.com> wrote:
>>>>>
>>>>>> So I think there are a couple of things I’d like to add to this
>>>>>> conversation.
>>>>>>
>>>>>> 1. The original intent/purpose of the id_token is to communicate an
>>>>>> identity assertion to the requesting client about the logged in user. Hence
>>>>>> the ‘aud’ claim in the id_token being the client_id of the requesting
>>>>>> client. General JWT based ‘aud’ claim processing rules require another
>>>>>> party receiving the id_token to reject it because the ‘aud’ claim doesn’t
>>>>>> match the receiver (see section 4.1.3 of RFC 7519). I have significant
>>>>>> concerns around trying to re-purpose the id_token for something different
>>>>>> (communicating status of the authentication to another party than the
>>>>>> requesting client).
>>>>>>
>>>>>> 2. The need for a secure way for the client to communicate to another
>>>>>> party (e.g. resource server) status about the authenticated user is valid.
>>>>>> However, I don’t believe that using the id_token is the best way to do
>>>>>> this. That is because, in addition to the ‘aud’ claim issues highlighted
>>>>>> previously, there are significant privacy risks in doing so. I’ve seen many
>>>>>> deployments that put user claims into the id_token that are NOT appropriate
>>>>>> for a subsequent resource server. Asking the AS to limit the user claims in
>>>>>> the id_token because it will be used to communicate authentication status
>>>>>> to a resource server could hamper the requesting client as it now needs a
>>>>>> different way to get those user claims that are appropriate just for
>>>>>> itself. I would much prefer that a new token be defined for the explicit
>>>>>> purpose of communicating authentication status. That frees up the AS to
>>>>>> limit PII related claims in that token while providing them in the id_token
>>>>>> to the requesting client. This also allows the AS to identify the list of
>>>>>> ‘aud’ values matching the receiving servers or potentially removing it
>>>>>> completely.
>>>>>>
>>>>>> 3. A new ’scope’, as currently proposed, can instruct the AS to
>>>>>> return this new token. There is much precedent for scopes to trigger this
>>>>>> type of behavior including the ‘openid’ scope itself.
>>>>>>
>>>>>> In my career I have rarely seen overloading intent to work out well.
>>>>>> Maybe others have a different experience.
>>>>>>
>>>>>> Thanks,
>>>>>> George
>>>>>>
>>>>>> George Fletcher
>>>>>> Identity Standards Architect
>>>>>> Practical Identity LLC
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Sep 5, 2025, at 5:18 AM, Jacob Ideskog via Openid-specs-ab <
>>>>>> openid-specs-ab at lists.openid.net> wrote:
>>>>>>
>>>>>> Hi all,
>>>>>>
>>>>>> I'd like to chip in on the semantics of the two approaches.
>>>>>>
>>>>>> The way I've always interpreted the id_token vs the user info is the
>>>>>> following:
>>>>>>
>>>>>> The *id_token* represents the authentication transaction that just
>>>>>> took place. For that reason it contains important non-profile information
>>>>>> such as auth_time, acr, amr etc which are useful for the RP when deciding
>>>>>> if the authentication that took place is strong enough, fresh enough etc.
>>>>>> It *can* also contain a number of useful claims about the account or
>>>>>> the user but at a minimum it needs the subject in some form.
>>>>>>
>>>>>> The *user info *on the other hand is mainly governed by the profile
>>>>>> scope and sibling scopes. It does not contain authentication specific
>>>>>> information but rather only account specific details.
>>>>>>
>>>>>> In our implementation we tend to recommend adding account/user claims
>>>>>> in the ID token if you think the RP needs them to save them the round trip
>>>>>> for user info, but it's optional and up to the particular use-case. For
>>>>>> instance if you intend to share the ID token as this spec proposes, then
>>>>>> adding account claims should be weighed against the privacy posture
>>>>>> required.
>>>>>>
>>>>>> That said, to me, issuing a proof based on user info is less valuable
>>>>>> to a 3rd party as it would not contain the authentication specific details
>>>>>> that may matter to that party as well. If nothing else, the auth_time is
>>>>>> generally valuable. It could also convey details about how long the OP
>>>>>> considers the session to be valid for if you chose to interpret the exp as
>>>>>> such.
>>>>>> Issuing a bound ID token seems more to the point if that's the main
>>>>>> use-case we're after. If all we want to do is share user info details to
>>>>>> another party then a credential would do.
>>>>>>
>>>>>> It sounds like they solve different problems and should not be mixed.
>>>>>>
>>>>>> Just my 2¢
>>>>>>
>>>>>> /Jacob Ideskog
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Thu, 21 Aug 2025 at 19:39, Dick Hardt via Openid-specs-ab <
>>>>>> openid-specs-ab at lists.openid.net> wrote:
>>>>>>
>>>>>>> Here is my homework as assigned by the working group chair. :)
>>>>>>>
>>>>>>> KB = OpenID Connect Key Binding
>>>>>>> UVC = OpenID Connect UserInfo Verifiable Credentials
>>>>>>> Links to specs at bottom
>>>>>>>
>>>>>>>
>>>>>>> *Tl;dr:*KB adds the key to an ID Token
>>>>>>> UVC creates a verifiable credential with same info, but VC syntax
>>>>>>> KB does it in one call to OP
>>>>>>> UVC requires two calls to OP
>>>>>>>
>>>>>>> *Key Bound Token*
>>>>>>> KB outputs an id_token that includes a `cnf` claim of the public key
>>>>>>> UVC outputs a verifiable credential with a `did:jwk:ey...` claim
>>>>>>> Both include all the same user claims
>>>>>>>
>>>>>>>
>>>>>>> *Authentication Request*
>>>>>>> - KB uses `dpop` scope as well as `dpop_jkt` parameter
>>>>>>> - UVC uses `userinfo_credential`
>>>>>>>
>>>>>>> KB has extra layer of security as `dpop_jkt` provides additional
>>>>>>> assurance between authentication request and token request
>>>>>>>
>>>>>>> *Token Request*
>>>>>>> - KB - RP passes DPoP JWT as header
>>>>>>> - UVC has no changes
>>>>>>>
>>>>>>> *Token Response*
>>>>>>> - KB - OP passes back id_token that includes `cnf` claim
>>>>>>> - UVC - OP passes back an access_token as well as c_nonce and
>>>>>>> c_nonce_expires_in
>>>>>>>
>>>>>>> At this point, KB has completed the key binding ...
>>>>>>>
>>>>>>> *Credential Request and Response *
>>>>>>> UVC continues on
>>>>>>> - RP generates a verifiable credential request and passes it with
>>>>>>> the access_token as a bearer token to the OP's credential endpoint
>>>>>>> - OP returns a verifiable credential
>>>>>>>
>>>>>>>
>>>>>>> https://dickhardt.github.io/openid-key-binding/main.html
>>>>>>> https://github.com/dickhardt/openid-key-binding
>>>>>>>
>>>>>>> https://openid.net/specs/openid-connect-userinfo-vc-1_0.html
>>>>>>>
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> Openid-specs-ab mailing list
>>>>>>> Openid-specs-ab at lists.openid.net
>>>>>>> https://lists.openid.net/mailman/listinfo/openid-specs-ab
>>>>>>>
>>>>>>
>>>>>>
>>>>>> --
>>>>>> Jacob Ideskog
>>>>>> CTO
>>>>>> Curity
>>>>>> -------------------------------------------------------------------
>>>>>> Sankt Göransgatan 66, Stockholm, Sweden
>>>>>> M: +46 70-2233664
>>>>>> j <jacob at twobo.com>acob at curity.io
>>>>>> curity.io
>>>>>> -------------------------------------------------------------------
>>>>>> _______________________________________________
>>>>>> Openid-specs-ab mailing list
>>>>>> Openid-specs-ab at lists.openid.net
>>>>>> https://lists.openid.net/mailman/listinfo/openid-specs-ab
>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>> Openid-specs-ab mailing list
>>>>> Openid-specs-ab at lists.openid.net
>>>>> https://lists.openid.net/mailman/listinfo/openid-specs-ab
>>>>>
>>>>
>>>>
>>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openid.net/pipermail/openid-specs-ab/attachments/20250909/a9d90843/attachment-0001.htm>


More information about the Openid-specs-ab mailing list