openid4vci

package
v0.7.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 25, 2026 License: BSD-2-Clause Imports: 22 Imported by: 0

README

OpenID4VCI

This is a Go implementation of the OpenID4VCI draft 14, aligns with the Italian profile.

https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0-ID1.html#abstract

Documentation

Index

Examples

Constants

View Source
const (
	GrantTypeAuthorizationCode = "authorization_code"
	GrantTypePreAuthorizedCode = "urn:ietf:params:oauth:grant-type:pre-authorized_code"
)

Grant type constants used as map keys in CredentialOfferParameters.Grants and as GrantType values in TokenRequest.

View Source
const (
	// ErrInvalidCredentialRequest The Credential Request is missing a required parameter, includes an unsupported parameter or parameter value, repeats the same parameter, or is otherwise malformed.
	ErrInvalidCredentialRequest string = "invalid_credential_request" // #nosec G101

	// ErrUnsupportedCredentialType Requested Credential type is not supported.
	ErrUnsupportedCredentialType = "unsupported_credential_type"

	// ErrUnsupportedCredentialFormat Requested Credential Format is not supported.
	ErrUnsupportedCredentialFormat = "unsupported_credential_format"

	// ErrInvalidProof The proof or proofs parameter in the Credential Request is invalid: (1) if both fields are missing, or (2) both are present simultaneously, or (3) one of the provided key proofs is invalid, or (4) if at least one of the key proofs does not contain a c_nonce value (refer to Section 7.2).
	ErrInvalidProof = "invalid_proof"

	// ErrInvalidNonce The proof or proofs parameter in the Credential Request uses an invalid nonce: at least one of the key proofs contains an invalid c_nonce value. The wallet should retrieve a new c_nonce value (refer to Section 7).
	ErrInvalidNonce = "invalid_nonce"

	// ErrInvalidEncryptionParameters This error occurs when the encryption parameters in the Credential Request are either invalid or missing. In the latter case, it indicates that the Credential Issuer requires the Credential Response to be sent encrypted, but the Credential Request does not contain the necessary encryption parameters.
	ErrInvalidEncryptionParameters = "invalid_encryption_parameters"

	// ErrUnknownCredentialConfiguration The credential_configuration_id in the Credential Request is not recognized by the Credential Issuer.
	ErrUnknownCredentialConfiguration = "unknown_credential_configuration"

	// ErrUnknownCredentialIdentifier The credential_identifier in the Credential Request is not recognized by the Credential Issuer.
	ErrUnknownCredentialIdentifier = "unknown_credential_identifier"

	// ErrCredentialRequestDenied The Credential Request has not been accepted by the Credential Issuer.
	ErrCredentialRequestDenied = "credential_request_denied" // #nosec G101
)

Credential errors

View Source
const (
	// ErrInvalidRequest The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed.
	ErrInvalidRequest = "invalid_request"

	// ErrUnauthorizedClient  The client is not authorized to request an authorization code using this method.
	ErrUnauthorizedClient = "unauthorized_client"

	// ErrAccessDenied The resource owner or authorization server denied the request.
	ErrAccessDenied = "access_denied"

	// ErrUnsupportedResponseType The authorization server does not support obtaining an authorization code using this method.
	ErrUnsupportedResponseType = "unsupported_response_type"

	// ErrInvalidScope The requested scope is invalid, unknown, or malformed.
	ErrInvalidScope = "invalid_scope"

	// ErrServerError The authorization server encountered an unexpected condition that prevented it from fulfilling the request.(This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)
	ErrServerError = "server_error"

	// ErrTemporarilyUnavailable The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.  (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)
	ErrTemporarilyUnavailable = "temporarily_unavailable"
)
View Source
const (

	// ErrTokenInvalidRequest * The Authorization Server does not expect a Transaction Code in the Pre-Authorized Code Flow but the Client provides a Transaction Code.
	// * The Authorization Server expects a Transaction Code in the Pre-Authorized Code Flow but the Client does not provide a Transaction Code.
	ErrTokenInvalidRequest = "invalid_request"

	// ErrTokenInvalidGrant * The Authorization Server expects a Transaction Code in the Pre-Authorized Code Flow but the Client provides the wrong Transaction Code.
	// * The End-User provides the wrong Pre-Authorized Code or the Pre-Authorized Code has expired.
	ErrTokenInvalidGrant = "invalid_grant"

	// ErrTokenInvalidClient * The Client tried to send a Token Request with a Pre-Authorized Code without a Client ID but the Authorization Server does not support anonymous access.
	ErrTokenInvalidClient = "invalid_client"

	// ErrTokenUnauthorizedClient The client is not authorized to request an authorization code using this method.
	ErrTokenUnauthorizedClient = "unauthorized_client"

	// ErrTokenAccessDenied The resource owner or authorization server denied the request.
	ErrTokenAccessDenied = "access_denied"

	// ErrTokenUnsupportedResponseType the authorization server does not support obtaining an authorization code using this method.
	ErrTokenUnsupportedResponseType = "unsupported_response_type"

	// ErrTokenInvalidScope the requested scope is invalid, unknown, or malformed.
	ErrTokenInvalidScope = "invalid_scope"

	// ErrTokenServerError the authorization server encountered an unexpected condition that prevented it from fulfilling the request. (This error code is needed because a 500 Internal Server Error HTTP status code cannot be returned to the client via an HTTP redirect.)
	ErrTokenServerError = "server_error"

	// ErrTokenTemporarilyUnavailable The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.  (This error code is needed because a 503 Service Unavailable HTTP status code cannot be returned to the client via an HTTP redirect.)
	ErrTokenTemporarilyUnavailable = "temporarily_unavailable"
)

Token errors

View Source
const (
	// InvalidNotificationID  invalid_notification_id: The notification_id in the Notification Request was invalid.
	InvalidNotificationID = "invalid_notification_id"

	// InvalidNotificationRequest invalid_notification_request: The Notification Request is missing a required parameter, includes an unsupported parameter or parameter value, repeats the same parameter, or is otherwise malformed.
	InvalidNotificationRequest = "invalid_notification_request"
)

Notification errors

Variables

This section is empty.

Functions

func CheckSimple

func CheckSimple(s any) error

CheckSimple checks for validation error with a simpler signature

func NewValidator

func NewValidator() (*validator.Validate, error)

NewValidator creates a new validator

func StatusCode

func StatusCode(err *Error) int

StatusCode returns the HTTP status code for the error

Example
package main

import (
	"fmt"

	"github.com/SUNET/vc/pkg/openid4vci"
)

func main() {
	tests := []struct {
		name string
		err  *openid4vci.Error
	}{
		{"bad request", &openid4vci.Error{Err: openid4vci.ErrInvalidCredentialRequest}},
		{"unauthorized", &openid4vci.Error{Err: openid4vci.ErrUnauthorizedClient}},
		{"forbidden", &openid4vci.Error{Err: openid4vci.ErrAccessDenied}},
		{"server error", &openid4vci.Error{Err: openid4vci.ErrServerError}},
		{"unavailable", &openid4vci.Error{Err: openid4vci.ErrTemporarilyUnavailable}},
	}

	for _, tt := range tests {
		code := openid4vci.StatusCode(tt.err)
		fmt.Printf("%s: %d\n", tt.name, code)
	}
}
Output:
bad request: 400
unauthorized: 401
forbidden: 403
server error: 500
unavailable: 503
Example (BadRequest)
package main

import (
	"fmt"
	"net/http"

	"github.com/SUNET/vc/pkg/openid4vci"
)

func main() {
	err := &openid4vci.Error{Err: openid4vci.ErrInvalidProof}
	code := openid4vci.StatusCode(err)
	fmt.Println(code == http.StatusBadRequest)
}
Output:
true

Types

type AuthorizationConsentLoginReply

type AuthorizationConsentLoginReply struct{}

type AuthorizationConsentLoginRequest

type AuthorizationConsentLoginRequest struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

type AuthorizationConsentReply

type AuthorizationConsentReply struct{}

type AuthorizationConsentRequest

type AuthorizationConsentRequest struct {
	State string `json:"state"`
	Code  string `json:"code"`
}

type AuthorizationDetailsParameter

