Replies: 14 comments 54 replies
-
|
Yes, the above picture is incorrect because there is indeed another actor initiating the credential offer process. It is the Issuer not the Holder/User that starts the process.
From the UI perspective, it'd be good to have a view that shows the QR code to whoever creates credential offers for registered users. In the context of a University for example, it would be someone from administration who holds the 'credential-offer-create' role. That person would want to see not only the offerUri but also the associated QR code, which can then be passed on to the student. This brings me to why the current getCredentialOfferURI(...) response is inadequate because it requires two calls: one for the uri and one for the qr code. Instead, it should work such that the uri is always returned and the qr code can be optionally returned in the same payload as well - it should just be another representation for the uri. Currently, two calls to that endpoint create two distinct credential offers. |
Beta Was this translation helpful? Give feedback.
-
|
Here are my thoughts to this topic: @mposolda you are absolutely right. This endpoint is basically for testing purposes to have a fast initialization endpoint so we can test this feature. This is also related to a ticket I once created: #39260. The topic of this ticket might be misunderstood but I meant to move these custom-endpoints into their own class to make sure that such confusion will not arise :-) Regarding the credential_offer:
These use-cases are relevant for the PreAuthorized Code Flow. cross-device flow
user-self-initiated flow
admin-initiated flow
That is my understanding of how it should work. |
Beta Was this translation helpful? Give feedback.
-
|
Hi @mposolda Thanks for initiating this discussion, I'm not sure Keycloak itself should be showing a QR code since IMHO it belongs in the application domain, and specifically in the I'm not sure Keycloak should be doing this work itself, sending the transaction code out of band - Keycloak does not see the user details during the preauthorized code acquisition and hence it will not know where to send the transaction code to. Furthermore, for example, if I login to MyUniversity, the implicit knowledge that I need some credentials related to this university is already established, so I'd not expect to provide information such as my university at the Keycloak login time... Apologies if I'm missing a few points. I think your point about the user profile is good, I saw there was a UserInfo VC draft underway, which can be relevant. Thanks |
Beta Was this translation helpful? Give feedback.
-
|
In the University use case, administration already has a trust relationship with the student - part of that would be the student's email. The student will also likely have credentials that allow her to do stuff on the Universities online portal. These credentials would not necessarily have to be the same that we are talking about in the context of oid4vci authorization. In theory, it would be possible that the Issuer (Keycloak) has a User entries with associated Credentials that students know nothing about. The Issuer initiates the credential offer e.g. sends an CredentialOfferURI to the student. The pre-authorized code grants the student the right to fetch a credential with a specific credential_id (and nothing else) - no Keycloak login would ever be required. |
Beta Was this translation helpful? Give feedback.
-
|
ok, the holder may nudge/remind the issuer as long as there is a common understanding that the holder does not somehow create the offer. With Keycloak you need to have the |
Beta Was this translation helpful? Give feedback.
-
|
Perhaps, I am adding the diagrams with the flows as how I can imagine it may work. Admin initiated-flow with "Required action" .Admin uses "Required actions" in Keycloak for various things already. For example admin adds required action "Update profile" or "Setup TOTP" to the user. Then user is requested during his next login to KC to update his user profile or setup his TOTP. This is done by KC page shown to him. So I can imagine the page (possibly with QR code for the wallet) is shown to him during his next login. The "Credential portal" is some OIDC application secured by Keycloak. It is the party like "University portal" (or sequenceDiagram
participant AD as Admin
participant PT as Credential Portal
participant US as User
participant WL as Wallet
participant KC as Keycloak
AD->>KC: 1) Admin authenticates
KC->>PT: 2) Admin authenticated in credential-portal app
AD->>PT: 3) Admin triggers creation of credential-offer for the user
PT->>KC: 4) Admin API request to create required-action "creation of credential offer" for user
US->>KC: 5) User doing login to KC to some browser application
KC->>US: 6) QR code page displayed to user (at the end of the login, after authentication is finished)
US->>WL: 7) User scans QR code to the wallet
Note over US,KC: 8) Flow continues as per OID4VCI specs step 3 of pre-authorized flow in paragraph 3.5
Admin-API initiated flow with the emailSimilar to previous, but the email is sent to the user. After user clicks on the link from email, the KC page is displayed to him. Keycloak already has support for this functionality of sending email to users. For example admin can send email to the user asking user to update his TOTP. Once user clicks on the link from email, the page with "Setup TOP" is displayed to him. So just leveraging existing Keycloak functionality, which is pretty much already there. sequenceDiagram
participant AD as Admin
participant PT as Credential Portal
participant US as User
participant WL as Wallet
participant KC as Keycloak
AD->>KC: 1) Admin authenticates
KC->>PT: 2) Admin authenticated in credential-portal app
AD->>PT: 3) Admin triggers creation of credential-offer for the user
PT->>KC: 4.a) Admin API request to send email to the user
KC->>US: 4.b) Email sent to user like "Credential offer available to you. Please click this link to see it"
US->>KC: 5) User clicks link from email
KC->>US: 6) Link from email displays KC page with QR code displayed to user
US->>WL: 7) User scans QR code to the wallet
Note over US,KC: Flow continues as per OID4VCI specs step 3 of pre-authorized flow in paragraph 3.5
User initiated flowUser initiates creation of credential-offer for himself from some "Credential portal" application . Probably similar to the @sberyozkin example above. It seems the only main difference between this flow and @sberyozkin flow is, that QR code is displayed by KC page instead of by "Credential portal" application itself: sequenceDiagram
participant US as User
participant PT as Credential Portal
participant US as User
participant WL as Wallet
participant KC as Keycloak
US->>KC: 1) User authentication
KC->>PT: 2) User authenticated in credential-portal app
US->>PT: 3) User triggers creation of credential-offer
PT->>KC: 4) OIDC authentication flow with "kc_action=create-credential-offer:xy" parameter
KC->>US: 5) KC display page with QR code to the user after SSO flow finish
US->>WL: 6) User scans QR code to the wallet
Note over US,KC: Flow continues as per OID4VCI specs step 3 of pre-authorized flow in paragraph 3.5
Additional pointsI can see some more variants to those flows. For example QR code does not need to be directly displayed to the user, but instead it can be directly sent to the wallet in case that wallet supports I hope to do prototype of this flow early next year to better present how I can imagine this to work. Created issue for this: #45026 . |
Beta Was this translation helpful? Give feedback.
-
|
How would this work in the case where the user does not have KC login credentials? With a pre-authorized CredentialOffer the user receives a code that when exchanged for an AccessToken allows her to fetch the credential associated with the offer. No other trust relationship with KC would be required. |
Beta Was this translation helpful? Give feedback.
-
|
Good morning, the question I've been planning to ask today, is a credential offer that requires the use of the authorization code flow grant is supported in Keycloak ? It should be relevant to this discussion to some extent. Such an offer can also be scanned via a QR code. |
Beta Was this translation helpful? Give feedback.
-
|
I looked at this again and thought it might help to break it down into
Issuer creates a Credential OfferFrom the spec perspective, we have great liberty how to create the Credential Offer, specifically about the state the server maintains associated with the Credential Offer (CredentialOfferState).
The EBSI Conformance Issuer for example has an endpoint like this .... Lets break it down ....
So yes, with this particular issuer (and for the purpose of conformance testing) there is a way for the Holder to initiate the Credential Offer process. The somewhat awkward The EBSI Issuer then creates the Credential Offer and sends it to the credential_offer_endpoint. EBSI supports both ...
Here we would have the liberty to authorize the Holder. For example, we could require proof of possession of the key material that the did is derived from and that we can resolve that did to an actual OAUTH client_id for the given credential_type. Since we are creating a CredentialOfferState it might be useful to do some authorization to protect ourselves from DOS attacks to this endpoint. Also, in the case of a pre-auth offer, it would be required to do so. We currently have an endpoint that is similar to the above and we protect it by the Issuer sends the Credential Offer to the HolderThe spec mentions four ways of doing so ...
Perhaps worth noting, that a Holder is not necessarily a natural person - it may be an institution or thing. The Issuer can therefore not assume that some interactive protocol has to happen to get the Credential Offer. The Holder consumes the Credential OfferHere we are bound by spec. When Holder has already received the Credential Offer we have two possible flows
Get Credential Pre-AuthorizedThe Holder can get the Credential without any other form of authorization. i.e. the pre-auth code grants the right to fetch a specific Credential instance, which would have been created when the Issuer made the Credential Offer. Because of that, it is feasible that the Get Credential non Pre-AuthorizedThe image shows the IDToken handshake, which is required by EBSI. For this discussion however, we can replace that authorization flow by OAUTH Code Flow just the same The TokenResponse may contain An authorization flow is necessary for the Holder to get the Credential associated with the Credential Offer. With IDToken authorization (as required by EBSI) there would be no interactive authorization step with the Holder. Same as above - the Holder would have a KC account with attributes that become Credential claim values, but not necessarily a login to that account. From the Issuer's perspective, it is sufficient to be able to map the Holder's DID to an existing account and to verify proof of possession for that DID. I guess that's it from me - look forward to talking to you next year cheers |
Beta Was this translation helpful? Give feedback.
-
Clarified PositionI would like to restate my position more clearly, because I think several parts of the discussion are mixing spec-defined roles with real-world deployment architectures, which leads to confusion. 1. Scope of OID4VCI and Role DefinitionsThe OID4VCI specification implicitly assumes a direct relationship between:
The Credential Issuer in the sense of the specification is the entity that:
The specification does NOT define any concept of an intermediary issuer, issuer proxy, or delegated issuer. 2. Real-World Architecture with an IntermediaryIn real-world deployments, an intermediary component such as Keycloak is often introduced:
This architectural separation is common in federated identity systems but is outside the explicit scope of the OID4VCI specification. 3. Consequences of This ArchitectureIntroducing an intermediary has several implications that are not addressed by the current specification, for example:
Addressing these points typically requires mechanisms such as transient users, pre-authorized flows, or out-of-band data provisioning, none of which are normatively defined for this scenario. 4. Interpretation from the Perspective of the SpecificationFrom a pure OID4VCI perspective, the entity that:
is the Credential Issuer. If Keycloak fulfills these responsibilities, then Keycloak is the Credential Issuer according to the specification, regardless of whether it acts on behalf of another organization. 5. Implication for Credential Offer PresentationBased on the above, it is consistent with the specification that:
Expecting the Credential Offer to be displayed on the business authority’s website (e.g. the university) implicitly assumes a role separation that is not modeled in OID4VCI. 6. ConclusionThe current confusion primarily arises from mixing:
OID4VCI currently models only the former. |
Beta Was this translation helpful? Give feedback.
-
|
For what it's worth ... it might help (at this point) to reduce architecture, role, implementation complexity into one until we achieve our next intermediary goal. We could decide that Keycloak == Issuer and that there is no other entity involved in issuing process (for now). Our next intermediary goal could be ...
In our discussions we could then simply say "The Issuer" and imply ...
In other words, we would focus on becoming a spec compliant oid4vci Issuer first. Folks who have more complex (intermediary) uses cases in mind, can build it externally and participate in design/architecture decisions to the extend that the rest interface can support that use case in principal. |
Beta Was this translation helpful? Give feedback.
-
|
I'd say if a credential_offer is to exist in Keycloak for the purpose that it needs to hold state like pre-auth code, tx_code, credential_identifier there must be something in Keycloak that creates that credential_offer. This cannot be done by human to UI action alone, because a Holder/Wallet can not only be a human but also a backend service, institution or an otherwise headless thing. There is the use case (also mentioned in the blog) of ...
In the human Wallet to Issuer case, there must still be something that triggers offer creation and hence the state associated with it. Keycloak could then still present that state in its UI (e.g. show a QR code and require additional actions). However, the /create_credential_offer endpoint needs to versatile and well protected enough to do that low-level operation first (i.e. create an internal credential offer) BTW, there was this idea that the /create_credential_offer endpoint does create the credential offer and returns nothing. Through some other endpoint or in the UI the state of that credential offer could be shown, communicated, etc. We dismissed this idea, because it does not fix anything but simply delegates a potential vulnerability to some other endpoint. Perhaps related is this comment: #45231 (comment) |
Beta Was this translation helpful? Give feedback.
-
|
Conceptually it should be possible to draw a box around Keycloak (The Issuer) and only consider messages that come in and go out. These must be spec conform messages and it should not matter whether they come from a wallet or some other thing external to Keycloak. IMHO, it is somewhat regrettable, that the spec introduces the notion of credential offer that the Issuer makes, but does not say how to trigger credential offer creation. In practice, we will likely see a great variety of Issuer implementations that all do it differently - this would be a pain for University Portal creators. Perhaps we should bring it up for oid4vci-1.1 |
Beta Was this translation helpful? Give feedback.
-
|
In case it hasn't been mentioned in the context already ... A wallet that gets given an credential offer with embedded pre-auth code, does the following ...
The protocol does not make room for additional steps beyond those two (i.e. Wallets won't do Keycloak specific stuff) Yes, intercepting the pre-auth code is an attack vector, which however is mitigated by
Perhaps, our focus should be shifted more to The AccessToken should only give access to ...
If access was narrowed like this, an insider could still get hold of a credential that references another subject. This credential would however be useless when it comes to verification - the vp request would fail because the wallet cannot proof that it is the rightful owner of that credential. Intercepting a pre-auth code would not be more consequential than an intercepted credential request or leaked credential. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I would like to ask about OID4VCI Pre-authorization code flow as implemented in current Keycloak.
Current way
Per my understanding, there is the Keycloak endpoint
/realms/test/protocol/oid4vc/credential-offer-uri, which is supposed to create credential-offer and it is very first endpoint, which needs to be triggered during the Keycloak OID4VCI pre-authorization code flow. This is "custom" Keycloak endpoint, which is not described in the OID4VCI specification.Endpoint is supposed to be invoked with the
Authorization: Bearerand requires valid access token. The QR code picture is returned by Keycloak server and that QR code is supposed to be displayed in the OIDC client application, from where then eventually can be scanned by the user to his Wallet. So there might be some client application (referred to asOIDC clientin the picture and text below) where this QR code must be currently displayed. Per my understanding, the typical flow may look like this:I see some possible limitations here. Especially:
Per the specification, the QR code is supposed to be sent by the issuer to the wallet. But here we have possibly another actor (OIDC client) rather than QR code being displayed by the issuer
OIDC client himself can obtain the token from pre-authorization grant, which is supposed to be used by the Wallet. There are possible security issues with privilege escalation here like [OID4VCI] Impersonation possible in OID4VCI credential creation endpoint #44745 .
There is not any consent displayed to the user as requested per the specification . The OIDC client application may possibly display some consent to the user before it sends the initial request for credential-offer creation, however Keycloak as credential issuer doesn't have any control if the user really properly provided the consent for this.
Harder to handle cases where user is missing some mandatory attributes for the OID4VC credential.
Harder to handle more secure variants - especially the variant with
tx_code, which might be a requirement for some deployments.See some more limitations below (in the section "More limitations")
Considering the limitations above, I wonder if this
credential-offer-uriendpoint is really proper way to approach the problem of properly starting this flow?Proposal
Can we use the Keycloak required-actions / application-initiated actions (AIA) to approach the problem instead? In short, I can imagine something like this:
There will be new required action implementation in Keycloak like
create-oid4vci-credential-offer.This can be parameterized AIA. Some Keycloak required actions (EG.
DeleteCredentialActionorIdpLinkAction) already supports parameter. Client application can use something likekc_action=create-oid4vci-credential-offer:parameter-valuewhereparameter-valuemight be some structure (maybe JSON) encapsulating some parameters currently sent to credential-offer-uri endpoint (EG.credential-configuration-id,client_id. Not sure if more are needed. I would rather avoidusername- see [OID4VCI] Impersonation possible in OID4VCI credential creation endpoint #44745 for the details).Keycloak can display screen to the user with the QR code and some text like
You can register credential 'Passport' with Wallet 'Lissy-wallet'Once user consents this and scans the QR code with his Wallet, browser redirects him back to OIDC client. But note that the OIDC client doesn't see the QR code or any other context of OID4VC credential. It is just used for trigger the flow with
kc_actionparameter. The wallet can continue proper OID4VC pre-authorization code flow now.Variants
TX Code support - On the screen with QR code, there could be possibly also option to send the email with
tx_codeto the user. Or maybe this is done automatically if configured before redirecting to OIDC client? Thetx_codesupport is probably a follow-up? But can be probably nice to support it IMO.Credential offer endpoint - Instead of displaying QR code, the screen can just ask user for the consent and then the credential-offer could be directly sent to the wallet
credential_offer_endpointif it is preferred way of the wallet to receive credential offer. This is per specs section 12.1Admin triggered flow: Instead of flow being triggered from OIDC client, it can possibly be triggered by administrator, who would ask user to start credential-offer creation. This might be done by:
UserResource.executeActionsEmail, but it doesn't support any parameters. So may require some API updates and admin console updates - in the admin console, it is bit hidden in the Credentials tab of the user (In the tab Users -> Selecting user -> tab Credentials -> button Credential Reset)WDYT?
More limitations
Editing this discussion (on 2026-01-26) to add some more limitations (based on the discussion points below and some others):
The
credential-offer-uricustom endpoint returns either QR-code or URI, but not both. When OIDC-client (AKA. "Issuer portal") wants to display both on it's page, it cannot work as 2nd request would require creating another credential-offerAdministrators may have a need to implement another actor (this "Issuer portal") by themselves. That is the actor, which needs to send this
credential-offer-uricustom REST request to Keycloak and then somehow propagate the obtained data (QR-code or URI) to users. It is not possible to leverage any existing libraries for OID4VCI or OIDC as this endpoint is currently Keycloak specific (not implemented by any specification)Permissions model: Currently it is strictly required that to call the endpoint, user must have role
credential-offer-create. There is not much flexibility, especially:user self-issuance flows do not work as user cannot create credential-offer-uri for himself (unless he is in the role
credential-offer-uri)There is new role
credential-offer-createneeded in KC. Existing roles are not leveragedNot much flexibility. For example when want to specify that admin
joeis able to create credential-offers just for users, who are members ofgroup-a, but adminmaryjust for users fromgroup-bSome of the limitations are possible to be addressed in current REST endpoint (EG. limitation 6), but some not
Beta Was this translation helpful? Give feedback.
All reactions