@sphereon/oid4vci-client
Version:
OpenID for Verifiable Credential Issuance (OpenID4VCI) client
183 lines (160 loc) • 6.42 kB
text/typescript
import {
AccessTokenResponse,
CredentialIssuerMetadataV1_0_13,
CredentialOfferPayloadV1_0_13,
CredentialOfferRequestWithBaseUrl,
determineSpecVersionFromOffer,
EndpointMetadata,
ExperimentalSubjectIssuance,
getIssuerFromCredentialOfferPayload,
OID4VCICredentialFormat,
OpenId4VCIVersion,
UniformCredentialOfferRequest,
} from '@sphereon/oid4vci-common';
import { CredentialFormat } from '@sphereon/ssi-types';
import { CredentialOfferClient } from './CredentialOfferClient';
import { CredentialRequestClient } from './CredentialRequestClient';
export class CredentialRequestClientBuilderV1_0_13 {
credentialEndpoint?: string;
deferredCredentialEndpoint?: string;
deferredCredentialAwait = false;
deferredCredentialIntervalInMS = 5000;
credentialIdentifier?: string;
credentialTypes?: string[] = [];
format?: CredentialFormat | OID4VCICredentialFormat;
token?: string;
version?: OpenId4VCIVersion;
subjectIssuance?: ExperimentalSubjectIssuance;
issuerState?: string;
public static fromCredentialIssuer({
credentialIssuer,
metadata,
version,
credentialIdentifier,
credentialTypes,
}: {
credentialIssuer: string;
metadata?: EndpointMetadata;
version?: OpenId4VCIVersion;
credentialIdentifier?: string;
credentialTypes?: string | string[];
}): CredentialRequestClientBuilderV1_0_13 {
const issuer = credentialIssuer;
const builder = new CredentialRequestClientBuilderV1_0_13();
builder.withVersion(version ?? OpenId4VCIVersion.VER_1_0_13);
builder.withCredentialEndpoint(metadata?.credential_endpoint ?? (issuer.endsWith('/') ? `${issuer}credential` : `${issuer}/credential`));
if (metadata?.deferred_credential_endpoint) {
builder.withDeferredCredentialEndpoint(metadata.deferred_credential_endpoint);
}
if (credentialIdentifier) {
builder.withCredentialIdentifier(credentialIdentifier);
}
if (credentialTypes) {
builder.withCredentialType(credentialTypes);
}
return builder;
}
public static async fromURI({ uri, metadata }: { uri: string; metadata?: EndpointMetadata }): Promise<CredentialRequestClientBuilderV1_0_13> {
const offer = await CredentialOfferClient.fromURI(uri);
return CredentialRequestClientBuilderV1_0_13.fromCredentialOfferRequest({ request: offer, ...offer, metadata, version: offer.version });
}
public static fromCredentialOfferRequest(opts: {
request: UniformCredentialOfferRequest;
scheme?: string;
baseUrl?: string;
version?: OpenId4VCIVersion;
metadata?: EndpointMetadata;
}): CredentialRequestClientBuilderV1_0_13 {
const { request, metadata } = opts;
const version = opts.version ?? request.version ?? determineSpecVersionFromOffer(request.original_credential_offer);
if (version < OpenId4VCIVersion.VER_1_0_13) {
throw new Error('Versions below v1.0.13 (draft 13) are not supported.');
}
const builder = new CredentialRequestClientBuilderV1_0_13();
const issuer = getIssuerFromCredentialOfferPayload(request.credential_offer) ?? (metadata?.issuer as string);
builder.withVersion(version);
builder.withCredentialEndpoint(metadata?.credential_endpoint ?? (issuer.endsWith('/') ? `${issuer}credential` : `${issuer}/credential`));
if (metadata?.deferred_credential_endpoint) {
builder.withDeferredCredentialEndpoint(metadata.deferred_credential_endpoint);
}
const ids: string[] = (request.credential_offer as CredentialOfferPayloadV1_0_13).credential_configuration_ids;
// if there's only one in the offer, we pre-select it. if not, you should provide the credentialType
if (ids.length && ids.length === 1) {
builder.withCredentialIdentifier(ids[0]);
}
return builder;
}
public static fromCredentialOffer({
credentialOffer,
metadata,
}: {
credentialOffer: CredentialOfferRequestWithBaseUrl;
metadata?: EndpointMetadata;
}): CredentialRequestClientBuilderV1_0_13 {
const builder = CredentialRequestClientBuilderV1_0_13.fromCredentialOfferRequest({
request: credentialOffer,
metadata,
version: credentialOffer.version,
});
return builder;
}
public withCredentialEndpointFromMetadata(metadata: CredentialIssuerMetadataV1_0_13): this {
this.credentialEndpoint = metadata.credential_endpoint;
return this;
}
public withCredentialEndpoint(credentialEndpoint: string): this {
this.credentialEndpoint = credentialEndpoint;
return this;
}
public withIssuerState(issuerState?: string): this {
this.issuerState = issuerState;
return this;
}
public withDeferredCredentialEndpointFromMetadata(metadata: CredentialIssuerMetadataV1_0_13): this {
this.deferredCredentialEndpoint = metadata.deferred_credential_endpoint;
return this;
}
public withDeferredCredentialEndpoint(deferredCredentialEndpoint: string): this {
this.deferredCredentialEndpoint = deferredCredentialEndpoint;
return this;
}
public withDeferredCredentialAwait(deferredCredentialAwait: boolean, deferredCredentialIntervalInMS?: number): this {
this.deferredCredentialAwait = deferredCredentialAwait;
this.deferredCredentialIntervalInMS = deferredCredentialIntervalInMS ?? 5000;
return this;
}
public withCredentialIdentifier(credentialIdentifier: string): this {
this.credentialIdentifier = credentialIdentifier;
return this;
}
public withCredentialType(credentialTypes: string | string[]): this {
this.credentialTypes = Array.isArray(credentialTypes) ? credentialTypes : [credentialTypes];
return this;
}
public withFormat(format: CredentialFormat | OID4VCICredentialFormat): this {
this.format = format;
return this;
}
public withSubjectIssuance(subjectIssuance: ExperimentalSubjectIssuance): this {
this.subjectIssuance = subjectIssuance;
return this;
}
public withToken(accessToken: string): this {
this.token = accessToken;
return this;
}
public withTokenFromResponse(response: AccessTokenResponse): this {
this.token = response.access_token;
return this;
}
public withVersion(version: OpenId4VCIVersion): this {
this.version = version;
return this;
}
public build(): CredentialRequestClient {
if (!this.version) {
this.withVersion(OpenId4VCIVersion.VER_1_0_11);
}
return new CredentialRequestClient(this);
}
}