type AuthorizationDetailsParameter struct {
	Type string `json:"type" form:"type" validate:"required,oneof=openid_credential"`

	// CredentialConfigurationID: REQUIRED when format parameter is not present. String specifying a unique identifier of the Credential being described in the credential_configurations_supported map in the Credential Issuer Metadata as defined in Section 11.2.3. The referenced object in the credential_configurations_supported map conveys the details, such as the format, for issuance of the requested Credential. This specification defines Credential Format specific Issuer Metadata in Appendix A. It MUST NOT be present if format parameter is present.
	CredentialConfigurationID string `json:"credential_configuration_id,omitempty" form:"credential_configuration_id" validate:"required_without=Format"`

	// Format REQUIRED when credential_configuration_id parameter is not present. String identifying the format of the Credential the Wallet needs. This Credential format identifier determines further claims in the authorization details object needed to identify the Credential type in the requested format. This specification defines Credential Format Profiles in Appendix A. It MUST NOT be present if credential_configuration_id parameter is present.
	Format string `json:"format,omitempty" form:"format" validate:"required_without=CredentialConfigurationID"`

	// VCT REQUIRED. String as defined in Appendix A.3.2. This claim contains the type values the Wallet requests authorization for at the Credential Issuer. It MUST only be present if the format claim is present. It MUST not be present otherwise.
	VCT string `json:"vct,omitempty" form:"vct" validate:"required_with=Format"`

	// Claims OPTIONAL. Object as defined in Appendix A.3.2 excluding the display and value_type parameters. mandatory parameter here is used by the Wallet to indicate to the Issuer that it only accepts Credential(s) issued with those claim(s).
	Claims map[string]any `json:"claims,omitempty" form:"claims"`

	// CredentialIdentifiers REQUIRED (Token Response only). A non-empty array of strings, each uniquely identifying
	// a Credential Dataset that can be issued using the Access Token returned in this response.
	CredentialIdentifiers []string `json:"credential_identifiers,omitempty"`
}

AuthorizationDetailsParameter https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-using-authorization-details

type AuthorizationResponse

type AuthorizationResponse struct {
	//	Code REQUIRED.  The authorization code generated by the authorization server.  The authorization code MUST expire shortly after it is issued to mitigate the risk of leaks. A maximum authorization code lifetime of 10 minutes is RECOMMENDED.  The client MUST NOT use the authorization code more than once.  If an authorization code is used more than once, the authorization server MUST deny the request and SHOULD	revoke (when possible) all tokens previously issued based on that authorization code. The authorization code is bound to the client identifier and redirection URI.
	Code string `json:"code" validate:"required"`

	// State REQUIRED if the "state" parameter was present in the client authorization request.  The exact value received from the client.
	State string `json:"state" validate:"required"`

	RedirectURL string `json:"-"`

	Scope string `json:"-"`

	ClientID string `json:"-"`

	WalletClientID string `json:"-"`

	SessionID string `json:"-"`
}

AuthorizationResponse RFC6749#4.1.2

type AuthorizeRequest

type AuthorizeRequest struct {
	ClientID   string `json:"client_id" uri:"client_id" form:"client_id" validate:"required"`
	RequestURI string `json:"request_uri" uri:"request_uri" form:"request_uri" validate:"required"`
}

type BatchCredentialIssuance

type BatchCredentialIssuance struct {
	// BatchSize: REQUIRED. Integer value specifying the maximum array size for the proofs parameter in a Credential Request.
	BatchSize int `json:"batch_size" yaml:"batch_size" validate:"required"`
}

type ClaimDescription

type ClaimDescription struct {
	// Path: REQUIRED. A non-empty array representing a claims path pointer that specifies the path to a claim within the credential.
	// A nil entry denotes a wildcard over an array's elements (e.g. ["nationalities", null]),
	// matching the claims path pointer semantics used by presentation/DCQL and VCTM.
	Path []*string `json:"path" yaml:"path" validate:"required"`

	// SVGID: OPTIONAL. A string linking the claim to a specific element ID in an SVG background template.
	SVGID string `json:"svg_id,omitempty" yaml:"svg_id,omitempty"`

	// Mandatory: OPTIONAL. Boolean which, when set to true, indicates that the Credential Issuer will always include this claim.
	Mandatory bool `json:"mandatory,omitempty" yaml:"mandatory,omitempty"`

	// Display: OPTIONAL. A non-empty array of objects containing display properties for the claim.
	Display []ClaimDisplayProperties `json:"display,omitempty" yaml:"display,omitempty"`
}

ClaimDescription describes a claim within a Credential for display purposes.

type ClaimDisplayProperties

type ClaimDisplayProperties struct {
	// Name: OPTIONAL. String value of a display name for the claim.
	Name string `json:"name,omitempty" yaml:"name,omitempty"`

	// Label: OPTIONAL. Same as Name — included for compatibility with consumers
	// (e.g. wallet-common's dataUriResolver) that expect a "label" field.
	Label string `json:"label,omitempty" yaml:"label,omitempty"`

	// Locale: OPTIONAL. String value that identifies the language of this object.
	Locale string `json:"locale,omitempty" yaml:"locale,omitempty" validate:"bcp47_language_tag"`
}

ClaimDisplayProperties contains display properties for a claim.

type Credential

type Credential struct {
	Credential string `json:"credential" validate:"required"`
}

type CredentialConfigurationsSupported

type CredentialConfigurationsSupported struct {
	// Format: REQUIRED. A JSON string identifying the format of this Credential, e.g., dc+sd-jwt, mso_mdoc, jwt_vc_json, ldp_vc.
	Format string `json:"format" yaml:"format" validate:"required"`

	// Scope: OPTIONAL. A JSON string identifying the scope value that this Credential Issuer supports for this particular Credential.
	Scope string `json:"scope,omitempty" yaml:"scope,omitempty"`

	// CredentialSigningAlgValuesSupported: OPTIONAL. A non-empty array of algorithm identifiers that the Issuer uses to sign the issued Credential.
	// For dc+sd-jwt format, these are strings like "ES256". For mso_mdoc format, these are COSE algorithm identifiers (integers like -7 for ES256).
	CredentialSigningAlgValuesSupported []any `json:"credential_signing_alg_values_supported,omitempty" yaml:"credential_signing_alg_values_supported,omitempty"`

	// CryptographicBindingMethodsSupported: OPTIONAL. A non-empty array of case sensitive strings that identify the representation of the cryptographic key material that the issued Credential is bound to.
	// Valid values include "jwk", "cose_key", and DID method prefixes like "did:key", "did:web", "did:jwk", etc.
	CryptographicBindingMethodsSupported []string `json:"cryptographic_binding_methods_supported,omitempty" yaml:"cryptographic_binding_methods_supported,omitempty"`

	// ProofTypesSupported: OPTIONAL. Object that describes specifics of the key proof(s) that the Credential Issuer supports.
	ProofTypesSupported map[string]ProofsTypesSupported `json:"proof_types_supported,omitempty" yaml:"proof_types_supported,omitempty"`

	// CredentialMetadata: OPTIONAL. Object containing information relevant to the usage and display of issued Credentials.
	CredentialMetadata *CredentialMetadata `json:"credential_metadata,omitempty" yaml:"credential_metadata,omitempty"`

	// VCT: REQUIRED for dc+sd-jwt format. String designating the type of the Credential, as defined in SD-JWT VC.
	VCT string `json:"vct,omitempty" yaml:"vct,omitempty"`

	// CredentialDefinition: REQUIRED for jwt_vc_json and ldp_vc formats. Object containing the detailed description of the Credential type.
	CredentialDefinition *CredentialDefinition `json:"credential_definition,omitempty" yaml:"credential_definition,omitempty"`

	// Doctype: REQUIRED for mso_mdoc format. String identifying the Credential type, as defined in ISO 18013-5.
	Doctype string `json:"doctype,omitempty" yaml:"doctype,omitempty"`

	// Cryptosuite: OPTIONAL. For ldp_vc and vc+ld+json formats, identifies the cryptographic suite used for Data Integrity Proofs.
	Cryptosuite string `json:"cryptosuite,omitempty" yaml:"cryptosuite,omitempty"`

	// DisclosurePolicy: OPTIONAL. Embedded disclosure policy per CIR 2024/2979 Annex III and ETSI TS 119 472-3.
	// Specifies conditions a Relying Party must meet to receive this attestation.
	// Distributed via Credential Issuer metadata (ARF 3.0 §6.6.2.8, Discussion Paper Topic D §3.1 Option A).
	DisclosurePolicy *EmbeddedDisclosurePolicy `json:"disclosure_policy,omitempty" yaml:"disclosure_policy,omitempty"`
}

CredentialConfigurationsSupported Object that describes specifics of the Credential that the Credential Issuer supports issuance of. https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-credential-issuer-metadata-p

type CredentialDefinition

type CredentialDefinition struct {
	// Type: REQUIRED. Array designating the types a certain Credential type supports, according to [VC_DATA], Section 4.3.
	Type []string `json:"type" yaml:"type" validate:"required"`

	// Context: REQUIRED for ldp_vc. Array as defined in [VC_DATA], Section 4.1.
	// Note: conditionally required — must be enforced at the application level based on format.
	Context []string `json:"@context,omitempty" yaml:"@context,omitempty"`
}

CredentialDefinition describes the Credential type for W3C VC formats (jwt_vc_json, ldp_vc). https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#appendix-A.1.1.2

type CredentialIssuerMetadataParameters

