Skip to content

feat: sd-jwt revocation flow#357

Open
sagarkhole4 wants to merge 19 commits intofeat/oidc-main-syncfrom
feat/sd-jwt-revocation-flow
Open

feat: sd-jwt revocation flow#357
sagarkhole4 wants to merge 19 commits intofeat/oidc-main-syncfrom
feat/sd-jwt-revocation-flow

Conversation

@sagarkhole4
Copy link
Copy Markdown

@sagarkhole4 sagarkhole4 commented Mar 30, 2026

Feat/sd jwt revocation flow

Summary by CodeRabbit

  • New Features

    • Credential revocation: Added revoke endpoint to revoke issued credentials
    • Status list configuration: New settings for server URL, API key, and default size
    • CLI support: Added command-line parameters for status list configuration
    • SD-JWT module: Integrated SD-JWT Virtual Credential support
  • Documentation

    • Updated API documentation with new revocation endpoint

…e sessions and integrate SdJwtVcModule.

Signed-off-by: Sagar Khole <sagar.khole@ayanworks.com>
…e sessions and integrate SdJwtVcModule.

Signed-off-by: Sagar Khole <sagar.khole@ayanworks.com>
Signed-off-by: Sagar Khole <sagar.khole@ayanworks.com>
Signed-off-by: Sagar Khole <sagar.khole@ayanworks.com>
Signed-off-by: Sagar Khole <sagar.khole@ayanworks.com>
Signed-off-by: Sagar Khole <sagar.khole@ayanworks.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 30, 2026

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2f6b33d4-dac4-4c5c-b4bf-2a66dfeca978

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR introduces credential revocation via status lists for OpenID4VC issuance. It adds CLI configuration for status-list server endpoints, extends the issuance controller and service to create and manage status lists, implements a revocation endpoint, and provides utilities for remote status-list operations including JWT signing and concurrent-modification locking.

Changes

Cohort / File(s) Summary
CLI Configuration & Setup
samples/cliConfig.json, src/cli.ts, src/cliAgent.ts
Added status-list server configuration (URL, API key, default size) to CLI argument parsing and AriesRestConfig; registered SdJwtVcModule; environment variables set from config with required statusListServerUrl validation.
Type Definitions
src/controllers/types.ts, src/controllers/openid4vc/types/issuer.types.ts, src/controllers/x509/x509.types.ts
Added CredentialState and CredentialRole enums; extended credential offer types with statusListDetails (listId, index, listSize) and isRevocable flag; replaced imported X509 key usage enums with local definitions.
Issuance Session Controller & Service
src/controllers/openid4vc/issuance-sessions/issuance-sessions.Controller.ts, src/controllers/openid4vc/issuance-sessions/issuance-sessions.service.ts
Added POST revoke endpoint; refactored createCredentialOffer to async with status-list creation logic including server URL injection and metadata storage; added revokeBySessionId method to revoke credentials in status lists.
Status List Utilities
src/utils/statusListService.ts
New utility service for remote status-list management: checkAndCreateStatusList creates/verifies status lists with JWT signing; revokeCredentialInStatusList updates and signs revocation entries with per-listId promise locking to serialize concurrent operations.
Routes & API Documentation
src/routes/routes.ts, src/routes/swagger.json
Registered POST /openid4vc/issuance-sessions/{issuanceSessionId}/revoke endpoint with authentication; updated OpenAPI schemas across all credential offer types and sessions schema to include statusListDetails and isRevocable properties.
Build Configuration
tsconfig.build.json
Updated TypeScript compiler options: changed lib from ES2021.Promise to ESNext/DOM; reformatted types and include arrays to multi-line format; removed trailing newline.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Controller as IssuanceSessionsController
    participant Service as IssuanceSessionsService
    participant StatusListUtil as statusListService
    participant Server as Status List Server
    participant Agent

    rect rgba(135, 206, 250, 0.5)
    Note over Client,Agent: Credential Offer Creation with Status List
    Client->>Controller: POST /issuance-sessions (with statusListDetails)
    Controller->>Service: createCredentialOffer(options, agentReq)
    Service->>Service: Map credentials async
    loop For each credential
        Service->>StatusListUtil: checkAndCreateStatusList(agent, listId, issuerDid)
        StatusListUtil->>Server: GET /status-lists/{listId}
        alt Status List Exists
            Server-->>StatusListUtil: 200 OK
        else Status List Not Found
            Server-->>StatusListUtil: 404 Not Found
            StatusListUtil->>Agent: Resolve issuer DID verification method
            Agent-->>StatusListUtil: Verification method
            StatusListUtil->>StatusListUtil: Sign statuslist+jwt
            StatusListUtil->>Server: POST /status-lists (id, jwt)
            Server-->>StatusListUtil: 201 Created
        end
        Service->>Service: Build status block with uri & idx
        Service->>Service: Store credential in offerStatusInfo
    end
    Service->>Service: Set issuanceMetadata.StatusListInfo
    Service-->>Controller: Offer with status list injection
    Controller-->>Client: 200 OK (credential offer)
    end

    rect rgba(144, 238, 144, 0.5)
    Note over Client,Agent: Credential Revocation
    Client->>Controller: POST /issuance-sessions/{id}/revoke
    Controller->>Service: revokeBySessionId(agentReq, sessionId)
    Service->>Service: Load issuance session record
    Service->>Service: Extract StatusListInfo from metadata
    loop For each revocation entry
        Service->>StatusListUtil: revokeCredentialInStatusList(agent, listId, idx, issuerDid)
        StatusListUtil->>StatusListUtil: Acquire per-listId lock
        StatusListUtil->>Server: GET /status-lists/{listId}
        Server-->>StatusListUtil: Current JWT
        StatusListUtil->>StatusListUtil: Parse JWT → StatusList
        StatusListUtil->>StatusListUtil: Set index status to revoked (1)
        StatusListUtil->>StatusListUtil: Sign updated statuslist+jwt
        StatusListUtil->>Server: PATCH /status-lists/{listId} (new jwt)
        Server-->>StatusListUtil: 200 OK
        StatusListUtil->>StatusListUtil: Release per-listId lock
    end
    Service-->>Controller: success message
    Controller-->>Client: 200 OK (revocation complete)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • shitrerohit
  • RinkalBhojani

