File

src/issuer/issuance/oid4vci/oid4vci.controller.ts

Prefix

:tenantId/vci

Description

Controller for handling OID4VCI (OpenID for Verifiable Credential Issuance) requests.

Index

Methods

Methods

Async credential
credential(req: Request, res: Response, tenantId: string)
Decorators :
@Post('credential')
@HttpCode(HttpStatus.OK)
@SessionLogger('session', 'OID4VCI')

Endpoint to issue credentials

Parameters :
Name Type Optional
req Request No
res Response No
tenantId string No
Returns : Promise<CredentialResponse | DeferredCredentialResponse | string>
deferredCredential
deferredCredential(req: Request, body: DeferredCredentialRequestDto, tenantId: string)
Decorators :
@Post('deferred_credential')
@SessionLogger('transaction_id', 'OID4VCI')
@HttpCode(HttpStatus.OK)

Deferred Credential Endpoint

According to OID4VCI Section 9, this endpoint is used by the wallet to poll for credentials that were not immediately available.

Parameters :
Name Type Optional Description
req Request No

The request

body DeferredCredentialRequestDto No

The deferred credential request containing transaction_id

tenantId string No

The tenant ID

Returns : Promise<CredentialResponse>

The credential response if ready, or issuance_pending error

nonce
nonce(tenantId: string)
Decorators :
@Post('nonce')
@HttpCode(HttpStatus.OK)
@Header('Cache-Control', 'no-store')
Parameters :
Name Type Optional
tenantId string No
Returns : any
notifications
notifications(body: NotificationRequestDto, req: Request, tenantId: string)
Decorators :
@Post('notification')
@SessionLogger('notification_id', 'OID4VCI')

Notification endpoint

Parameters :
Name Type Optional
body NotificationRequestDto No
req Request No
tenantId string No
Returns : any
import {
    Body,
    ConflictException,
    Controller,
    Header,
    HttpCode,
    HttpStatus,
    Param,
    Post,
    Req,
    Res,
    UseInterceptors,
} from "@nestjs/common";
import { ApiExcludeController, ApiParam, ApiTags } from "@nestjs/swagger";
import type {
    CreateCredentialResponseReturn,
    CredentialResponse,
    DeferredCredentialResponse,
} from "@openid4vc/openid4vci";
import type { Request, Response } from "express";
import { SessionLogger } from "../../../shared/utils/logger/session-logger.decorator";
import { SessionLoggerInterceptor } from "../../../shared/utils/logger/session-logger.interceptor";
import { DeferredCredentialRequestDto } from "./dto/deferred-credential-request.dto";
import { NotificationRequestDto } from "./dto/notification-request.dto";
import { Oid4vciService } from "./oid4vci.service";

/**
 * Controller for handling OID4VCI (OpenID for Verifiable Credential Issuance) requests.
 */
@ApiTags("OID4VCI")
@ApiParam({ name: "tenantId", required: true })
@ApiExcludeController(process.env.SWAGGER_ALL !== "true")
@Controller(":tenantId/vci")
@UseInterceptors(SessionLoggerInterceptor)
export class Oid4vciController {
    constructor(private readonly oid4vciService: Oid4vciService) {}

    /**
     * Endpoint to issue credentials
     * @param req
     * @param res
     * @param tenantId
     * @returns
     */
    @Post("credential")
    @HttpCode(HttpStatus.OK)
    @SessionLogger("session", "OID4VCI")
    async credential(
        @Req() req: Request,
        @Res({ passthrough: true }) res: Response,
        @Param("tenantId") tenantId: string,
    ): Promise<CredentialResponse | DeferredCredentialResponse | string> {
        return this.oid4vciService.getCredential(req, tenantId).then(
            (result) => {
                // Check if this is a deferred response (has non-null transaction_id)
                if ("transaction_id" in result && result.transaction_id) {
                    res.status(HttpStatus.ACCEPTED);
                    return result;
                }

                const credentialResult =
                    result as CreateCredentialResponseReturn;

                // If the response is encrypted, return the JWE string directly
                // See: https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-credential-response
                if (credentialResult.credentialResponseJwt) {
                    res.setHeader("Content-Type", "application/jwt");
                    return credentialResult.credentialResponseJwt;
                }

                return credentialResult.credentialResponse;
            },
            (err) => {
                //TODO: implement errors according to: https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-credential-request-errors
                throw new ConflictException(
                    `Credential issuance failed: ${err.message}`,
                );
            },
        );
    }

    /**
     * Deferred Credential Endpoint
     *
     * According to OID4VCI Section 9, this endpoint is used by the wallet to poll
     * for credentials that were not immediately available.
     *
     * @param req The request
     * @param body The deferred credential request containing transaction_id
     * @param tenantId The tenant ID
     * @returns The credential response if ready, or issuance_pending error
     */
    @Post("deferred_credential")
    @SessionLogger("transaction_id", "OID4VCI")
    @HttpCode(HttpStatus.OK)
    deferredCredential(
        @Req() req: Request,
        @Body() body: DeferredCredentialRequestDto,
        @Param("tenantId") tenantId: string,
    ): Promise<CredentialResponse> {
        return this.oid4vciService.getDeferredCredential(req, body, tenantId);
    }

    /**
     * Notification endpoint
     * @param body
     * @returns
     */
    @Post("notification")
    @SessionLogger("notification_id", "OID4VCI")
    notifications(
        @Body() body: NotificationRequestDto,
        @Req() req: Request,
        @Param("tenantId") tenantId: string,
    ) {
        return this.oid4vciService.handleNotification(req, body, tenantId);
    }

    @Post("nonce")
    @HttpCode(HttpStatus.OK)
    @Header("Cache-Control", "no-store")
    nonce(@Param("tenantId") tenantId: string) {
        //TODO: maybe also add it into the header, see https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-nonce-response
        return this.oid4vciService.nonceRequest(tenantId).then((nonce) => ({
            c_nonce: nonce,
        }));
    }
}

results matching ""

    No results matching ""