type CredentialIssuerMetadataParameters struct {
	// CredentialIssuer: REQUIRED. The Credential Issuer's identifier, as defined in Section 12.2.1.
	CredentialIssuer string `json:"credential_issuer" yaml:"credential_issuer" validate:"required"`

	// AuthorizationServers: OPTIONAL. A non-empty array of strings, where each string is an identifier of the OAuth 2.0 Authorization Server (as defined in [RFC8414]) the Credential Issuer relies on for authorization.
	AuthorizationServers []string `json:"authorization_servers,omitempty" yaml:"authorization_servers,omitempty"`

	// CredentialEndpoint: REQUIRED. URL of the Credential Issuer's Credential Endpoint, as defined in Section 8.2. This URL MUST use the https scheme and MAY contain port, path, and query parameter components.
	CredentialEndpoint string `json:"credential_endpoint" yaml:"credential_endpoint" validate:"required"`

	// NonceEndpoint: OPTIONAL. URL of the Credential Issuer's Nonce Endpoint, as defined in Section 7. This URL MUST use the https scheme and MAY contain port, path, and query parameter components. If omitted, the Credential Issuer does not require the use of c_nonce.
	NonceEndpoint string `json:"nonce_endpoint,omitempty" yaml:"nonce_endpoint,omitempty"`

	// DeferredCredentialEndpoint: OPTIONAL. URL of the Credential Issuer's Deferred Credential Endpoint, as defined in Section 9. This URL MUST use the https scheme and MAY contain port, path, and query parameter components. If omitted, the Credential Issuer does not support the Deferred Credential Endpoint.
	DeferredCredentialEndpoint string `json:"deferred_credential_endpoint,omitempty" yaml:"deferred_credential_endpoint,omitempty"`

	// NotificationEndpoint: OPTIONAL. URL of the Credential Issuer's Notification Endpoint, as defined in Section 11. This URL MUST use the https scheme and MAY contain port, path, and query parameter components. If omitted, the Credential Issuer does not support the Notification Endpoint.
	NotificationEndpoint string `json:"notification_endpoint,omitempty" yaml:"notification_endpoint,omitempty"`

	// CredentialResponseEncryption: OPTIONAL. Object containing information about whether the Credential Issuer supports encryption of the Credential Response on top of TLS.
	CredentialResponseEncryption *MetadataCredentialResponseEncryption `json:"credential_response_encryption,omitempty" yaml:"credential_response_encryption" validate:"omitempty"`

	// BatchCredentialIssuance: OPTIONAL. Object containing information about the Credential Issuer's support for batch issuance of Credentials on the Credential Endpoint.
	BatchCredentialIssuance *BatchCredentialIssuance `json:"batch_credential_issuance,omitempty" yaml:"batch_credential_issuance,omitempty"`

	// Display: OPTIONAL. A non-empty array of objects, where each object contains display properties of a Credential Issuer for a certain language.
	Display []MetadataDisplay `json:"display,omitempty" yaml:"display,omitempty"`

	// Claims: OPTIONAL.
	Claims []ClaimDescription `json:"claims,omitempty" yaml:"claims,omitempty"`

	// SignedMetadata: OPTIONAL. A JWT that contains Credential Issuer metadata parameters as claims.
	SignedMetadata string `json:"signed_metadata,omitempty" yaml:"signed_metadata,omitempty"`

	// CredentialConfigurationsSupported: REQUIRED. Object that describes specifics of the Credential that the Credential Issuer supports issuance of. This object contains a list of name/value pairs, where each name is a unique identifier of the supported Credential being described.
	CredentialConfigurationsSupported map[string]CredentialConfigurationsSupported `json:"credential_configurations_supported" yaml:"credential_configurations_supported" validate:"required"`

	// MdocIacasURI: OPTIONAL. URL of the endpoint where the Credential Issuer publishes
	// its IACA (Issuing Authority Certificate Authority) certificates for mDOC verification.
	// Used by verifiers to dynamically fetch trust anchors for ISO 18013-5 mDOC credentials.
	MdocIacasURI string `json:"mdoc_iacas_uri,omitempty" yaml:"mdoc_iacas_uri,omitempty"`
}

CredentialIssuerMetadataParameters https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-credential-issuer-metadata-p

func (*CredentialIssuerMetadataParameters) MarshalJWTClaims added in v0.6.0

func (c *CredentialIssuerMetadataParameters) MarshalJWTClaims() (jwt.MapClaims, error)

func (*CredentialIssuerMetadataParameters) MetadataIssuer added in v0.6.0

func (c *CredentialIssuerMetadataParameters) MetadataIssuer() string

MetadataIssuer returns the issuer identifier embedded in the metadata (credential_issuer), used to verify it matches the request's iss claim.

func (*CredentialIssuerMetadataParameters) Sign

Sign creates a signed JWT representation of the metadata and sets the signed_metadata field. Per OID4VCI 1.0 Section 12.2.4, signed_metadata is an OPTIONAL JWT that contains the Credential Issuer metadata parameters as claims, using typ "openidvci-issuer-metadata+jwt".

type CredentialMetadata

type CredentialMetadata struct {
	// Display: OPTIONAL. A non-empty array of objects, where each object contains the display properties of the supported Credential for a certain language.
	Display []CredentialMetadataDisplay `json:"display,omitempty" yaml:"display,omitempty"`

	// Claims: OPTIONAL. A non-empty array of claims description objects as defined in Appendix B.2.
	Claims []ClaimDescription `json:"claims,omitempty" yaml:"claims,omitempty"`
}

CredentialMetadata contains information relevant to the usage and display of issued Credentials. https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-credential-issuer-metadata-p

type CredentialMetadataDisplay

type CredentialMetadataDisplay struct {
	// Name: REQUIRED. String value of a display name for the Credential.
	Name string `json:"name" yaml:"name" validate:"required"`

	// Locale: OPTIONAL. String value that identifies the language of this object represented as a language tag taken from values defined in BCP47 [RFC5646]. Multiple display objects MAY be included for separate languages. There MUST be only one object for each language identifier.
	Locale string `json:"locale,omitempty" yaml:"locale,omitempty" validate:"bcp47_language_tag"`

	// Description: OPTIONAL. String value of a description of the Credential.
	Description string `json:"description,omitempty" yaml:"description,omitempty"`

	// BackgroundColor: OPTIONAL. String value of a background color of the Credential represented as numerical color values defined in CSS Color Module Level 37 [CSS-Color].
	BackgroundColor string `json:"background_color,omitempty" yaml:"background_color,omitempty"`

	Logo *MetadataLogo `json:"logo,omitempty" yaml:"logo,omitempty"`

	// BackgroundImage: OPTIONAL. Object with information about the background image of the Credential. At least the following parameter MUST be included:
	BackgroundImage *MetadataBackgroundImage `json:"background_image,omitempty" yaml:"background_image,omitempty"`
	// TextColor: OPTIONAL. String value of a text color of the Credential represented as numerical color values defined in CSS Color Module Level 37 [CSS-Color].
	TextColor string `json:"text_color,omitempty" yaml:"text_color,omitempty"`

	// Rendering: OPTIONAL
	Rendering *MetadataRendering `json:"rendering,omitempty" yaml:"rendering,omitempty"`
}

CredentialMetadataDisplay displays properties of the supported Credential for a certain language.

type CredentialOffer

type CredentialOffer string

CredentialOffer URI

func (*CredentialOffer) QR

func (c *CredentialOffer) QR(recoveryLevel, size int, walletURL string) (*QR, error)

QR returns a base64 encoded QR code, for convenience not part of the spec

func (*CredentialOffer) String

func (c *CredentialOffer) String() string

func (*CredentialOffer) Unpack

Unpack unpacks the CredentialOffer string into a CredentialOfferParameters

type CredentialOfferParameters

type CredentialOfferParameters struct {
	CredentialIssuer           string         `json:"credential_issuer" bson:"credential_issuer" validate:"required"`
	CredentialConfigurationIDs []string       `json:"credential_configuration_ids" bson:"credential_configuration_ids" validate:"required"`
	Grants                     map[string]any `json:"grants"`
}

CredentialOfferParameters https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-credential-offer-parameters

func ParseCredentialOfferURI

func ParseCredentialOfferURI(credentialOfferURI string) (*CredentialOfferParameters, error)

ParseCredentialOfferURI parses a credential offer URI to a CredentialOfferParameters

func (*CredentialOfferParameters) CredentialOffer

func (c *CredentialOfferParameters) CredentialOffer() (CredentialOffer, error)

CredentialOffer creates a credential offer

Example
package main

import (
	"fmt"

	"github.com/SUNET/vc/pkg/openid4vci"
)

func main() {
	offer := &openid4vci.CredentialOfferParameters{ // #nosec G101
		CredentialIssuer:           "https://issuer.example.com",
		CredentialConfigurationIDs: []string{"IdentityCredential"},
	}

	credOffer, err := offer.CredentialOffer()
	if err != nil {
		fmt.Println("error:", err)
		return
	}

	// The credential offer is a URL-encoded string containing the JSON
	s := credOffer.String()
	fmt.Println("starts with credential_offer:", s[:17] == "credential_offer=")
}
Output:
starts with credential_offer: true

func (*CredentialOfferParameters) Marshal

func (c *CredentialOfferParameters) Marshal() ([]byte, error)

Marshal marshals the CredentialOffer

Example
package main

import (
	"encoding/json"
	"fmt"

	"github.com/SUNET/vc/pkg/openid4vci"
)