Poem

🐰 A status list's born in the cloud up high,
Credentials revoked as moments pass by,
Locks keep the peace when conflicts might brew,
From offer to revoke, the JWT's true! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.18% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat: sd-jwt revocation flow' directly describes the main objective of the PR, which is to implement revocation functionality for SD-JWT credentials across the OpenID4VC issuance flow.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/sd-jwt-revocation-flow

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ajile-in ajile-in changed the title Feat/sd jwt revocation flow feat: sd-jwt revocation flow Apr 2, 2026
…e sessions and integrate SdJwtVcModule.

Signed-off-by: Sagar Khole <sagar.khole@ayanworks.com>
…e sessions and integrate SdJwtVcModule.

Signed-off-by: Sagar Khole <sagar.khole@ayanworks.com>
Signed-off-by: Sagar Khole <sagar.khole@ayanworks.com>
Signed-off-by: Sagar Khole <sagar.khole@ayanworks.com>
Signed-off-by: Sagar Khole <sagar.khole@ayanworks.com>
Signed-off-by: Sagar Khole <sagar.khole@ayanworks.com>
@tipusinghaw
Copy link
Copy Markdown
Contributor

@coderabbitai Please review

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 6, 2026

@tipusinghaw Sure! I'll start reviewing the changes in this PR right away.

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Comment thread samples/cliConfig.json Outdated
Comment thread src/controllers/openid4vc/issuance-sessions/issuance-sessions.service.ts Outdated
Comment thread src/controllers/openid4vc/issuance-sessions/issuance-sessions.service.ts Outdated
Comment thread src/utils/statusListService.ts Outdated
Comment thread src/utils/statusListService.ts Outdated
Comment thread src/utils/statusListService.ts Outdated
Comment thread tsconfig.build.json Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

🧹 Nitpick comments (1)
src/controllers/x509/x509.types.ts (1)

103-113: Example values don't match enum type.

The @example shows string names (["digitalSignature", "keyEncipherment", "crlSign"]), but X509KeyUsage is a numeric enum (e.g., DigitalSignature = 1, KeyEncipherment = 4). API consumers may be confused about whether to send enum names or numeric values.

Update the example to reflect the actual expected format, or clarify how the API deserializes string names to enum values.

