Skip to content

Conversation

@Ryanmtate
Copy link

@Ryanmtate Ryanmtate commented Sep 30, 2025

This pull request adds support for a new "DC API" workflow type to the OpenCred platform, enabling Digital Credential API-based verification flows. It introduces a new relying party configuration for DC API, updates the JWT generation logic to handle DC API responses, and adds related configuration, validation, and localization changes.

DC API Workflow Support

  • Added support for a new dc-api workflow type in the configuration (WorkflowType.DcApi) and included it in the list of available exchange protocols. [1] [2]
  • Added a sample relying party configuration for DC API, including workflow details and claim mappings, to combined.example.yaml.
  • Updated workflow validation logic to recognize and handle the new DC API type.

JWT Generation Enhancements

  • Enhanced jwtFromExchange in common/jwt.js to generate JWTs for DC API workflows, extracting relevant fields from the DC API response and including verification status and errors as claims.

Localization and UI

  • Added DC API-specific translation strings for UI prompts and error messages in the configuration.

General Configuration

Added an example config for dc api workflow.

Signed-off-by: Ryan Tate <ryan.tate@spruceid.com>
Signed-off-by: Ryan Tate <ryan.tate@spruceid.com>
Signed-off-by: Ryan Tate <ryan.tate@spruceid.com>
>
{{
$t("dcApiSwitchMethod") ||
"Use a different verification method"
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TODO: Need to identify if there is a way to fallback to annex b and if annex c/d is not supported for a device. (e.g., bluetooth, browser experimental flags, etc.).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is a good point for discussion. I think it is a solvable question, though it would be a great starting point to identify what specific device we should use to test this approach to see how much effort should be invested in it.

The general paradigm for opencred is that each session is an "exchange" for a particular workflow backend but that different wallet interaction methods could be used to facilitate that workflow backend's processing. Switching back to the oid4vp "native" backend from inside a request for a "dc-api" backend would slightly break that paradigm, but I imagine the DcApi workflow backend could manage some fallback processing using the code from the native backend, with some refactoring. If we end up needing to do it.

const payload = {
iss: config.server.baseUri,
aud: rp.clientId,
sub: subject || exchange.id,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to identify what the subject should be. It may not be guaranteed that the document number would be requested by a relying party.

Need to identify if this JWT construction is correct.

@ottonomy ottonomy self-requested a review October 1, 2025 18:39
@ottonomy ottonomy marked this pull request as draft October 1, 2025 18:39
@ottonomy
Copy link
Collaborator

ottonomy commented Oct 2, 2025

Updated ESLint configuration to enforce single quotes and improve code style consistency across the project (.eslintrc.cjs).

@Ryanmtate seems like some of the files in the PR have a bunch of formatting changes to use double quotes and changed spacing. Generally preferable to split linting/formatting changes out into their own PRs but sometimes it's not practical, so I'm willing to consider it here, but maybe you could relint the config.js file and a couple others to ensure that the eslint config changes are working against the current "DB style" approach.

Our team is using MacOS or Unix systems generally, so it wouldn't be a surprise if there is a little formatting consistency work to do to enable clean collaboration with windows user developers.

@davidlehn
Copy link
Contributor

  • Also commenting on the formatting/style churn. I assume that was from some editor automation?
  • Looks like maybe a couple lines do a useful change from errant tabs to spaces, but otherwise it all seems an unnecessary change.
  • PRs from remote branches are not running actions, but if they did, there would be 1638 lint problems here.
  • The added eslint quotes rule maybe isn't needed. That is already in the digitalbazaar config, but without the avoidEscape option. In either case, there are now 310 double quote errors.

@Ryanmtate
Copy link
Author

  • Also commenting on the formatting/style churn. I assume that was from some editor automation?
  • Looks like maybe a couple lines do a useful change from errant tabs to spaces, but otherwise it all seems an unnecessary change.
  • PRs from remote branches are not running actions, but if they did, there would be 1638 lint problems here.
  • The added eslint quotes rule maybe isn't needed. That is already in the digitalbazaar config, but without the avoidEscape option. In either case, there are now 310 double quote errors.

Yes, thank you, this was an IDE configuration, which doesn't seem to be pulling in the eslint config. I will see if I can revert these formatting changes.

Signed-off-by: Ryan Tate <ryan.tate@spruceid.com>
Signed-off-by: Ryan Tate <ryan.tate@spruceid.com>
Signed-off-by: Ryan Tate <ryan.tate@spruceid.com>
Signed-off-by: Ryan Tate <ryan.tate@spruceid.com>
Signed-off-by: Ryan Tate <ryan.tate@spruceid.com>
Signed-off-by: Ryan Tate <ryan.tate@spruceid.com>
Signed-off-by: Ryan Tate <ryan.tate@spruceid.com>
@Ryanmtate
Copy link
Author

@ottonomy @davidlehn

I ran eslint against the project and resolved the linting errors. I still see formatting changes to the .vue exchange layout file, maybe there is another linter for vue being used?

@Ryanmtate Ryanmtate marked this pull request as ready for review October 7, 2025 03:30
Signed-off-by: Ryan Tate <ryan.tate@spruceid.com>
@davidlehn
Copy link
Contributor

@ottonomy @davidlehn

I ran eslint against the project and resolved the linting errors. I still see formatting changes to the .vue exchange layout file, maybe there is another linter for vue being used?

The eslint setup does lint .vue files via the eslint-config-digitalbazaar/vue3 rules. It's going to enforce the same js style there and and check for other vue issues. Looks like those files were changed to another style with different quotes, indents, and so on.

A future opinionated style issue is that the next version of digitalbazaar eslint config checks for no trailing commas. I notice many being added here. Configurable of course, but that's the direction we went for consistency vs no rule and mixed syntax.

Copy link
Collaborator

@ottonomy ottonomy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks again for submitting this. I will plan on finishing processing this into an OlenCred update that also simplifies the config structure that I've been preparing. I took some notes on the integration points for me as I work.

I'll especially be looking at removing the secondary exchange creation for session purposes. There was another case of such a thing already in OpenCred, and they should probably both go away for more database efficiency. I'm sure I'll discover what you mean more specifically by limitations in the session lifecycle that caused you to go this direction. It seems like it's not a data type issue but maybe more like something about not exposing some private server side data to the client?

Some of the comments in this review are likely incorrect or etc, mostly pointers for my notes as I integrate.

// Default to 1 hour
const expirySeconds = rp.idTokenExpirySeconds || 3600;

const subject = stepResults.response['org.iso.18013.5.1'].document_number;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Danger with non happy path payloads

const stepResults = exchange.variables.results[stepResultKey];

// Handle DC API workflow differently
if(rp.workflow?.type === 'dc-api' && !!stepResults) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Break out into testable function to generate the payload for dc API

}

async initDcApi() {
const rp = config.opencred.relyingParties.find(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There may be multiple rps of this type, rp assignment should be done at request time in auth/middleware.

rp?.workflow?.baseUrl,
submissionEndpoint,
referenceEndpoint,
encoder.encode(config.opencred.caStore[0]),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Find appropriate specific cert, probably at request time associated with a specific RP. The session store is probably the thing that needs to happen first.

const rp = req.rp;
const exchange = await this.getExchange({rp, id: req.params.exchangeId});

logUtils.presentationStart(rp?.clientId, exchange?.id);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move after next line and check log lifecycle for consistency here

emit("overrideActive");
};
const switchToOtherMethod = () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Improve this to only use available methods for the workflow type

<p class="text-lg text-green-600 mb-6">
{{ successMessage }}
</p>
<div class="mt-6">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only if on loginview, handle with events, don't show button if not possible

};
const handleGoBack = () => {
emit("overrideActive");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sure this is right for "go back"

:style="{ color: brand.primary }"
@click="switchToOtherMethod"
>
{{ $t("dcApiTryAnotherWay") || "Try another way" }}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Todo, define and test fallback

state.currentUXMethodIndex = openid4vpIndex;
}
}
// For other workflow types, keep default (first protocol in the list)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean up to only display possible options for the RP and choose best one first

Signed-off-by: Ryan Tate <ryan.tate@spruceid.com>
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

Successfully merging this pull request may close these issues.

3 participants