func main() {
	offer := &openid4vci.CredentialOfferParameters{ // #nosec G101
		CredentialIssuer:           "https://issuer.example.com",
		CredentialConfigurationIDs: []string{"UniversityDegree_LDP_VC"},
		Grants: map[string]any{
			"authorization_code": openid4vci.GrantAuthorizationCode{
				IssuerState: "eyJhbGciOiJSU0Et",
			},
		},
	}

	data, err := offer.Marshal()
	if err != nil {
		fmt.Println("error:", err)
		return
	}

	// Parse back to verify structure
	var parsed map[string]any
	if err := json.Unmarshal(data, &parsed); err != nil {
		fmt.Println("error:", err)
		return
	}

	fmt.Println("credential_issuer:", parsed["credential_issuer"])
	ids := parsed["credential_configuration_ids"].([]any)
	fmt.Println("credential_configuration_ids:", ids[0])
}
Output:
credential_issuer: https://issuer.example.com
credential_configuration_ids: UniversityDegree_LDP_VC

type CredentialOfferResult added in v0.5.10

type CredentialOfferResult struct {
	CredentialOfferParameters
	ID string `json:"-"`
}

CredentialOfferResult wraps a credential offer with its pre-authorized code.

func NewCredentialOffer added in v0.5.10

func NewCredentialOffer(issuerURL, credentialConfigID, grantType string) (*CredentialOfferResult, error)

NewCredentialOffer creates an OpenID4VCI credential offer for the given grant type. Supported grant types: GrantTypePreAuthorizedCode, GrantTypeAuthorizationCode.

type CredentialOfferURI

type CredentialOfferURI string

func (*CredentialOfferURI) QR

func (c *CredentialOfferURI) QR(recoveryLevel, size int, walletURL, issuerURL string) (*QR, error)

func (*CredentialOfferURI) String

func (c *CredentialOfferURI) String() string

func (*CredentialOfferURI) UUID

func (c *CredentialOfferURI) UUID() (string, error)

type CredentialOfferURIRequest

type CredentialOfferURIRequest struct {
	CredentialOfferUUID string `uri:"credential_offer_uuid" binding:"required" validate:"required,max=128,printascii"`
}

type CredentialOfferURIResponse

type CredentialOfferURIResponse struct{}

type CredentialRequest

type CredentialRequest struct {
	// Header fields
	DPoP          string `header:"dpop" validate:"required"`
	Authorization string `header:"Authorization" validate:"required"`

	// CredentialIdentifier REQUIRED when an Authorization Details of type openid_credential was returned
	// from the Token Response. It MUST NOT be used otherwise. A string that identifies a Credential Dataset
	// that is requested for issuance. When this parameter is used, the credential_configuration_id MUST NOT be present.
	CredentialIdentifier string `` /* 132-byte string literal not displayed */

	// CredentialConfigurationID REQUIRED if a credential_identifiers parameter was not returned from
	// the Token Response as part of the authorization_details parameter. It MUST NOT be used otherwise.
	// String that uniquely identifies one of the keys in the name/value pairs stored in the
	// credential_configurations_supported Credential Issuer metadata. When this parameter is used,
	// the credential_identifier MUST NOT be present.
	CredentialConfigurationID string `` /* 128-byte string literal not displayed */

	// Proofs OPTIONAL. Object providing one or more proof of possessions of the cryptographic key material
	// to which the issued Credential instances will be bound to. The proofs parameter contains exactly one
	// parameter named as the proof type in Appendix F, the value set for this parameter is a non-empty array
	// containing parameters as defined by the corresponding proof type.
	// "Exactly one proof type" is enforced in Validate() below, not via a
	// struct tag: the go-playground/validator custom validation function
	// registered for this used to be named "single_proof_type", but it was
	// never actually being invoked here (confirmed live with a canary panic
	// that never fired) for reasons not tracked down within the time spent
	// investigating -- moving the check to Validate(), which already runs
	// reliably for this request, sidesteps whatever is wrong with the
	// struct-tag path rather than leaving proof-type-count unchecked.
	Proofs *Proofs `json:"proofs,omitempty" validate:"omitempty"`

	// Proof OPTIONAL. Single proof object for non-batch requests.
	// Deprecated: Use Proofs instead. This field is kept for backward compatibility with older wallets.
	Proof *Proof `json:"proof,omitempty" validate:"omitempty"`

	// CredentialResponseEncryption OPTIONAL. Object containing information for encrypting the Credential Response.
	// If this request element is not present, the corresponding credential response returned is not encrypted.
	CredentialResponseEncryption *CredentialResponseEncryption `json:"credential_response_encryption,omitempty" validate:"omitempty"`
}

CredentialRequest https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-credential-request

func (*CredentialRequest) HashAuthorizeToken

func (c *CredentialRequest) HashAuthorizeToken() string

HashAuthorizeToken hashes the Authorization header using SHA-256 and encodes it in Base64 URL format.

func (*CredentialRequest) IsAccessTokenDPoP

func (c *CredentialRequest) IsAccessTokenDPoP() bool

IsAccessTokenDPoP checks if the Authorization header belongs to DPoP proof

func (*CredentialRequest) ResolveCredentialFormat deprecated

func (req *CredentialRequest) ResolveCredentialFormat(metadata *CredentialIssuerMetadataParameters) (string, error)

ResolveCredentialFormat determines the credential format from the request. According to OpenID4VCI spec, the format is derived from the credential_configuration_id which maps to a credential configuration in the issuer metadata.

Deprecated: Use ResolveCredentialFormatWithAuthDetails for credential_identifier support.

func (*CredentialRequest) ResolveCredentialFormatWithAuthDetails added in v0.6.1

func (req *CredentialRequest) ResolveCredentialFormatWithAuthDetails(metadata *CredentialIssuerMetadataParameters, authorizationDetails []AuthorizationDetailsParameter) (string, error)

ResolveCredentialFormatWithAuthDetails determines the credential format from the request. When credential_identifier is used, the authorizationDetails from the token response are needed to map the identifier to a credential_configuration_id.

func (*CredentialRequest) Validate

func (c *CredentialRequest) Validate(ctx context.Context, authorizationDetails []AuthorizationDetailsParameter) error

Validate validates the CredentialRequest against the authorization details per OID4VCI 1.0 Section 7.1. When authorization_details with credential_identifiers was returned in the Token Response, the Credential Request MUST use credential_identifier (matching one of the returned identifiers). Otherwise, credential_configuration_id MUST be used.

func (*CredentialRequest) VerifyProof

func (c *CredentialRequest) VerifyProof(publicKey crypto.PublicKey) error

VerifyProof verifies the key proof according to OpenID4VCI 1.0 Appendix F.4 https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-verifying-proof

To validate a key proof, the Credential Issuer MUST ensure that: - all required claims for that proof type are contained - the key proof is explicitly typed using header parameters - the header parameter indicates a registered asymmetric digital signature algorithm, not "none" - the signature on the key proof verifies with the public key - the header parameter does not contain a private key - if the server has a Nonce Endpoint, the nonce matches the server-provided c_nonce - the creation time is within an acceptable window

func (*CredentialRequest) VerifyProofWithOptions

func (c *CredentialRequest) VerifyProofWithOptions(publicKey crypto.PublicKey, opts *VerifyProofOptions) error

VerifyProofWithOptions verifies the key proof with additional options. Supports jwt, di_vp, and attestation proof types as defined in the OpenID4VCI spec.

type CredentialResponse

type CredentialResponse struct {
	// Credentials OPTIONAL. Contains an array of issued Credentials. It MUST NOT be used if credential or transaction_id parameter is present. The values in the array MAY be a string or an object, depending on the Credential Format. See Appendix A for the Credential Format-specific encoding requirements.
	Credentials []Credential `json:"credentials,omitempty" validate:"required_without=TransactionID Credential"`

	// TransactionID: OPTIONAL. String identifying a Deferred Issuance transaction. This claim is contained in the response if the Credential Issuer was unable to immediately issue the Credential. The value is subsequently used to obtain the respective Credential with the Deferred Credential Endpoint (see Section 9). It MUST be present when the credential parameter is not returned. It MUST be invalidated after the Credential for which it was meant has been obtained by the Wallet.
	TransactionID string `json:"transaction_id,omitempty" validate:"required_without=Credentials Credential"`

	// CNonce: OPTIONAL. String containing a nonce to be used to create a proof of possession of key material when requesting a Credential (see Section 7.2). When received, the Wallet MUST use this nonce value for its subsequent Credential Requests until the Credential Issuer provides a fresh nonce.
	CNonce string `json:"c_nonce,omitempty"`

	// CNonceExpiresIn: OPTIONAL. Number denoting the lifetime in seconds of the c_nonce.
	CNonceExpiresIn int `json:"c_nonce_expires_in,omitempty"`

	// NotificationID: OPTIONAL. String identifying an issued Credential that the Wallet includes in the Notification Request as defined in Section 10.1. This parameter MUST NOT be present if credential parameter is not present.
	NotificationID string `json:"notification_id,omitempty" validate:"required_with=Credentials"`
}