📝 Suggested example update
 export interface KeyUsageDto {
   /**
-   * `@example` ["digitalSignature", "keyEncipherment", "crlSign"]
+   * `@example` [1, 4, 64]
+   * `@description` Array of X509KeyUsage values: DigitalSignature=1, NonRepudiation=2, KeyEncipherment=4, DataEncipherment=8, KeyAgreement=16, KeyCertSign=32, CrlSign=64, EncipherOnly=128, DecipherOnly=256
   */
   usages: X509KeyUsage[]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/controllers/x509/x509.types.ts` around lines 103 - 113, The example for
KeyUsageDto is misleading because usages is typed as X509KeyUsage (a numeric
enum); update the example to show numeric enum values or clarify conversion:
change the usages example to use the numeric enum values (e.g., [1, 4, 128]) or
add a note that string names are accepted and will be mapped to X509KeyUsage;
modify the KeyUsageDto JSDoc for the usages property and/or add a brief remark
next to markAsCritical to indicate optionality so consumers know the expected
payload format for the usages field.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/controllers/openid4vc/issuance-sessions/issuance-sessions.service.ts`:
- Around line 194-197: The code treats a missing issuanceMetadata.StatusListInfo
as an internal error; instead, update IssuanceSessionsService to return a client
error (4xx) for this input/caller problem by replacing the thrown generic Error
when statusInfo is falsy/empty with a specific HTTP error (e.g., BadRequest or a
400 HttpError) that includes the sessionId and a clear message; locate the check
around statusInfo = record.issuanceMetadata?.StatusListInfo and change the throw
to the appropriate HttpError type used in the codebase so callers receive a 4xx
rather than a 500.
- Around line 53-88: The code currently always injects a top-level SD-JWT-style
status block and doesn't validate that revocability is actually supported for
the chosen signer/format; update the logic around effectiveIssuerDid,
effectiveStatusList, isRevocable, and the payload merge to (1) validate at offer
creation time that isRevocable is only allowed when a revocation mechanism will
actually be attached (e.g., DID signer + SD-JWT/status-list for SD-JWT formats,
or DID signer + W3C-style credentialStatus for W3C VC formats; reject
combinations like isRevocable true with x5c signer or mso_mdoc or when no
effectiveStatusList), (2) compute and attach format-specific status payloads:
for SD-JWT formats use status: { status_list: { uri, idx } }, for W3C VC formats
use credentialStatus with the equivalent uri/index structure, and for mso_mdoc
do not add a JSON status claim (status is handled in CBOR MSO), and (3) keep
using checkAndCreateStatusList and offerStatusInfo but only push into
offerStatusInfo when you actually attach a revocation mechanism; use the
existing symbols effectiveIssuerDid, effectiveStatusList,
checkAndCreateStatusList, offerStatusInfo, supported, statusBlock and replace
the unconditional payload injection with format-aware branches that either
attach the appropriate claim or throw/reject when revocability cannot be
supported.

In `@src/utils/statusListService.ts`:
- Around line 69-71: The fetch calls in statusListService (the call that uses
uri and getApiKeyHeaders) must be routed through the shared HTTP helper that
enforces an abort/timeout and retry policy; replace direct fetch(uri, { headers:
getApiKeyHeaders() }) usages with the helper so requests are bounded by a
timeout/AbortSignal and ensure retries are only applied to safe read operations
(e.g., the status-list GET path) while write paths (issuance/revocation updates)
use a single timed request without retries; update every occurrence (the fetch
at lines using uri/getApiKeyHeaders and the other fetch blocks around 88-92 and
125-149) to use the helper and propagate the AbortSignal or timeout error
handling back to the caller.
- Around line 68-99: The GET→404→POST path for creating status lists is racy for
concurrent callers: wrap the creation logic for a given listId in a per-listId
lock (e.g., acquire/release based on listId) so only one caller performs the
fetch/create flow, or at minimum handle POST conflicts by treating a 409 as
success and re-reading the list after POST; specifically guard the block that
fetches uri, constructs StatusList, resolves issuer DID via agent.dids.resolve,
signs with signStatusList (using keyId), and posts to
`${getServerUrl()}/status-lists` (i.e., the code referencing listId, listSize,
StatusList, signStatusList, postRes) so concurrent Promise.all callers do not
both try to create the same list and fail.
- Around line 37-63: signStatusList currently hardcodes alg: 'EdDSA' and relies
on a non-specific verification method; change it to select the signing key and
algorithm based on the verification relationship (e.g., assertionMethod) and the
actual key type or provided signerOptions rather than array position, and set
the protected header kid to the full DID URL of the selected verification
method. Concretely: update the logic that calls getKmsKeyIdForDid and the
JwsProtectedHeaderOptions (the header variable) to accept/respect a
signerOptions or derive alg from the resolved key type (Ed25519->EdDSA,
P-256->ES256, secp256k1->ES256K), lookup the correct verificationMethod by its
relationship (not index 0), populate protectedHeaderOptions.kid with the DID URL
of that method, and pass the resolved alg and kid into
jwsService.createJwsCompact; apply the same pattern to the other signing sites
flagged (the other blocks using JwsProtectedHeaderOptions and createJwsCompact).

In `@tsconfig.build.json`:
- Line 39: The file ends with a closing brace but lacks a trailing newline;
update the tsconfig.build.json so that after the final closing brace (`}`) there
is a single newline character at EOF (ensure the file ends with a newline to
satisfy linters and POSIX conventions).
- Around line 19-22: The tsconfig.build.json currently includes "DOM" in the
"lib" array which brings browser types into a Node backend and causes conflicts;
remove "DOM" from the "lib" array so it only contains "ESNext" (or replace with
the minimal required ES libs) and rely on the existing "types": ["node"] for
Node typings; update any project docs or a one-line comment if there's a
specific reason to keep DOM types, otherwise delete the "DOM" entry to resolve
the type conflicts.

---

Nitpick comments:
In `@src/controllers/x509/x509.types.ts`:
- Around line 103-113: The example for KeyUsageDto is misleading because usages
is typed as X509KeyUsage (a numeric enum); update the example to show numeric
enum values or clarify conversion: change the usages example to use the numeric
enum values (e.g., [1, 4, 128]) or add a note that string names are accepted and
will be mapped to X509KeyUsage; modify the KeyUsageDto JSDoc for the usages
property and/or add a brief remark next to markAsCritical to indicate
optionality so consumers know the expected payload format for the usages field.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b154db66-7575-4f6c-917e-11e4e5ca9a08

📥 Commits

Reviewing files that changed from the base of the PR and between 741465f and 5e7263b.

📒 Files selected for processing (12)
  • samples/cliConfig.json
  • src/cli.ts
  • src/cliAgent.ts
  • src/controllers/openid4vc/issuance-sessions/issuance-sessions.Controller.ts
  • src/controllers/openid4vc/issuance-sessions/issuance-sessions.service.ts
  • src/controllers/openid4vc/types/issuer.types.ts
  • src/controllers/types.ts
  • src/controllers/x509/x509.types.ts
  • src/routes/routes.ts
  • src/routes/swagger.json
  • src/utils/statusListService.ts
  • tsconfig.build.json
👮 Files not reviewed due to content moderation or server errors (6)
  • src/controllers/openid4vc/types/issuer.types.ts
  • samples/cliConfig.json
  • src/controllers/openid4vc/issuance-sessions/issuance-sessions.Controller.ts
  • src/cliAgent.ts
  • src/cli.ts
  • src/routes/swagger.json

Comment thread src/utils/statusListService.ts Outdated
Comment thread src/utils/statusListService.ts
Comment thread src/utils/statusListService.ts Outdated
Comment thread tsconfig.build.json
Comment thread tsconfig.build.json Outdated
@tipusinghaw tipusinghaw force-pushed the feat/sd-jwt-revocation-flow branch from 5e7263b to 1291984 Compare April 7, 2026 06:02
Signed-off-by: Sagar Khole <sagar.khole@ayanworks.com>
Signed-off-by: Sagar Khole <sagar.khole@ayanworks.com>
Comment thread samples/cliConfig.json Fixed
Signed-off-by: Sagar Khole <sagar.khole@ayanworks.com>
@tipusinghaw tipusinghaw self-requested a review April 10, 2026 06:11
…lection for status list operations

Signed-off-by: Sagar Khole <sagar.khole@ayanworks.com>
Signed-off-by: Sagar Khole <sagar.khole@ayanworks.com>
@sonarqubecloud
Copy link
Copy Markdown

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