CredentialResponse https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-credential-response

type CredentialResponseEncryption

type CredentialResponseEncryption struct {
	// JWK REQUIRED. Object containing a single public key as a JWK used for encrypting the Credential Response.
	JWK JWK `json:"jwk" validate:"required"`

	// Enc REQUIRED. JWE enc algorithm for encrypting Credential Responses.
	Enc string `json:"enc" validate:"required"`

	// Zip OPTIONAL. JWE zip algorithm for compressing Credential Responses prior to encryption.
	// If absent then compression MUST not be used.
	Zip string `json:"zip,omitempty"`
}

CredentialResponseEncryption contains information for encrypting the Credential Response. https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-credential-request

type DIVPProof

type DIVPProof struct {
	// Type is the proof type, e.g., "DataIntegrityProof"
	Type string `json:"type" validate:"required"`

	// Cryptosuite identifies the cryptographic suite used
	// Supported: eddsa-rdfc-2022, ecdsa-rdfc-2019, ecdsa-sd-2023, eddsa-jcs-2022, ecdsa-jcs-2019
	Cryptosuite string `json:"cryptosuite" validate:"required,oneof=eddsa-rdfc-2022 ecdsa-rdfc-2019 ecdsa-sd-2023 eddsa-jcs-2022 ecdsa-jcs-2019"`

	// ProofPurpose MUST be "authentication" for OpenID4VCI
	ProofPurpose string `json:"proofPurpose" validate:"required,eq=authentication"`

	// VerificationMethod is a URL that identifies the public key to use for verification
	VerificationMethod string `json:"verificationMethod" validate:"required"`

	// Domain MUST be the Credential Issuer Identifier
	Domain string `json:"domain" validate:"required"`

	// Challenge MUST be the c_nonce value provided by the Credential Issuer (when provided)
	Challenge string `json:"challenge,omitempty"`

	// Created is the creation time of the proof
	Created string `json:"created,omitempty"`

	// ProofValue is the actual proof signature value
	ProofValue string `json:"proofValue" validate:"required"`
}

DIVPProof represents a Data Integrity Proof https://www.w3.org/TR/vc-data-integrity/

type DeferredCredentialRequest

type DeferredCredentialRequest struct {
	TransactionID string `json:"transaction_id" validate:"required"`
}

DeferredCredentialRequest https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-deferred-credential-request

type EmbeddedDisclosurePolicy added in v0.7.0

type EmbeddedDisclosurePolicy struct {
	// PolicyType identifies the disclosure policy type. One of:
	//   - "none": no policy applies (default)
	//   - "authorized_relying_parties": only RPs in the allowlist may receive this attestation
	//   - "specific_root_of_trust": only RPs with access certificates from specific roots may receive this attestation
	PolicyType string `` /* 133-byte string literal not displayed */

	// AuthorizedRelyingParties is a list of EU-wide unique Relying Party identifiers
	// (as found in the Wallet-Relying Party Registration Certificate).
	// Required when policy_type is "authorized_relying_parties".
	AuthorizedRelyingParties []string `` /* 162-byte string literal not displayed */

	// TrustedRoots is a list of root or intermediate certificate SHA-256 fingerprints
	// (hex-encoded, 64 characters) from which the RP's access certificate must be derived.
	// Required when policy_type is "specific_root_of_trust".
	TrustedRoots []string `` /* 151-byte string literal not displayed */
}

EmbeddedDisclosurePolicy defines rules indicating the conditions a wallet-relying party must meet to access an electronic attestation of attributes. Per CIR 2024/2979 Annex III, three common policy types are defined.

type Error

type Error struct {
	Err              string `json:"error"`
	ErrorDescription any    `json:"error_description,omitempty"`
}

Error is the error response

func (*Error) Error

func (e *Error) Error() string
Example
package main

import (
	"fmt"

	"github.com/SUNET/vc/pkg/openid4vci"
)

func main() {
	err := &openid4vci.Error{
		Err:              openid4vci.ErrInvalidProof,
		ErrorDescription: "proof JWT is expired",
	}

	fmt.Println(err.Error())
}
Output:
invalid_proof: proof JWT is expired

type GrantAuthorizationCode

type GrantAuthorizationCode struct {
	IssuerState         string `json:"issuer_state" bson:"issuer_state"`
	AuthorizationServer string `json:"authorization,omitempty" bson:"authorization_server,omitempty"`
}

GrantAuthorizationCode authorization code grant

type GrantPreAuthorizedCode

type GrantPreAuthorizedCode struct {
	PreAuthorizedCode   string  `json:"pre-authorized_code" bson:"pre-authorized_code" validate:"required"`
	TXCode              *TXCode `json:"tx_code,omitempty" bson:"tx_code,omitempty"`
	AuthorizationServer string  `json:"authorization_server,omitempty" bson:"authorization_server,omitempty"`
}

GrantPreAuthorizedCode authorization code grant

type JWK

type JWK struct {
	CRV string `json:"crv" validate:"required"`
	KID string `json:"kid" validate:"required"`
	KTY string `json:"kty" validate:"required"`
	X   string `json:"x" validate:"required"`
	Y   string `json:"y" validate:"required"`
}

JWK holds the JSON Web Key

type KeyAttestationRequirement added in v0.7.1

type KeyAttestationRequirement struct {
	KeyStorage                      []string `json:"key_storage,omitempty" yaml:"key_storage,omitempty"`
	UserAuthentication              []string `json:"user_authentication,omitempty" yaml:"user_authentication,omitempty"`
	PreferredKeyStorageStatusPeriod *int     `json:"preferred_key_storage_status_period,omitempty" yaml:"preferred_key_storage_status_period,omitempty"`
}

KeyAttestationRequirement describes constraints the Wallet's key attestation must satisfy for a given proof type. All fields are optional; a zero value serializes to `{}`, meaning "attestation metadata present, no constraints declared" -- see ProofsTypesSupported.KeyAttestationsRequired.

type MetadataBackgroundImage

type MetadataBackgroundImage struct {
	// URI REQUIRED. String value that contains a URI where the Wallet can obtain the background image of the Credential from the Credential Issuer. The Wallet needs to determine the scheme, since the URI value could use the https: scheme, the data: scheme, etc.
	URI string `json:"uri" yaml:"uri" validate:"required"`
}

MetadataBackgroundImage contains information about the background image of the Credential

type MetadataConfig

type MetadataConfig struct {
	KeyConfig                            *pki.KeyConfig
	CredentialIssuer                     string
	CredentialEndpoint                   string
	NonceEndpoint                        string
	AuthorizationServers                 []string
	DeferredCredentialEndpoint           string
	NotificationEndpoint                 string
	CryptographicBindingMethodsSupported []string
	CredentialSigningAlgValuesSupported  []string
	ProofSigningAlgValuesSupported       []string
	CredentialResponseEncryption         *MetadataCredentialResponseEncryption
	BatchCredentialIssuance              *BatchCredentialIssuance
	Display                              []MetadataDisplay
	Claims                               []ClaimDescription
	CredentialConfigurationsSupported    map[string]CredentialConfigurationsSupported
	MdocIacasURI                         string
}

MetadataConfig holds the configuration parameters needed to generate and sign issuer metadata

func (*MetadataConfig) GenerateIssuerMetadata

func (cfg *MetadataConfig) GenerateIssuerMetadata(ctx context.Context) *CredentialIssuerMetadataParameters

GenerateIssuerMetadata creates issuer metadata from configuration. Returns unsigned metadata that should be signed on-demand in the endpoint handler for freshness.

type MetadataCredentialResponseEncryption

type MetadataCredentialResponseEncryption struct {
	// AlgValuesSupported: REQUIRED. Array containing a list of the JWE [RFC7516] encryption algorithms (alg values) [RFC7518] supported by the Credential and Batch Credential Endpoint to encode the Credential or Batch Credential Response in a JWT [RFC7519].
	AlgValuesSupported []string `json:"alg_values_supported" yaml:"alg_values_supported" validate:"required"`

	// EncValuesSupported: REQUIRED. Array containing a list of the JWE [RFC7516] encryption algorithms (enc values) [RFC7518] supported by the Credential and Batch Credential Endpoint to encode the Credential or Batch Credential Response in a JWT [RFC7519].
	EncValuesSupported []string `json:"enc_values_supported" yaml:"enc_values_supported" validate:"required"`

	// EncryptionRequired: REQUIRED. Boolean value specifying whether the Credential Issuer requires the additional encryption on top of TLS for the Credential Response. If the value is true, the Credential Issuer requires encryption for every Credential Response and therefore the Wallet MUST provide encryption keys in the Credential Request. If the value is false, the Wallet MAY chose whether it provides encryption keys or not.
	EncryptionRequired bool `json:"encryption_required" yaml:"encryption_required"`
}

MetadataCredentialResponseEncryption Object containing information about whether the Credential Issuer supports encryption of the Credential and Batch Credential Response on top of TLS.

type MetadataDisplay

type MetadataDisplay struct {
	// Name: OPTIONAL. String value of a display name for the Credential Issuer.
	Name string `json:"name,omitempty" yaml:"name,omitempty"`

	// Locale: OPTIONAL. String value that identifies the language of this object represented as a language tag taken from values defined in BCP47 [RFC5646]. There MUST be only one object for each language identifier.
	Locale string `json:"locale,omitempty" yaml:"locale,omitempty" validate:"bcp47_language_tag"`

	Logo *MetadataLogo `json:"logo,omitempty" yaml:"logo,omitempty"`
}

MetadataDisplay contains display properties of a Credential Issuer for a certain language. Below is a non-exhaustive list of valid parameters that MAY be included:

type MetadataLogo struct {
	// URI: REQUIRED. String value that contains a URI where the Wallet can obtain the logo of the Credential Issuer. The Wallet needs to determine the scheme, since the URI value could use the https: scheme, the data: scheme, etc.
	URI string `json:"uri" yaml:"uri" validate:"required"`

	// AltText: OPTIONAL. String value of the alternative text for the logo image.
	AltText string `json:"alt_text,omitempty" yaml:"alt_text,omitempty"`
}

MetadataLogo object with information about the logo of the Credential Issuer. Below is a non-exhaustive list of parameters that MAY be included:

type MetadataRendering added in v0.7.0

type MetadataRendering struct {
	// Simple: OPTIONAL. Object containing simple rendering information, such as a logo.
	Simple *MetadataSimpleRendering `json:"simple,omitempty" yaml:"simple,omitempty"`

	// SvgTemplates: OPTIONAL. A non-empty array of SVG template objects used to render the Credential.
	SvgTemplates []MetadataSvgTemplate `json:"svg_templates,omitempty" yaml:"svg_templates,omitempty"`
}

MetadataRendering contains rendering information for a Credential Issuer or Credential, as defined in ISO/IEC 18013-5 and referenced by OpenID4VCI mdoc rendering extensions.

type MetadataSimpleRendering added in v0.7.0

type MetadataSimpleRendering struct {
	Logo *MetadataLogo `json:"logo,omitempty" yaml:"logo,omitempty"`
}

MetadataSimpleRendering contains simple (non-SVG) rendering information.

type MetadataSvgTemplate added in v0.7.0

type MetadataSvgTemplate struct {
	// URI: REQUIRED. String value that contains a URI where the Wallet can obtain the SVG template.
	URI string `json:"uri" yaml:"uri" validate:"required"`

	// URIIntegrity: OPTIONAL. Subresource integrity hash (e.g. "sha256-...") of the SVG template,
	// allowing the Wallet to verify the integrity of the fetched resource.
	URIIntegrity string `json:"uri#integrity,omitempty" yaml:"uri_integrity,omitempty"`

	// Properties: OPTIONAL. Object describing the rendering properties this template is suited for,
	// such as orientation, color scheme, and contrast.
	Properties *MetadataSvgTemplateProperties `json:"properties,omitempty" yaml:"properties,omitempty"`
}

MetadataSvgTemplate describes a single SVG template used to render a Credential.

type MetadataSvgTemplateProperties added in v0.7.0

type MetadataSvgTemplateProperties struct {
	// Orientation: OPTIONAL. String value, e.g. "portrait" or "landscape".
	Orientation string `json:"orientation,omitempty" yaml:"orientation,omitempty"`

	// ColorScheme: OPTIONAL. String value, e.g. "light" or "dark".
	ColorScheme string `json:"color_scheme,omitempty" yaml:"color_scheme,omitempty"`

	// Contrast: OPTIONAL. String value, e.g. "normal" or "high".
	Contrast string `json:"contrast,omitempty" yaml:"contrast,omitempty"`
}

MetadataSvgTemplateProperties describes the rendering context an SVG template is intended for.

type NonceResponse

type NonceResponse struct {
	CNonce string `json:"c_nonce"`
}

NonceResponse https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-nonce-response

type NotificationRequest

type NotificationRequest struct {
	NotificationID   string `json:"notification_id" validate:"required"`
	Event            string `json:"event" validate:"required,oneof=credential_accepted credential_failure credential_deleted"`
	EventDescription string `json:"event_description,omitempty"`
}

NotificationRequest https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0-ID1.html#name-notification-request

type PARRequest

type PARRequest struct {
	// RFC 6749#4.1.1
	ResponseType string `form:"response_type" json:"response_type" validate:"required,oneof=code"`
	ClientID     string `json:"client_id" form:"client_id" validate:"required"`
	RedirectURI  string `json:"redirect_uri" form:"redirect_uri" validate:"required"`
	Scope        string `json:"scope" form:"scope"`
	State        string `json:"state" form:"state"`

	Prompt               string                          `json:"prompt" form:"prompt"`
	AuthorizationDetails []AuthorizationDetailsParameter `json:"authorization_details" form:"authorization_details"`
	CodeChallenge        string                          `json:"code_challenge" form:"code_challenge" validate:"required"`
	CodeChallengeMethod  string                          `json:"code_challenge_method" form:"code_challenge_method" validate:"required,oneof=S256 plain"`

	// https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-additional-request-paramete
	WalletIssuer string `json:"wallet_issuer" form:"wallet_issuer"`
	UserHint     string `json:"user_hint" form:"user_hint"`
	IssuingState string `json:"issuing_state" form:"issuing_state"`

	// Client authentication via wallet attestation.
	// Supports two mechanisms per draft-ietf-oauth-attestation-based-client-auth-04:
	//  1. HTTP headers: OAuth-Client-Attestation + OAuth-Client-Attestation-PoP (§3.1)
	//  2. Form body: client_assertion + client_assertion_type (legacy, deprecated)
	// The standard-compliant mechanism (1) takes precedence.
	ClientAttestation    string `json:"-" form:"-" header:"OAuth-Client-Attestation"`
	ClientAttestationPoP string `json:"-" form:"-" header:"OAuth-Client-Attestation-PoP"`
	ClientAssertion      string `json:"client_assertion" form:"client_assertion" validate:"omitempty,max=8192,printascii"`
	ClientAssertionType  string `json:"client_assertion_type" form:"client_assertion_type" validate:"omitempty,max=256,printascii"`
}

PARRequest https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#RFC6749

func BindAuthorizationRequest

func BindAuthorizationRequest(body io.ReadCloser) (*PARRequest, error)

BindAuthorizationRequest binds the AuthorizationRequest

type ParResponse

type ParResponse struct {
	// RequestURI : The request URI corresponding to the authorization request posted. This URI is used as reference to the respective request data in the subsequent authorization request only. The way the authorization process obtains the authorization request data is at the discretion of the authorization server and out of scope of this specification. There is no need to make the authorization request data available to other parties via this URI.
	RequestURI string `json:"request_uri" form:"request_uri" validate:"required"`

	// ExpiresIn : A JSON number that represents the lifetime of the request URI in seconds. The request URI lifetime is at the discretion of the authorization server and will typically be relatively short.
	ExpiresIn int `json:"expires_in" form:"expires_in" validate:"required"`
}

type Proof

type Proof struct {
	// ProofType REQUIRED. String denoting the key proof type.
	ProofType string `json:"proof_type" validate:"required"`

	// JWT The JWT proof, when proof_type is "jwt"
	JWT string `json:"jwt,omitempty"`

	// CWT The CWT proof, when proof_type is "cwt"
	CWT string `json:"cwt,omitempty"`

	// LDPVp The Linked Data Proof VP, when proof_type is "ldp_vp"
	LDPVp any `json:"ldp_vp,omitempty"`
}

Proof represents a single proof object (used in non-batch requests) https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-proof-types

func (*Proof) ExtractJWK

func (p *Proof) ExtractJWK() (*apiv1_issuer.Jwk, error)

ExtractJWK extracts the holder's public key from the proof

func (*Proof) ExtractSubjectDID

func (p *Proof) ExtractSubjectDID() string

ExtractSubjectDID extracts the subject DID from the proof if available. For JWT proofs, this would typically come from the JWT claims. Returns empty string if no subject DID is found.

type ProofAttestation

type ProofAttestation string

ProofAttestation represents a Key Attestation JWT proof as defined in OpenID4VCI 1.0 Appendix D.1 https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-key-attestation

func (ProofAttestation) ExtractAllJWKs added in v0.7.0

func (p ProofAttestation) ExtractAllJWKs(maxLength int) ([]*apiv1_issuer.Jwk, error)

ExtractAllJWKs extracts all attested keys from the attestation JWT. The attested_keys claim contains an array of JWKs; this returns all of them. maxLength limits the number of keys that can be extracted to prevent abuse. It must be at least 1.

func (ProofAttestation) ExtractJWK

func (p ProofAttestation) ExtractJWK() (*apiv1_issuer.Jwk, error)

ExtractJWK extracts the first attested key (JWK) from the attestation JWT. The attested_keys claim contains an array of JWKs that are attested by this proof.

func (ProofAttestation) ExtractNonce added in v0.7.1

func (p ProofAttestation) ExtractNonce() string

ExtractNonce extracts the nonce claim from the attestation JWT without verifying signature, mirroring ProofJWTToken.ExtractNonce. Needed because handlers_issuer.go's nonce resolution previously only looked at Proofs.JWT, so a credential request using the "attestation" proof type (which the EUDI reference wallet's pinned openid4vci-kt actually sends when metadata declares attestation support, lpidproto PLAN.md workstream 7) fell back to the stale pre-auth-code nonce and failed Verify()'s own nonce check with "nonce claim does not match server-provided c_nonce".

func (ProofAttestation) Validate

func (p ProofAttestation) Validate() error

Validate parses and validates the Key Attestation JWT structure according to OpenID4VCI spec. This validates the header and claims structure without verifying the signature.

func (ProofAttestation) Verify

func (p ProofAttestation) Verify(opts *VerifyProofOptions) error

Verify verifies a Key Attestation proof according to OpenID4VCI 1.0 Appendix D.1 https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-key-attestation

This checks that the attestation JWT is validly signed by whoever holds the private key matching its own x5c leaf certificate -- the same self-consistency check ProofJWTToken.Verify does for JWT proofs -- using the JWT's own embedded certificate, not a trusted root. It does NOT establish that the attestation issuer identified by that certificate is itself trustworthy: this codebase has no trusted-attestation-issuer registry yet (a separate, larger effort, akin to the FIDO2 hardware-attestation trust work), so a self-issued or otherwise arbitrary certificate still passes. That said, this is a real improvement over accepting the proof with no signature check at all (the previous behavior, via ParseUnverified): forging attested_keys or claims now requires an actual private key and a certificate to match, not just well-formed JSON. A proof with no x5c header has no key material this server can resolve at all (there is no kid-based registry either), so it is rejected outright rather than silently accepted.

type ProofAttestationClaims

type ProofAttestationClaims struct {
	// Iss is the issuer of the attestation, OPTIONAL
	Iss string `json:"iss,omitempty"`

	// Iat is the issued at time, REQUIRED
	Iat int64 `json:"iat" validate:"required"`

	// Exp is the expiration time, OPTIONAL
	Exp int64 `json:"exp,omitempty"`

	// AttestedKeys is a non-empty array of attested JWKs, REQUIRED
	AttestedKeys []ProofJWK `json:"attested_keys" validate:"required,min=1,dive"`

	// Nonce is the c_nonce value, OPTIONAL but REQUIRED when issuer has Nonce Endpoint
	Nonce string `json:"nonce,omitempty"`

	// AttestationProcess describes the attestation process, OPTIONAL
	AttestationProcess string `json:"attestation_process,omitempty"`
}

ProofAttestationClaims represents the claims of a Key Attestation JWT (Appendix D.1)

type ProofAttestationHeader

type ProofAttestationHeader struct {
	// Alg is the algorithm used to sign the JWT, REQUIRED, must not be "none"
	Alg string `json:"alg" validate:"required,ne=none"`

	// Typ is the type of the JWT, REQUIRED, must be "key-attestation+jwt"
	Typ string `json:"typ" validate:"required,eq=key-attestation+jwt"`

	// Kid is the key ID of the attestation issuer's signing key
	Kid string `json:"kid,omitempty"`

	// X5c is the X.509 certificate chain of the attestation issuer
	X5c []string `json:"x5c,omitempty"`
}

ProofAttestationHeader represents the JOSE header of a Key Attestation JWT (Appendix D.1)

type ProofDIVP

type ProofDIVP struct {
	// Context is the JSON-LD context, REQUIRED per W3C VC Data Model
	Context []string `json:"@context" validate:"required,min=1"`

	// Type is the type of the presentation, REQUIRED, must include "VerifiablePresentation"
	Type []string `json:"type" validate:"required,min=1"`

	// Proof contains the Data Integrity Proof(s), one of Proof or Proofs REQUIRED
	Proof *DIVPProof `json:"proof,omitempty" validate:"required_without=Proofs"`

	// Proofs contains multiple Data Integrity Proofs if more than one is present
	Proofs []DIVPProof `json:"proofs,omitempty" validate:"required_without=Proof,dive"`

	// VerifiableCredential contains the credentials being presented
	VerifiableCredential []any `json:"verifiableCredential,omitempty"`

	// Holder is the DID of the holder
	Holder string `json:"holder,omitempty"`

	// ID is an optional identifier for the presentation
	ID string `json:"id,omitempty"`
}

ProofDIVP represents a W3C Verifiable Presentation with Data Integrity Proof as defined in OpenID4VCI 1.0 Appendix F.2 https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-di_vp-proof-type

func (*ProofDIVP) ExtractJWK

func (vp *ProofDIVP) ExtractJWK() (*apiv1_issuer.Jwk, error)

ExtractJWK extracts the holder's public key reference from the DI_VP proof. For DI_VP, the verificationMethod is typically a DID URL that needs external resolution. This method returns a JWK with the Kid set to the verificationMethod for external resolution.

func (*ProofDIVP) Validate

func (vp *ProofDIVP) Validate() error

Validate validates the ProofDIVP struct using validator tags.

func (*ProofDIVP) Verify

func (vp *ProofDIVP) Verify(opts *VerifyProofOptions) error

Verify verifies a Data Integrity Verifiable Presentation proof according to OpenID4VCI 1.0 Appendix F.2 https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-di_vp-proof-type

type ProofJWK

type ProofJWK struct {
	Kty string `json:"kty" validate:"required"`
	Crv string `json:"crv,omitempty"`
	X   string `json:"x,omitempty"`
	Y   string `json:"y,omitempty"`
	N   string `json:"n,omitempty"`
	E   string `json:"e,omitempty"`
	Kid string `json:"kid,omitempty"`
	Use string `json:"use,omitempty"`
	Alg string `json:"alg,omitempty"`
}

ProofJWK represents a JSON Web Key in a proof header

type ProofJWT

type ProofJWT struct {
	jwt.RegisteredClaims
}

ProofJWT holds the JWT for proof

type ProofJWTClaims

type ProofJWTClaims struct {
	// Aud is the audience, REQUIRED, must be the Credential Issuer Identifier
	Aud string `json:"aud" validate:"required"`

	// Iat is the issued at time, REQUIRED
	Iat int64 `json:"iat" validate:"required"`

	// Nonce is the c_nonce value, OPTIONAL but REQUIRED when issuer has Nonce Endpoint
	Nonce string `json:"nonce,omitempty"`

	// Iss is the issuer (client_id), OPTIONAL
	Iss string `json:"iss,omitempty"`
}

ProofJWTClaims represents the claims of a JWT proof (Appendix F.1)

type ProofJWTHeader

type ProofJWTHeader struct {
	// Alg is the algorithm used to sign the JWT, REQUIRED, must not be "none"
	Alg string `json:"alg" validate:"required,ne=none"`

	// Typ is the type of the JWT, REQUIRED, must be "openid4vci-proof+jwt"
	Typ string `json:"typ" validate:"required,eq=openid4vci-proof+jwt"`

	// Kid is the key ID, mutually exclusive with Jwk and X5c
	Kid string `json:"kid,omitempty" validate:"excluded_with=Jwk X5c"`

	// Jwk is the JSON Web Key, mutually exclusive with Kid and X5c
	Jwk *ProofJWK `json:"jwk,omitempty" validate:"excluded_with=Kid X5c"`

	// X5c is the X.509 certificate chain, mutually exclusive with Kid and Jwk
	X5c []string `json:"x5c,omitempty" validate:"excluded_with=Kid Jwk"`
}

ProofJWTHeader represents the JOSE header of a JWT proof (Appendix F.1)

type ProofJWTToken

type ProofJWTToken string

ProofJWTToken represents a JWT proof token as defined in OpenID4VCI 1.0 Appendix F.1 https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-jwt-proof-type

func (ProofJWTToken) ExtractJWK

func (p ProofJWTToken) ExtractJWK() (*apiv1_issuer.Jwk, error)

ExtractJWK extracts the holder's public key (JWK) from the JWT header. The key can be in the jwk, kid, or x5c header parameter.

func (ProofJWTToken) ExtractNonce added in v0.6.1

func (p ProofJWTToken) ExtractNonce() string

ExtractNonce extracts the nonce claim from the JWT proof without verifying signature.

func (ProofJWTToken) ExtractSubjectDID

func (p ProofJWTToken) ExtractSubjectDID() string

ExtractSubjectDID extracts the subject DID from the JWT claims. This looks for an "iss" (issuer) claim which in OpenID4VCI proof JWTs typically represents the holder's DID. Returns empty string if not found.

func (ProofJWTToken) Validate

func (p ProofJWTToken) Validate() error

Validate parses and validates the JWT structure according to OpenID4VCI spec. This validates the header and claims structure without verifying the signature.

func (ProofJWTToken) Verify

func (p ProofJWTToken) Verify(publicKey crypto.PublicKey, opts *VerifyProofOptions) error

Verify verifies a JWT proof according to OpenID4VCI 1.0 Appendix F.1 https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-jwt-proof-type

type Proofs

type Proofs struct {
	// JWT contains an array of JWTs as defined in Appendix F.1
	JWT []ProofJWTToken `json:"jwt,omitempty"`

	// DIVP contains an array of W3C Verifiable Presentations
	// signed using Data Integrity Proof as defined in Appendix F.2
	DIVP []ProofDIVP `json:"di_vp,omitempty"`

	// Attestation contains an array of JWTs representing key attestations
	// as defined in Appendix D.1. Confirmed as an array (not a bare string)
	// against the EUDI reference wallet's pinned eudi-lib-jvm-openid4vci-kt
	// (lpidproto PLAN.md workstream 7): it sends "attestation" with the same
	// array shape as "jwt", which this field previously rejected with a JSON
	// unmarshal error.
	Attestation []ProofAttestation `json:"attestation,omitempty"`
}

Proofs https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-credential-request Contains arrays of proofs by type for batch credential requests. Only one proof type should be used per request.

func (*Proofs) ExtractAllJWKs added in v0.7.0

func (p *Proofs) ExtractAllJWKs(maxLength int) ([]*apiv1_issuer.Jwk, error)

ExtractAllJWKs extracts one JWK per proof for batch credential issuance. For JWT and DIVP proof types, each proof in the array yields one JWK. For Attestation, all keys from the attested_keys claim are returned.

func (*Proofs) ExtractJWK

func (p *Proofs) ExtractJWK() (*apiv1_issuer.Jwk, error)

ExtractJWK extracts the holder's public key (JWK) from the proofs. It automatically detects which proof type is present and extracts accordingly: - jwt: from the jwk header of the first JWT - di_vp: from the verificationMethod of the first proof - attestation: from the attested_keys claim

func (*Proofs) ProofType added in v0.7.0

func (p *Proofs) ProofType() string

ProofType returns the proof type of the proofs contained in this struct.

type ProofsTypesSupported

type ProofsTypesSupported struct {
	// ProofSigningAlgValuesSupported: REQUIRED. Array of case sensitive strings that identify the algorithms that the Issuer supports for this proof type. The Wallet uses one of them to sign the proof. Algorithm names used are determined by the key proof type and are defined in Section 7.2.1.
	ProofSigningAlgValuesSupported []string `json:"proof_signing_alg_values_supported" yaml:"proof_signing_alg_values_supported" validate:"required"`

	// KeyAttestationsRequired: REQUIRED (per later OpenID4VCI drafts consumed by
	// eudi-lib-jvm-openid4vci-kt 0.12.1+, which hard-fails issuer metadata
	// validation without this field, and expects it to be a JSON object, not a
	// boolean -- confirmed by decompiling KeyAttestationRequirementTO in that
	// library). A zero-value KeyAttestationRequirement serializes to `{}`,
	// declaring no specific attestation constraints -- this project has no
	// Wallet Attestation / WSCD verification wired up yet (lpidproto PLAN.md
	// workstream 8, not yet started), so asserting real constraints here would
	// be dishonest. Revisit together with WS8 (production trust rollout).
	KeyAttestationsRequired KeyAttestationRequirement `json:"key_attestations_required" yaml:"key_attestations_required"`
}

ProofsTypesSupported Object that describes specifics of the key proof(s) that the Credential Issuer supports.

type QR

type QR struct {
	QRBase64           string `json:"qr_base64" bson:"qr_base64"`
	CredentialOfferURL string `json:"credential_offer_url" bson:"credential_offer_url"`
}

QR not part of the spec, for convenience

type TXCode

type TXCode struct {
	InputMode   string `json:"input_mode,omitempty" bson:"input_mode,omitempty" validate:"omitempty,oneof=numeric text"`
	Length      int    `json:"length,omitempty" bson:"length,omitempty"`
	Description string `json:"description,omitempty" bson:"description,omitempty"`
}

TXCode Transaction Code

type TokenRequest

type TokenRequest struct {
	// Header field
	DPOP string `header:"dpop"`

	// GrantType REQUIRED. "authorization_code", "urn:ietf:params:oauth:grant-type:pre-authorized_code", or "refresh_token".
	GrantType string `` /* 147-byte string literal not displayed */

	// Code REQUIRED for authorization_code grant. The authorization code received from the authorization server.
	Code string `form:"code" json:"code" validate:"required_if=GrantType authorization_code,omitempty,max=128,printascii"`

	// RedirectURI REQUIRED for authorization_code grant, if the "redirect_uri" parameter was included in the authorization request.
	RedirectURI string `form:"redirect_uri" json:"redirect_uri"`

	// ClientID REQUIRED for authorization_code grant when not using client assertion authentication (RFC 6749 §4.1.3).
	// When using private_key_jwt or client_secret_jwt, client_id is conveyed via the assertion's "sub" claim.
	// OPTIONAL for pre-authorized_code grant.
	ClientID string `form:"client_id" json:"client_id" validate:"omitempty,max=128,printascii"`

	// CodeVerifier OPTIONAL (required for public clients using authorization_code grant)
	CodeVerifier string `form:"code_verifier" json:"code_verifier"`

	// ClientAssertionType OPTIONAL. The type of client assertion. For private_key_jwt: "urn:ietf:params:oauth:client-assertion-type:jwt-bearer".
	ClientAssertionType string `form:"client_assertion_type" json:"client_assertion_type" validate:"omitempty,max=256,printascii"`

	// ClientAssertion OPTIONAL. The client assertion JWT for private_key_jwt or client_secret_jwt authentication.
	ClientAssertion string `form:"client_assertion" json:"client_assertion" validate:"omitempty,max=8192,printascii"`

	// Client attestation via HTTP headers (draft-ietf-oauth-attestation-based-client-auth-04 §3.1).
	ClientAttestation    string `json:"-" form:"-" header:"OAuth-Client-Attestation"`
	ClientAttestationPoP string `json:"-" form:"-" header:"OAuth-Client-Attestation-PoP"`

	// PreAuthorizedCode REQUIRED for pre-authorized_code grant. The code representing the authorization to obtain Credentials.
	PreAuthorizedCode string `` /* 168-byte string literal not displayed */

	// TXCode OPTIONAL. String value containing a Transaction Code.
	TXCode string `form:"tx_code" json:"tx_code"`

	// RefreshToken REQUIRED for refresh_token grant. The refresh token previously issued to the client.
	RefreshToken string `form:"refresh_token" json:"refresh_token" validate:"required_if=GrantType refresh_token,omitempty,max=256,printascii"`
}

TokenRequest https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-token-request

type TokenResponse

type TokenResponse struct {
	// AccessToken REQUIRED.  The access token issued by the authorization server.
	AccessToken string `json:"access_token" validate:"required"`

	// TokenType REQUIRED.  The type of the token issued as described in Section 7.1.  Value is case insensitive.
	TokenType string `json:"token_type" validate:"required"`

	// ExpiresIn RECOMMENDED.  The lifetime in seconds of the access token.  For example, the value "3600" denotes that the access token will expire in one hour from the time the response was generated. If omitted, the authorization server SHOULD provide the expiration time via other means or document the default value.
	ExpiresIn int `json:"expires_in" validate:"required"`

	// Scope OPTIONAL, if identical to the scope requested by the client; otherwise, REQUIRED.  The scope of the access token as described by Section 3.3.
	Scope string `json:"scope"`

	// State REQUIRED if the "state" parameter was present in the client authorization request.  The exact value received from the client.
	State string `json:"state"`

	// CNonce OPTIONAL. String containing a nonce to be used when creating a proof of possession of the key proof (see Section 7.2). When received, the Wallet MUST use this nonce value for its subsequent requests until the Credential Issuer provides a fresh nonce.
	CNonce string `json:"c_nonce"`

	// CNonceExpiresIn OPTIONAL. Number denoting the lifetime in seconds of the c_nonce.
	CNonceExpiresIn int `json:"c_nonce_expires_in"`

	// AuthorizationDetails REQUIRED when authorization_details parameter is used in either the Authorization Request or Token Request.
	// OPTIONAL when scope parameter was used to request issuance of a Credential. It MUST NOT be used otherwise.
	// It is a non-empty array of objects, as defined in Section 7 of [RFC9396].
	AuthorizationDetails []AuthorizationDetailsParameter `json:"authorization_details,omitempty"`

	// RefreshToken OPTIONAL. A refresh token bound to the DPoP key, allowing the client to obtain
	// fresh access tokens for credential re-issuance without full re-authentication.
	RefreshToken string `json:"refresh_token,omitempty"`

	// RefreshTokenExpiresIn OPTIONAL. Lifetime in seconds of the refresh token.
	RefreshTokenExpiresIn int `json:"refresh_token_expires_in,omitempty"`
}

TokenResponse https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-successful-token-response

type VerifyProofOptions

type VerifyProofOptions struct {
	// CNonce is the server-provided nonce value that must match the nonce in the proof
	// Required when the Credential Issuer has a Nonce Endpoint
	CNonce string
	// Audience is the expected Credential Issuer Identifier (required for aud validation)
	Audience string
	// SupportedAlgorithms is a list of supported signing algorithms
	SupportedAlgorithms []string
}

VerifyProofOptions contains optional parameters for proof verification

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL