Documentation
¶
Index ¶
- Constants
- Variables
- func BuildDirectPostURL(baseURL string, response *ResponseParameters) (string, error)
- func FilterStandardScopes(scopes []string) []string
- func GenerateQRV2(ctx context.Context, data string) (string, error)
- func GetClaimMappings(template PresentationRequestTemplate) map[string]string
- func IsMdocFormat(format string) bool
- func IsSDJWTFormatIdentifier(format string) bool
- func IsW3CVCFormatIdentifier(format string) bool
- func MatchCryptosuite(cryptosuite string, cryptosuiteValues []string) bool
- func MatchProofType(proofType string, proofTypeValues []string) bool
- func MatchTrustedAuthorities(trustedAuthorities []TrustedAuthority, credentialCertChain [][]byte, ...) bool
- func MatchTypeValues(credentialTypes []string, typeValues [][]string) bool
- func ValidateCredentialQuery(query CredentialQuery) error
- func ValidateVPToken(vpToken, nonce, clientID string) error
- type ClaimQuery
- type ClaimTransformDef
- type ClaimsExtractor
- func (ce *ClaimsExtractor) ApplyClaimTransforms(claims map[string]any, transformDefs map[string]ClaimTransformDef) (map[string]any, error)
- func (ce *ClaimsExtractor) ExtractAndMapClaims(ctx context.Context, vpToken string, claimMappings map[string]string, ...) (map[string]any, error)
- func (ce *ClaimsExtractor) ExtractClaimsFromVPToken(ctx context.Context, vpToken string) (map[string]any, error)
- func (ce *ClaimsExtractor) MapClaimsToOIDC(vpClaims map[string]any, claimMappings map[string]string) (map[string]any, error)
- type Client
- type ClientMetadata
- type Config
- type Constraints
- type CredentialQuery
- type CredentialSetQuery
- type DCQL
- type DCQLValidationError
- type Descriptor
- type DirectPostJWTResponse
- type DirectPostResponse
- type EphemeralEncryptionKeyCache
- func (e *EphemeralEncryptionKeyCache) Delete(kid string)
- func (e *EphemeralEncryptionKeyCache) GenerateAndStore(kid string) (privateKey jwk.Key, publicKey jwk.Key, err error)
- func (e *EphemeralEncryptionKeyCache) Get(kid string) (jwk.Key, bool)
- func (e *EphemeralEncryptionKeyCache) Len() int
- func (e *EphemeralEncryptionKeyCache) Set(kid string, key jwk.Key)
- func (e *EphemeralEncryptionKeyCache) SetWithTTL(kid string, key jwk.Key, ttl time.Duration)
- func (e *EphemeralEncryptionKeyCache) Stop()
- type ErrorResponse
- type Field
- type Filter
- type Format
- type InputDescriptor
- type JWK
- type JWTVCFormat
- type Keys
- type LDPVCFormat
- type MetaQuery
- type MsoMdocFormat
- type PresentationBuilder
- func (pb *PresentationBuilder) BuildDCQLQuery(ctx context.Context, scopes []string) (*DCQL, error)
- func (pb *PresentationBuilder) BuildFromScopes(ctx context.Context, scopes []string) (*DCQL, PresentationRequestTemplate, error)
- func (pb *PresentationBuilder) BuildFromTemplate(ctx context.Context, templateID string) (*DCQL, PresentationRequestTemplate, error)
- func (pb *PresentationBuilder) FindTemplateByScopes(scopes []string) PresentationRequestTemplate
- func (pb *PresentationBuilder) GetTemplate(templateID string) (PresentationRequestTemplate, error)
- func (pb *PresentationBuilder) ListTemplates() []PresentationRequestTemplate
- type PresentationDefinitionParameter
- type PresentationRequestTemplate
- type PresentationSubmission
- type QRReply
- type RequestObject
- type RequestObjectCache
- func (r *RequestObjectCache) Delete(requestURI string)
- func (r *RequestObjectCache) Get(requestURI string) (*RequestObject, bool)
- func (r *RequestObjectCache) Len() int
- func (r *RequestObjectCache) Set(requestURI string, requestObject *RequestObject)
- func (r *RequestObjectCache) SetWithTTL(requestURI string, requestObject *RequestObject, ttl time.Duration)
- func (r *RequestObjectCache) Stop()
- type ResponseParameters
- type SDJWTVCFormat
- type StaticVC20KeyResolver
- type SubmissionRequirement
- type TransactionData
- type TrustService
- type TrustedAuthority
- type TrustedAuthorityMatcher
- type VC20CreateRequest
- type VC20CreateResult
- type VC20Handler
- type VC20HandlerOption
- func WithVC20AllowedSkew(skew time.Duration) VC20HandlerOption
- func WithVC20Clock(clock func() time.Time) VC20HandlerOption
- func WithVC20KeyResolver(resolver VC20KeyResolver) VC20HandlerOption
- func WithVC20RevocationCheck(check bool) VC20HandlerOption
- func WithVC20SignerConfig(config *VC20SignerConfig) VC20HandlerOption
- func WithVC20StaticKey(key crypto.PublicKey) VC20HandlerOption
- func WithVC20TrustedIssuers(issuers []string) VC20HandlerOption
- type VC20KeyResolver
- type VC20SignerConfig
- type VC20VerificationResult
- type VPBuildOptions
- type VPBuilder
- type VPBuilderOption
- type VPFormatsSupported
- type VPResponse
- type VPTokenValidator
- type VerificationFailedError
- type VerificationRejectedError
- type VerifierInfo
Examples ¶
- EphemeralEncryptionKeyCache.GenerateAndStore
- ErrorResponse.Error
- ErrorResponse.IsAuthorizationError
- InputDescriptor
- New
- New (Usage)
- New (WithCustomConfig)
- NewEphemeralEncryptionKeyCache
- NewErrorResponse
- NewRequestObjectCache
- PresentationSubmission
- RequestObjectCache.SetWithTTL
- VerificationFailedError
- VerificationRejectedError
Constants ¶
const ( // FormatJwtVCJson is the format identifier for JWT-based W3C VC without JSON-LD. FormatJwtVCJson = "jwt_vc_json" // FormatSDJWTVC is the format identifier for IETF SD-JWT VC. FormatSDJWTVC = "dc+sd-jwt" // FormatMsoMdoc is the format identifier for ISO mdoc. FormatMsoMdoc = "mso_mdoc" // FormatLdpVCDCQL is the format identifier for W3C VC Data Integrity (used in DCQL). // Note: This duplicates FormatLdpVC from vc20_handler.go but is needed for non-vc20 builds. FormatLdpVCDCQL = "ldp_vc" )
Credential format identifiers as defined in OpenID4VP Appendix B. Note: FormatLdpVC is defined in vc20_handler.go (vc20 build tag)
const ( // TrustedAuthorityTypeAKI is for Authority Key Identifier matching. // Value is base64url-encoded KeyIdentifier from AuthorityKeyIdentifier. TrustedAuthorityTypeAKI = "aki" // TrustedAuthorityTypeETSI is for ETSI Trusted List matching. // Value is the URL of the Trusted List (e.g., https://lotl.example.com). TrustedAuthorityTypeETSI = "etsi_tl" // TrustedAuthorityTypeOpenIDFederation is for OpenID Federation matching. // Value is the Entity Identifier of the Trust Anchor. TrustedAuthorityTypeOpenIDFederation = "openid_federation" )
TrustedAuthorityType constants per OpenID4VP spec Section 6.1.1
const ( // OAuth 2.0 standard errors ErrorInvalidScope = "invalid_scope" // Requested scope value is invalid, unknown, or malformed ErrorInvalidRequest = "invalid_request" // Request contains invalid parameters or violates requirements ErrorInvalidClient = "invalid_client" // Client authentication failed ErrorAccessDenied = "access_denied" // User denied consent or wallet lacks credentials // OpenID4VP specific errors ErrorVPFormatsNotSupported = "vp_formats_not_supported" // Wallet doesn't support requested VP formats ErrorInvalidRequestURIMethod = "invalid_request_uri_method" // Invalid request_uri_method value ErrorInvalidTransactionData = "invalid_transaction_data" // Transaction data is invalid or malformed )
Error codes defined in OpenID4VP spec Section 8.5
const ( FormatLdpVC = "ldp_vc" // VC Data Model 1.1 with Data Integrity FormatVC20JSON = "vc+ld+json" // VC Data Model 2.0 with Data Integrity )
VC20Format identifiers per OpenID4VC spec Appendix A
const ( CryptosuiteECDSA2019 = "ecdsa-rdfc-2019" CryptosuiteECDSASd = "ecdsa-sd-2023" CryptosuiteEdDSA2022 = "eddsa-rdfc-2022" )
Supported cryptosuites
const ( // DefaultEphemeralKeyTTL is the default TTL for ephemeral encryption keys DefaultEphemeralKeyTTL = 10 * time.Minute )
const ( // DefaultRequestObjectTTL is the default TTL for request objects DefaultRequestObjectTTL = 10 * time.Minute )
Variables ¶
var ErrInvalidVerifierHost = errors.New("verifier host is invalid or empty")
var StandardOIDCScopes = map[string]bool{ "openid": true, "profile": true, "email": true, "address": true, "phone": true, "offline_access": true, }
StandardOIDCScopes contains scopes defined by OpenID Connect Core. These are protocol-level scopes that are optional for credential matching. The "openid" scope is REQUIRED by the OIDC specification and will always be present, but it does not need to be mapped to a credential.
Functions ¶
func BuildDirectPostURL ¶
func BuildDirectPostURL(baseURL string, response *ResponseParameters) (string, error)
BuildDirectPostURL creates a URL-encoded form data string for direct_post
func FilterStandardScopes ¶
FilterStandardScopes removes standard OIDC scopes from the list. This is a utility function that can be used when you specifically need to identify scopes that are not standard OIDC scopes. Note that credential matching logic does NOT use this - all scopes (including standard ones) are considered for matching to allow optional credential mappings.
func GetClaimMappings ¶
func GetClaimMappings(template PresentationRequestTemplate) map[string]string
GetClaimMappings is a helper to extract claim mappings from a template Returns nil if the template doesn't implement this method
func IsMdocFormat ¶
IsMdocFormat returns true if the format is ISO mdoc format.
func IsSDJWTFormatIdentifier ¶
IsSDJWTFormatIdentifier returns true if the format identifier is SD-JWT VC format. Note: This is different from sdjwtvc.IsSDJWTFormat which checks the actual token format.
func IsW3CVCFormatIdentifier ¶
IsW3CVCFormatIdentifier returns true if the format identifier is a W3C Verifiable Credential format (ldp_vc or jwt_vc_json).
func MatchCryptosuite ¶
MatchCryptosuite checks if a cryptosuite is supported by the format configuration. Returns true if cryptosuiteValues is empty (no constraint) or contains the cryptosuite.
func MatchProofType ¶
MatchProofType checks if a proof type is supported by the format configuration. Returns true if proofTypeValues is empty (no constraint) or contains the proofType.
func MatchTrustedAuthorities ¶
func MatchTrustedAuthorities( trustedAuthorities []TrustedAuthority, credentialCertChain [][]byte, issuer string, matcher TrustedAuthorityMatcher, ) bool
MatchTrustedAuthorities checks if a credential matches any of the trusted authorities constraints. Returns true if trustedAuthorities is empty (no constraint) or the credential matches at least one. The matcher parameter provides the actual trust verification implementation. If matcher is nil, returns true (no validation performed).
func MatchTypeValues ¶
MatchTypeValues checks if a credential's types match any of the type_values alternatives. credentialTypes should be the fully expanded type IRIs from the credential. typeValues is the query's type_values constraint (array of string arrays). Returns true if the credential matches at least one of the alternatives.
func ValidateCredentialQuery ¶
func ValidateCredentialQuery(query CredentialQuery) error
ValidateCredentialQuery validates that a CredentialQuery has the required fields for the specified format.
func ValidateVPToken ¶
ValidateVPToken is a convenience function for basic VP Token validation
Types ¶
type ClaimQuery ¶
type ClaimQuery struct {
// Path REQUIRED The value MUST be a non-empty array representing a claims path pointer that specifies the path to a claim within the Credential, as defined in Section 7.
Path []string `json:"path" yaml:"path" validate:"required,min=1,dive,required"`
}
type ClaimTransformDef ¶
type ClaimTransformDef struct {
Type string // Transform type: date_format, boolean_string, uppercase, lowercase, etc.
Params map[string]string // Transform parameters
}
ClaimTransformDef defines a claim transformation
type ClaimsExtractor ¶
type ClaimsExtractor struct {
// contains filtered or unexported fields
}
ClaimsExtractor extracts and maps claims from VP tokens to OIDC claims
func NewClaimsExtractor ¶
func NewClaimsExtractor() *ClaimsExtractor
NewClaimsExtractor creates a new claims extractor
func (*ClaimsExtractor) ApplyClaimTransforms ¶
func (ce *ClaimsExtractor) ApplyClaimTransforms(claims map[string]any, transformDefs map[string]ClaimTransformDef) (map[string]any, error)
ApplyClaimTransforms applies transformations to claim values transformDefs: Map of OIDC claim name to transform definition
func (*ClaimsExtractor) ExtractAndMapClaims ¶
func (ce *ClaimsExtractor) ExtractAndMapClaims( ctx context.Context, vpToken string, claimMappings map[string]string, transformDefs map[string]ClaimTransformDef, ) (map[string]any, error)
ExtractAndMapClaims is a convenience function that combines extraction, mapping, and transformation This is the main entry point for the complete claims processing pipeline
func (*ClaimsExtractor) ExtractClaimsFromVPToken ¶
func (ce *ClaimsExtractor) ExtractClaimsFromVPToken(ctx context.Context, vpToken string) (map[string]any, error)
ExtractClaimsFromVPToken extracts claims from a VP token. Automatically detects the format:
- DCQL response: JSON object mapping credential query IDs to individual tokens
- mdoc: CBOR-based mobile document
- SD-JWT: dot-separated JWT with selective disclosures
Returns a merged map of disclosed claims from all credentials.
func (*ClaimsExtractor) MapClaimsToOIDC ¶
func (ce *ClaimsExtractor) MapClaimsToOIDC(vpClaims map[string]any, claimMappings map[string]string) (map[string]any, error)
MapClaimsToOIDC maps VP claims to OIDC claims using the template's claim mappings claimMappings: Key = VP claim path, Value = OIDC claim name Special mapping "*" : "*" means pass all claims through unchanged
type Client ¶
type Client struct {
EphemeralKeyCache *EphemeralEncryptionKeyCache
RequestObjectCache *RequestObjectCache
}
Client holds the OpenID4VP client with ephemeral key caching and request object caching
func New ¶
New creates a new OpenID4VP client with ephemeral key cache and request object cache
Example ¶
ExampleNew demonstrates creating an OpenID4VP client with default settings
package main
import (
"context"
"fmt"
"github.com/SUNET/vc/pkg/openid4vp"
)
func main() {
ctx := context.TODO()
// Create a client with default TTL settings (10 minutes for both caches)
client, err := openid4vp.New(ctx, nil)
if err != nil {
fmt.Printf("Error creating client: %v\n", err)
return
}
defer client.Close()
fmt.Println("Client created with default settings")
fmt.Printf("Ephemeral key cache initialized: %t\n", client.EphemeralKeyCache != nil)
fmt.Printf("Request object cache initialized: %t\n", client.RequestObjectCache != nil)
}
Output: Client created with default settings Ephemeral key cache initialized: true Request object cache initialized: true
Example (Usage) ¶
ExampleNew_usage demonstrates using both caches in the client
package main
import (
"context"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"fmt"
"github.com/SUNET/vc/pkg/openid4vp"
"github.com/lestrrat-go/jwx/v3/jwk"
)
func main() {
ctx := context.TODO()
// Create client
client, err := openid4vp.New(ctx, nil)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer client.Close()
// 1. Store a request object in the request object cache
requestObject := &openid4vp.RequestObject{
ResponseType: "vp_token",
ClientID: "https://verifier.example.com",
Nonce: "n-0S6_WzA2Mj",
State: "af0ifjsldkj",
}
requestURI := "urn:ietf:params:oauth:request_uri:6eSG8FrjKQb1Qiwj"
client.RequestObjectCache.Set(requestURI, requestObject)
// Retrieve the request object
retrieved, found := client.RequestObjectCache.Get(requestURI)
if found {
fmt.Printf("Request object - Client: %s\n", retrieved.ClientID)
fmt.Printf("Request object - State: %s\n", retrieved.State)
}
// 2. Store an ephemeral encryption key in the ephemeral key cache
// Generate a test key
privateKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
key, _ := jwk.Import(privateKey)
_ = key.Set(jwk.KeyIDKey, "ephemeral-key-123")
client.EphemeralKeyCache.Set("ephemeral-key-123", key)
// Retrieve the ephemeral key
retrievedKey, found := client.EphemeralKeyCache.Get("ephemeral-key-123")
if found {
kid, _ := retrievedKey.KeyID()
fmt.Printf("Ephemeral key - KID: %s\n", kid)
}
// Check both cache sizes
fmt.Printf("Request objects in cache: %d\n", client.RequestObjectCache.Len())
fmt.Printf("Ephemeral keys in cache: %d\n", client.EphemeralKeyCache.Len())
}
Output: Request object - Client: https://verifier.example.com Request object - State: af0ifjsldkj Ephemeral key - KID: ephemeral-key-123 Request objects in cache: 1 Ephemeral keys in cache: 1
Example (WithCustomConfig) ¶
ExampleNew_withCustomConfig demonstrates creating a client with custom TTL settings
package main
import (
"context"
"fmt"
"time"
"github.com/SUNET/vc/pkg/openid4vp"
)
func main() {
ctx := context.TODO()
// Create a client with custom TTL values
config := &openid4vp.Config{
EphemeralKeyTTL: 5 * time.Minute, // Ephemeral keys expire after 5 minutes
RequestObjectTTL: 3 * time.Minute, // Request objects expire after 3 minutes
}
client, err := openid4vp.New(ctx, config)
if err != nil {
fmt.Printf("Error creating client: %v\n", err)
return
}
defer client.Close()
fmt.Println("Client created with custom TTL settings")
fmt.Printf("Ephemeral key cache TTL: 5 minutes\n")
fmt.Printf("Request object cache TTL: 3 minutes\n")
}
Output: Client created with custom TTL settings Ephemeral key cache TTL: 5 minutes Request object cache TTL: 3 minutes
type ClientMetadata ¶
type ClientMetadata struct {
// JWKS OPTIONAL. A JSON Web Key Set, as defined in [RFC7591], that contains one or more public keys, such as those used by the Wallet as an input to a key agreement that may be used for encryption of the Authorization Response (see Section 8.3), or where the Wallet will require the public key of the Verifier to generate a Verifiable Presentation. This allows the Verifier to pass ephemeral keys specific to this Authorization Request. Public keys included in this parameter MUST NOT be used to verify the signature of signed Authorization Requests. Each JWK in the set MUST have a kid (Key ID) parameter that uniquely identifies the key within the context of the request.
JWKS *Keys `json:"jwks,omitempty" bson:"jwks,omitempty" validate:"omitempty"`
//encrypted_response_enc_values_supported: OPTIONAL. Non-empty array of strings, where each string is a JWE [RFC7516] enc algorithm that can be used as the content encryption algorithm for encrypting the Response. When a response_mode requiring encryption of the Response (such as dc_api.jwt or direct_post.jwt) is specified, this MUST be present for anything other than the default single value of A128GCM. Otherwise, this SHOULD be absent.
EncryptedResponseEncValuesSupported []string `` /* 189-byte string literal not displayed */
//vp_formats_supported: REQUIRED when not available to the Wallet via another mechanism. As defined in Section 11.1.
// Per OpenID4VP spec, this is the properly formatted field for client_metadata in authorization requests
VPFormatsSupported *VPFormatsSupported `json:"vp_formats_supported,omitempty" bson:"vp_formats_supported,omitempty"`
// authorization_signed_response_alg: OPTIONAL. As defined in [JARM].
AuthorizationSignedResponseALG string `` /* 152-byte string literal not displayed */
// authorization_encrypted_response_alg: OPTIONAL. As defined in [JARM].
AuthorizationEncryptedResponseALG string `` /* 175-byte string literal not displayed */
// authorization_encrypted_response_enc: OPTIONAL. As defined in [JARM].
AuthorizationEncryptedResponseENC string `` /* 178-byte string literal not displayed */
}
type Config ¶
type Config struct {
// EphemeralKeyTTL specifies the TTL for ephemeral encryption keys.
// If not set or zero, DefaultEphemeralKeyTTL (10 minutes) is used.
EphemeralKeyTTL time.Duration
// RequestObjectTTL specifies the TTL for request objects.
// If not set or zero, DefaultRequestObjectTTL (10 minutes) is used.
RequestObjectTTL time.Duration
}
Config holds configuration for the OpenID4VP client
type Constraints ¶
type CredentialQuery ¶
type CredentialQuery struct {
//ID REQUIRED. A string identifying the Credential in the response and, if provided, the constraints in credential_sets. The value MUST be a non-empty string consisting of alphanumeric, underscore (_), or hyphen (-) characters. Within the Authorization Request, the same id MUST NOT be present more than once.
ID string `json:"id" yaml:"id" validate:"required"`
// Format REQUIRED. A string that specifies the format of the requested Credential. Valid Credential Format Identifier values are defined in Appendix B.
Format string `json:"format" yaml:"format" validate:"required"`
// Multiple OPTIONAL. A boolean which indicates whether multiple Credentials can be returned for this Credential Query. If omitted, the default value is false.
Multiple bool `json:"multiple,omitempty" yaml:"multiple,omitempty"`
// Meta REQUIRED. An object defining additional properties requested by the Verifier that apply to the metadata and validity data of the Credential. The properties of this object are defined per Credential Format. Examples of those are in Appendix B.3.5 and Appendix B.2.3. If empty, no specific constraints are placed on the metadata or validity of the requested Credential.
Meta MetaQuery `json:"meta" yaml:"meta" validate:"required"`
// TrustedAuthorities OPTIONAL. A non-empty array of objects as defined in Section 6.1.1 that specifies expected authorities or trust frameworks that certify Issuers, that the Verifier will accept. Every Credential returned by the Wallet SHOULD match at least one of the conditions present in the corresponding trusted_authorities array if present.
TrustedAuthorities []TrustedAuthority `json:"trusted_authorities,omitempty" yaml:"trusted_authorities,omitempty"`
// RequireCryptographicHolderBinding OPTIONAL. A boolean which indicates whether the Verifier requires a Cryptographic Holder Binding proof. The default value is true, i.e., a Verifiable Presentation with Cryptographic Holder Binding is required. If set to false, the Verifier accepts a Credential without Cryptographic Holder Binding proof.
RequireCryptographicHolderBinding bool `json:"require_cryptographic_holder_binding,omitempty" yaml:"require_cryptographic_holder_binding,omitempty"`
// Claims OPTIONAL. A non-empty array of objects as defined in Section 6.3 that specifies claims in the requested Credential. Verifiers MUST NOT point to the same claim more than once in a single query. Wallets SHOULD ignore such duplicate claim queries.
Claims []ClaimQuery `json:"claims,omitempty" yaml:"claims,omitempty"`
// ClaimSet OPTIONAL. A non-empty array containing arrays of identifiers for elements in claims that specifies which combinations of claims for the Credential are requested. The rules for selecting claims to send are defined in Section 6.4.1.
ClaimSet []string `json:"claim_sets,omitempty" yaml:"claim_sets,omitempty" validate:"omitnil,min=1,dive,required"`
}
CredentialQuery is an object representing a request for a presentation of one or more matching Credentials.
func NewVC20CredentialQuery ¶
func NewVC20CredentialQuery(id string, typeValues [][]string, claims []ClaimQuery) CredentialQuery
NewVC20CredentialQuery creates a new CredentialQuery for W3C VC 2.0 Data Integrity format. typeValues should be an array of type alternatives, where each alternative is an array of fully expanded type IRIs that must all be present in the credential.
type CredentialSetQuery ¶
type CredentialSetQuery struct {
// Options REQUIRED A non-empty array, where each value in the array is a list of Credential Query identifiers representing one set of Credentials that satisfies the use case. The value of each element in the options array is a non-empty array of identifiers which reference elements in credentials.
Options [][]string `json:"options" yaml:"options" validate:"required,min=1,dive,required,min=1,dive,required"`
// Required OPTIONAL A boolean which indicates whether this set of Credentials is required to satisfy the particular use case at the Verifier. If omitted, the default value is true.
Required bool `json:"required,omitempty" yaml:"required,omitempty"`
// Purpose Can't find in spec, but in example from wwwallet
Purpose string `json:"purpose,omitempty" yaml:"purpose,omitempty"`
}
type DCQL ¶
type DCQL struct {
// Credentials REQUIRED. A non-empty array of Credential Queries as defined in Section 6.1 that specify the requested Credentials.
Credentials []CredentialQuery `json:"credentials" yaml:"credentials" validate:"required,min=1,dive,required"`
// CredentialSets OPTIONAL. A non-empty array of Credential Set Queries as defined in Section 6.2 that specifies additional constraints on which of the requested Credentials to return.
CredentialSets []CredentialSetQuery `json:"credential_sets,omitempty" yaml:"credential_sets,omitempty" validate:"omitnil,min=1,dive,required"`
}
type DCQLValidationError ¶
DCQLValidationError represents a validation error in a DCQL query.
func (*DCQLValidationError) Error ¶
func (e *DCQLValidationError) Error() string
type Descriptor ¶
type Descriptor struct {
ID string `json:"id" validate:"required"`
Path string `json:"path" validate:"required"`
PathNested *Descriptor `json:"path_nested,omitempty"`
Format string `json:"format" validate:"required,oneof=jwt jwt_vc jwt_vp ldp ldp_vc ldp_vp mso_mdoc ac_vc ac_vp sd_jwt"`
}
type DirectPostJWTResponse ¶
type DirectPostJWTResponse struct {
Response string `json:"response"` // Encrypted JWT containing the Authorization Response
}
DirectPostJWTResponse represents response_mode=direct_post.jwt (Section 8.3.1)
type DirectPostResponse ¶
type DirectPostResponse struct {
RedirectURI string `json:"redirect_uri,omitempty"` // Optional per spec
}
DirectPostResponse is the response from the direct_post endpoint (Section 8.2)
type EphemeralEncryptionKeyCache ¶
type EphemeralEncryptionKeyCache struct {
// contains filtered or unexported fields
}
EphemeralEncryptionKeyCache manages short-lived encryption keys for response encryption
func NewEphemeralEncryptionKeyCache ¶
func NewEphemeralEncryptionKeyCache(ttl time.Duration) *EphemeralEncryptionKeyCache
NewEphemeralEncryptionKeyCache creates and starts a new ephemeral encryption key cache with the specified TTL. Keys are automatically evicted after the TTL expires.
Example ¶
ExampleNewEphemeralEncryptionKeyCache demonstrates creating an ephemeral encryption key cache
package main
import (
"fmt"
"time"
"github.com/SUNET/vc/pkg/openid4vp"
)
func main() {
// Create a cache with 10-minute TTL
cache := openid4vp.NewEphemeralEncryptionKeyCache(10 * time.Minute)
defer cache.Stop()
fmt.Println("Ephemeral encryption key cache created")
fmt.Printf("Initial cache size: %d\n", cache.Len())
}
Output: Ephemeral encryption key cache created Initial cache size: 0
func (*EphemeralEncryptionKeyCache) Delete ¶
func (e *EphemeralEncryptionKeyCache) Delete(kid string)
Delete removes an ephemeral encryption key from the cache
func (*EphemeralEncryptionKeyCache) GenerateAndStore ¶
func (e *EphemeralEncryptionKeyCache) GenerateAndStore(kid string) (privateKey jwk.Key, publicKey jwk.Key, err error)
GenerateAndStore generates a new ephemeral encryption key pair, stores the private key in the cache, and returns both private and public JWKs. The key uses ECDH P-256.
Example ¶
ExampleEphemeralEncryptionKeyCache_GenerateAndStore demonstrates generating and storing a key pair
package main
import (
"fmt"
"github.com/SUNET/vc/pkg/openid4vp"
)
func main() {
cache := openid4vp.NewEphemeralEncryptionKeyCache(openid4vp.DefaultEphemeralKeyTTL)
defer cache.Stop()
// Generate ECDH P-256 key pair and store private key in cache
kid := "ephemeral-key-abc123"
privateKey, publicKey, err := cache.GenerateAndStore(kid)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
// Private key is automatically stored in cache
retrievedPrivate, found := cache.Get(kid)
if found {
fmt.Printf("Private key stored in cache: %t\n", retrievedPrivate != nil)
}
// Get key IDs
privateKid, _ := privateKey.KeyID()
publicKid, _ := publicKey.KeyID()
fmt.Printf("Private key KID: %s\n", privateKid)
fmt.Printf("Public key KID: %s\n", publicKid)
// Public key has "use" set to "enc"
use, _ := publicKey.KeyUsage()
fmt.Printf("Public key usage: %s\n", use)
}
Output: Private key stored in cache: true Private key KID: ephemeral-key-abc123 Public key KID: ephemeral-key-abc123 Public key usage: enc
func (*EphemeralEncryptionKeyCache) Get ¶
func (e *EphemeralEncryptionKeyCache) Get(kid string) (jwk.Key, bool)
Get retrieves an ephemeral encryption key by its key ID (kid)
func (*EphemeralEncryptionKeyCache) Len ¶
func (e *EphemeralEncryptionKeyCache) Len() int
Len returns the number of items currently in the cache
func (*EphemeralEncryptionKeyCache) Set ¶
func (e *EphemeralEncryptionKeyCache) Set(kid string, key jwk.Key)
Set stores an ephemeral encryption key with the specified key ID (kid)
func (*EphemeralEncryptionKeyCache) SetWithTTL ¶
SetWithTTL stores an ephemeral encryption key with a custom TTL
func (*EphemeralEncryptionKeyCache) Stop ¶
func (e *EphemeralEncryptionKeyCache) Stop()
Stop stops the cache's automatic expiration goroutine
type ErrorResponse ¶
type ErrorResponse struct {
ErrorCode string `json:"error"`
ErrorDescription string `json:"error_description,omitempty"`
State string `json:"state,omitempty"`
}
ErrorResponse represents an OAuth 2.0 error response as defined in Section 8.5
func NewErrorResponse ¶
func NewErrorResponse(code, description, state string) *ErrorResponse
NewErrorResponse creates a new ErrorResponse
Example ¶
package main
import (
"fmt"
"github.com/SUNET/vc/pkg/openid4vp"
)
func main() {
err := openid4vp.NewErrorResponse(
openid4vp.ErrorAccessDenied,
"user denied consent",
"state-abc123",
)
fmt.Println("error:", err.Error())
fmt.Println("code:", err.ErrorCode)
fmt.Println("state:", err.State)
}
Output: error: access_denied: user denied consent code: access_denied state: state-abc123
func (*ErrorResponse) Error ¶
func (e *ErrorResponse) Error() string
Error implements the error interface for ErrorResponse
Example ¶
package main
import (
"fmt"
"github.com/SUNET/vc/pkg/openid4vp"
)
func main() {
// Error with description
err1 := openid4vp.NewErrorResponse(openid4vp.ErrorInvalidRequest, "missing nonce", "")
fmt.Println(err1.Error())
// Error without description
err2 := openid4vp.NewErrorResponse(openid4vp.ErrorWalletUnavailable, "", "")
fmt.Println(err2.Error())
}
Output: invalid_request: missing nonce wallet_unavailable
func (*ErrorResponse) IsAuthorizationError ¶
func (e *ErrorResponse) IsAuthorizationError() bool
IsAuthorizationError checks if this is an authorization-related error
Example ¶
package main
import (
"fmt"
"github.com/SUNET/vc/pkg/openid4vp"
)
func main() {
authErr := openid4vp.NewErrorResponse(openid4vp.ErrorAccessDenied, "denied", "")
fmt.Println("access_denied is auth error:", authErr.IsAuthorizationError())
formatErr := openid4vp.NewErrorResponse(openid4vp.ErrorVPFormatsNotSupported, "unsupported", "")
fmt.Println("vp_formats_not_supported is auth error:", formatErr.IsAuthorizationError())
}
Output: access_denied is auth error: true vp_formats_not_supported is auth error: false
type InputDescriptor ¶
type InputDescriptor struct {
ID string `json:"id"`
Name string `json:"name,omitempty"`
Purpose string `json:"purpose,omitempty"`
Format map[string]map[string][]string `json:"format,omitempty"`
Group []string `json:"group,omitempty"`
Constraints Constraints `json:"constraints"`
}
Example ¶
package main
import (
"fmt"
"github.com/SUNET/vc/pkg/openid4vp"
)
func main() {
descriptor := openid4vp.InputDescriptor{
ID: "identity_credential",
Name: "Identity Credential",
Purpose: "We need to verify your identity",
Constraints: openid4vp.Constraints{
LimitDisclosure: "required",
Fields: []openid4vp.Field{
{
Path: []string{"$.vc.credentialSubject.given_name"},
},
},
},
}
fmt.Println("id:", descriptor.ID)
fmt.Println("name:", descriptor.Name)
fmt.Println("limit_disclosure:", descriptor.Constraints.LimitDisclosure)
fmt.Println("fields:", len(descriptor.Constraints.Fields))
}
Output: id: identity_credential name: Identity Credential limit_disclosure: required fields: 1
type JWK ¶
type JWK struct {
KTY string `json:"kty,omitempty" bson:"kty,omitempty" validate:"required,oneof=RSA EC OKP"`
X string `json:"x,omitempty" bson:"x,omitempty" validate:"omitempty"`
Y string `json:"y,omitempty" bson:"y,omitempty" validate:"omitempty"`
CRV string `json:"crv,omitempty" bson:"crv,omitempty" validate:"omitempty,oneof=P-256 P-384 P-521 Ed25519 Ed448 X25519 X448"`
N string `json:"n,omitempty" bson:"n,omitempty" validate:"omitempty"`
KID string `json:"kid,omitempty" bson:"kid,omitempty" validate:"omitempty"`
E string `json:"e,omitempty" bson:"e,omitempty" validate:"omitempty"`
Use string `json:"use,omitempty" bson:"use,omitempty" validate:"omitempty,oneof=sig enc"`
Alg string `json:"alg,omitempty" bson:"alg,omitempty"`
}
type JWTVCFormat ¶
type JWTVCFormat struct {
// AlgValues is a non-empty array containing identifiers of cryptographic algorithms supported.
// If present, the alg JOSE header of the presented VC/VP MUST match one of the array values.
AlgValues []string `json:"alg_values,omitempty" yaml:"alg_values,omitempty"`
}
JWTVCFormat defines format-specific parameters for JWT-based W3C VC (jwt_vc_json).
type LDPVCFormat ¶
type LDPVCFormat struct {
// ProofTypeValues is a non-empty array containing identifiers of proof types supported.
// If present, the proof type of the presented VC/VP MUST match one of the array values.
ProofTypeValues []string `` /* 134-byte string literal not displayed */
// CryptosuiteValues is a non-empty array containing identifiers of crypto suites supported.
// Used when one of the algorithms in ProofTypeValues supports multiple crypto suites.
CryptosuiteValues []string `` /* 161-byte string literal not displayed */
}
LDPVCFormat defines format-specific parameters for W3C VC Data Integrity (ldp_vc).
type MetaQuery ¶
type MetaQuery struct {
// VCTValues for SD-JWT VC format (dc+sd-jwt).
// A non-empty array of strings that specifies allowed values for the type of the requested Verifiable Credential.
// All elements in the array MUST be valid type identifiers as defined in [I-D.ietf-oauth-sd-jwt-vc].
// The Wallet MAY return Credentials that inherit from any of the specified types.
VCTValues []string `json:"vct_values,omitempty" yaml:"vct_values,omitempty"`
// TypeValues for W3C VC format (ldp_vc, jwt_vc_json).
// A non-empty array of string arrays specifying the fully expanded types (IRIs) that the Verifier accepts.
// Each top-level array specifies one alternative to match the fully expanded type values of the Verifiable Credential.
// Each inner array specifies a set of fully expanded types that MUST be present in the credential's type property.
TypeValues [][]string `json:"type_values,omitempty" yaml:"type_values,omitempty"`
// DoctypeValue for ISO mdoc format (mso_mdoc).
// String that specifies an allowed value for the doctype of the requested Verifiable Credential.
DoctypeValue string `json:"doctype_value,omitempty" yaml:"doctype_value,omitempty"`
}
MetaQuery represents format-specific metadata constraints for credential queries. For SD-JWT VC format (dc+sd-jwt): use VCTValues For W3C VC format (ldp_vc): use TypeValues
type MsoMdocFormat ¶
type MsoMdocFormat struct {
// IssuerAuthAlgValues is a non-empty array containing cryptographic algorithm identifiers
// supported for IssuerAuth COSE signatures.
IssuerAuthAlgValues []int `json:"issuerauth_alg_values,omitempty" yaml:"issuerauth_alg_values,omitempty"`
// DeviceAuthAlgValues is a non-empty array containing cryptographic algorithm identifiers
// supported for DeviceAuth COSE signatures or MACs.
DeviceAuthAlgValues []int `json:"deviceauth_alg_values,omitempty" yaml:"deviceauth_alg_values,omitempty"`
}
MsoMdocFormat defines format-specific parameters for ISO mdoc (mso_mdoc).
type PresentationBuilder ¶
type PresentationBuilder struct {
// contains filtered or unexported fields
}
PresentationBuilder builds OpenID4VP presentation requests from templates
func NewPresentationBuilder ¶
func NewPresentationBuilder[T PresentationRequestTemplate](templates []T) *PresentationBuilder
NewPresentationBuilder creates a new PresentationBuilder with the given templates The templates parameter accepts any slice of types that implement PresentationRequestTemplate
func (*PresentationBuilder) BuildDCQLQuery ¶
BuildDCQLQuery creates a DCQL query from OIDC scopes. This attempts to find matching templates, and falls back to a generic DCQL query if none are found. All scopes are considered for matching, including standard OIDC scopes like "openid". This allows standard OIDC scopes to optionally map to credentials if configured. Non-standard scopes are prioritized over standard scopes to prevent "openid" from always being selected when it appears first in the request.
func (*PresentationBuilder) BuildFromScopes ¶
func (pb *PresentationBuilder) BuildFromScopes(ctx context.Context, scopes []string) (*DCQL, PresentationRequestTemplate, error)
BuildFromScopes creates a DCQL query from OIDC scopes using configured templates Returns the DCQL query and the template that was used
func (*PresentationBuilder) BuildFromTemplate ¶
func (pb *PresentationBuilder) BuildFromTemplate(ctx context.Context, templateID string) (*DCQL, PresentationRequestTemplate, error)
BuildFromTemplate creates a DCQL query from a specific template ID
func (*PresentationBuilder) FindTemplateByScopes ¶
func (pb *PresentationBuilder) FindTemplateByScopes(scopes []string) PresentationRequestTemplate
FindTemplateByScopes finds a template that matches the given OIDC scopes Returns the first template where all requested scopes are present in the template's scopes
func (*PresentationBuilder) GetTemplate ¶
func (pb *PresentationBuilder) GetTemplate(templateID string) (PresentationRequestTemplate, error)
GetTemplate returns a specific template by ID
func (*PresentationBuilder) ListTemplates ¶
func (pb *PresentationBuilder) ListTemplates() []PresentationRequestTemplate
ListTemplates returns all templates
type PresentationDefinitionParameter ¶
type PresentationDefinitionParameter struct {
// ID The Presentation Definition MUST contain an id property. The value of this property MUST be a string.
// The string SHOULD provide a unique ID for the desired context.
ID string `json:"id" bson:"id" validate:"required"`
// Name The Presentation Definition MAY contain a name property. If present, its value SHOULD be a
// human-friendly string intended to constitute a distinctive designation of the Presentation Definition.
Name string `json:"name,omitempty" bson:"name,omitempty"`
// Purpose The Presentation Definition MAY contain a purpose property. If present, its value MUST be a
// string that describes the purpose for which the Presentation Definition's inputs are being used for.
Purpose string `json:"purpose,omitempty" bson:"purpose,omitempty"`
// InputDescriptors The Presentation Definition MUST contain an input_descriptors property.
// Its value MUST be an array of Input Descriptor Objects.
InputDescriptors []InputDescriptor `json:"input_descriptors" bson:"input_descriptors" validate:"required,dive"`
// SubmissionRequirements The Presentation Definition MAY contain a submission_requirements property.
// If present, its value MUST be an array of Submission Requirement Objects.
SubmissionRequirements []SubmissionRequirement `json:"submission_requirements,omitempty" bson:"submission_requirements,omitempty" validate:"omitempty,dive"`
// Format The Presentation Definition MAY contain a format property. If present, its value MUST be an object
// with one or more properties matching the registered Claim Format Designations.
Format map[string]Format `json:"format,omitempty" bson:"format,omitempty"`
}
type PresentationRequestTemplate ¶
type PresentationRequestTemplate interface {
GetID() string
GetOIDCScopes() []string
GetDCQLQuery() *DCQL
}
PresentationRequestTemplate represents a template for creating presentation requests. This is a minimal interface to avoid import cycles with pkg/configuration.
type PresentationSubmission ¶
type PresentationSubmission struct {
ID string `json:"id" validate:"required"`
DefinitionID string `json:"definition_id" validate:"required"`
DescriptorMap []Descriptor `json:"descriptor_map" validate:"required,dive,required"`
}
Example ¶
package main
import (
"fmt"
"github.com/SUNET/vc/pkg/openid4vp"
)
func main() {
submission := openid4vp.PresentationSubmission{
ID: "submission-1",
DefinitionID: "definition-1",
DescriptorMap: []openid4vp.Descriptor{
{
ID: "identity_credential",
Path: "$",
Format: "sd_jwt",
},
},
}
fmt.Println("id:", submission.ID)
fmt.Println("definition_id:", submission.DefinitionID)
fmt.Println("descriptors:", len(submission.DescriptorMap))
fmt.Println("first descriptor format:", submission.DescriptorMap[0].Format)
}
Output: id: submission-1 definition_id: definition-1 descriptors: 1 first descriptor format: sd_jwt
type QRReply ¶
type QRReply struct {
Base64Image string `json:"base64_image" bson:"base64_image" validate:"required"`
URI string `json:"uri" bson:"uri" validate:"required"`
}
QRReply is a collection of fields representing a QRReply code TODO(masv): not sure if the type should include uri,request_uri,client_id,session_id
func GenerateQR ¶
type RequestObject ¶
type RequestObject struct {
// ISS MAY be present in the Request Object. However, if it is present, the Wallet MUST ignore it.
ISS string `json:"iss" uri:"iss" validate:"required,url"`
AUD string `json:"aud,omitempty" bson:"aud,omitempty" validate:"required"`
IAT int64 `json:"iat,omitempty" bson:"iat,omitempty" validate:"required"`
// ResponseType REQUIRED. Value MUST be set to "code".
ResponseType string `json:"response_type" uri:"response_type" validate:"required,eq=code"`
// REQUIRED. Defined in [RFC6749]. This specification defines additional requirements to enable the use of Client Identifier Prefixes as described in Section 5.9. The Client Identifier can be created by parties other than the Wallet and it is considered unique within the context of the Wallet when used in combination with the Client Identifier Prefix.
ClientID string `json:"client_id" uri:"client_id" validate:"required"`
//RedirectURI OPTIONAL. As described in Section 3.1.2.
RedirectURI string `json:"redirect_uri,omitempty" uri:"redirect_uri" validate:"omitempty,url"`
// Scope OPTIONAL. The scope of the access request as described by Section 3.3.
Scope string `json:"scope,omitempty" uri:"scope" validate:"omitempty"`
// State REQUIRED under the conditions defined in Section 5.3. Otherwise, state is OPTIONAL. state values MUST only contain ASCII URL safe characters (uppercase and lowercase letters, decimal digits, hyphen, period, underscore, and tilde).
State string `json:"state,omitempty" uri:"state" validate:"omitempty"`
// Nonce REQUIRED. A case-sensitive String representing a value to securely bind Verifiable Presentation(s) provided by the Wallet to the particular transaction. The Verifier MUST create a fresh, cryptographically random number with sufficient entropy for every Authorization Request, store it with its current session, and pass it in the nonce Authorization Request Parameter to the Wallet. See Section 14.1 for details. Values MUST only contain ASCII URL safe characters (uppercase and lowercase letters, decimal digits, hyphen, period, underscore, and tilde).
Nonce string `json:"nonce" uri:"nonce" validate:"required"`
// ResponseMode REQUIRED. Defined in [OAuth.Responses]. This parameter can be used (through the new Response Mode direct_post) to ask the Wallet to send the response to the Verifier via an HTTPS connection (see Section 8.2 for more details). It can also be used to request that the resulting response be encrypted (see Section 8.3 for more details).
ResponseMode string `` /* 126-byte string literal not displayed */
//dcql_query
DCQLQuery *DCQL `json:"dcql_query,omitempty" bson:"dcql_query,omitempty" validate:"omitempty,dive"`
// ClientMetadata OPTIONAL. A JSON object containing the Verifier metadata values. It MUST be UTF-8 encoded.
ClientMetadata *ClientMetadata `json:"client_metadata,omitempty" validate:"omitempty"`
//RequestURIMethod: OPTIONAL. A string determining the HTTP method to be used when the request_uri parameter is included in the same request. Two case-sensitive valid values are defined in this specification: get and post. If request_uri_method value is get, the Wallet MUST send the request to retrieve the Request Object using the HTTP GET method, i.e., as defined in [RFC9101]. If request_uri_method value is post, a supporting Wallet MUST send the request using the HTTP POST method as detailed in Section 5.10. If the request_uri_method parameter is not present, the Wallet MUST process the request_uri parameter as defined in [RFC9101]. Wallets not supporting the post method will send a GET request to the Request URI (default behavior as defined in [RFC9101]). request_uri_method parameter MUST NOT be present if a request_uri parameter is not present. If the Verifier set the request_uri_method parameter value to post and there is no other means to convey its capabilities to the Wallet, it SHOULD add the client_metadata parameter to the Authorization Request. This enables the Wallet to assess the Verifier's capabilities, allowing it to transmit only the relevant capabilities through the wallet_metadata parameter in the Request URI POST request.
RequestURIMethod string `json:"request_uri_method,omitempty" bson:"request_uri_method,omitempty" validate:"omitempty,oneof=get post"`
// TransactionData OPTIONAL. Non-empty array of strings, where each string is a base64url-encoded JSON object that contains a typed parameter set with details about the transaction that the Verifier is requesting the End-User to authorize. See Section 8.4 for details. The Wallet MUST return an error if a request contains even one unrecognized transaction data type or transaction data not conforming to the respective type definition
TransactionData []TransactionData `json:"transaction_data,omitempty" bson:"transaction_data,omitempty" validate:"omitempty,dive,required"`
// VerifierInfo OPTIONAL. A non-empty array of attestations about the Verifier relevant to the Credential Request. These attestations MAY include Verifier metadata, policies, trust status, or authorizations. Attestations are intended to support authorization decisions, inform Wallet policy enforcement, or enrich the End-User consent dialog.
VerifierInfo []VerifierInfo `json:"verifier_info,omitempty" bson:"verifier_info,omitempty" validate:"omitempty,dive,required"`
// ResponseURI REQUIRED when the Response Mode direct_post is used. The URL to which the Wallet MUST send the Authorization Response using an HTTP POST request as defined by the Response Mode direct_post. The Response URI receives all Authorization Response parameters as defined by the respective Response Type. When the response_uri parameter is present, the redirect_uri Authorization Request parameter MUST NOT be present. If the redirect_uri Authorization Request parameter is present when the Response Mode is direct_post, the Wallet MUST return an invalid_request Authorization Response error. The response_uri value MUST be a value that the client would be permitted to use as redirect_uri when following the rules defined in Section 5.9.
ResponseURI string `json:"response_uri,omitempty" uri:"response_uri" validate:"required"`
}
RequestObject is sent by authorization request
func (*RequestObject) CreateAuthorizationRequestURI ¶
func (*RequestObject) Sign ¶
Sign creates a signed JWT representation of the RequestObject according to OpenID4VP specification. The JWT typ header is set to "oauth-authz-req+jwt" as required by OpenID4VP Section 5.2. Uses pki.Signer interface which supports both software keys and HSM.
Parameters:
- ctx: Context for signing operations
- signer: The pki.Signer for signing (supports both software and HSM keys)
- x5c: Optional X.509 certificate chain for key verification
Returns the signed JWT string or an error if signing fails.
type RequestObjectCache ¶
type RequestObjectCache struct {
// contains filtered or unexported fields
}
RequestObjectCache manages short-lived request objects for authorization requests
func NewRequestObjectCache ¶
func NewRequestObjectCache(ttl time.Duration) *RequestObjectCache
NewRequestObjectCache creates and starts a new request object cache with the specified TTL. Request objects are automatically evicted after the TTL expires.
Example ¶
ExampleNewRequestObjectCache demonstrates creating a request object cache
package main
import (
"fmt"
"time"
"github.com/SUNET/vc/pkg/openid4vp"
)
func main() {
// Create a cache with 10-minute TTL
cache := openid4vp.NewRequestObjectCache(10 * time.Minute)
defer cache.Stop()
// Store a request object
requestURI := "urn:ietf:params:oauth:request_uri:6eSG8FrjKQb1Qiwj"
requestObject := &openid4vp.RequestObject{
ResponseType: "vp_token",
ClientID: "https://verifier.example.com",
Nonce: "n-0S6_WzA2Mj",
}
cache.Set(requestURI, requestObject)
// Retrieve the request object
retrieved, found := cache.Get(requestURI)
if found {
fmt.Printf("Found request object for client: %s\n", retrieved.ClientID)
}
}
Output: Found request object for client: https://verifier.example.com
func (*RequestObjectCache) Delete ¶
func (r *RequestObjectCache) Delete(requestURI string)
Delete removes a request object from the cache
func (*RequestObjectCache) Get ¶
func (r *RequestObjectCache) Get(requestURI string) (*RequestObject, bool)
Get retrieves a request object by its request URI
func (*RequestObjectCache) Len ¶
func (r *RequestObjectCache) Len() int
Len returns the number of items currently in the cache
func (*RequestObjectCache) Set ¶
func (r *RequestObjectCache) Set(requestURI string, requestObject *RequestObject)
Set stores a request object with the specified request URI
func (*RequestObjectCache) SetWithTTL ¶
func (r *RequestObjectCache) SetWithTTL(requestURI string, requestObject *RequestObject, ttl time.Duration)
SetWithTTL stores a request object with a custom TTL
Example ¶
ExampleRequestObjectCache_SetWithTTL demonstrates setting a request object with custom TTL
package main
import (
"fmt"
"time"
"github.com/SUNET/vc/pkg/openid4vp"
)
func main() {
cache := openid4vp.NewRequestObjectCache(openid4vp.DefaultRequestObjectTTL)
defer cache.Stop()
// Store a request object with a custom short TTL (e.g., for one-time use)
requestURI := "urn:ietf:params:oauth:request_uri:short-lived"
requestObject := &openid4vp.RequestObject{
ResponseType: "vp_token",
ClientID: "https://verifier.example.com",
Nonce: "n-abc123",
}
// Set with 5-minute TTL instead of default 10 minutes
cache.SetWithTTL(requestURI, requestObject, 5*time.Minute)
fmt.Printf("Stored request object with 5-minute TTL\n")
}
Output: Stored request object with 5-minute TTL
func (*RequestObjectCache) Stop ¶
func (r *RequestObjectCache) Stop()
Stop stops the cache's automatic expiration goroutine
type ResponseParameters ¶
type ResponseParameters struct {
//VPToken REQUIRED. The structure of this parameter depends on the query language used to request the presentations in the Authorization Request:
VPToken string `json:"vp_token,omitempty" bson:"vp_token" validate:"omitempty,required_if=ResponseType vp_token"`
Code string `json:"code,omitempty" bson:"code"`
ISS string `json:"iss,omitempty" bson:"iss"`
State string `json:"state,omitempty" bson:"state"`
IDToken string `json:"id_token,omitempty" bson:"id_token"`
PresentationSubmission *PresentationSubmission `json:"presentation_submission,omitempty" bson:"presentation_submission"`
}
func ResponseParametersFromJSON ¶
func ResponseParametersFromJSON(data []byte) (*ResponseParameters, error)
ResponseParametersFromJSON deserializes the response parameters from JSON
func (*ResponseParameters) BuildCredential ¶
func (r *ResponseParameters) BuildCredential() (map[string]any, error)
BuildCredential unwraps the VPToken from the ResponseParameters
func (*ResponseParameters) ToJSON ¶
func (r *ResponseParameters) ToJSON() ([]byte, error)
ToJSON serializes the response parameters to JSON
func (*ResponseParameters) Validate ¶
func (r *ResponseParameters) Validate() error
Validate validates the response parameters according to OpenID4VP spec Section 8.1
type SDJWTVCFormat ¶
type SDJWTVCFormat struct {
// SDJWTAlgValues is a non-empty array containing cryptographic algorithm identifiers
// supported for the Issuer-signed JWT of an SD-JWT.
SDJWTAlgValues []string `json:"sd-jwt_alg_values,omitempty" yaml:"sd-jwt_alg_values,omitempty"`
// KBJWTAlgValues is a non-empty array containing cryptographic algorithm identifiers
// supported for a Key Binding JWT (KB-JWT).
KBJWTAlgValues []string `json:"kb-jwt_alg_values,omitempty" yaml:"kb-jwt_alg_values,omitempty"`
}
SDJWTVCFormat defines format-specific parameters for IETF SD-JWT VC (dc+sd-jwt).
type StaticVC20KeyResolver ¶
StaticVC20KeyResolver is a simple key resolver that returns a fixed key.
func (*StaticVC20KeyResolver) ResolveKey ¶
func (r *StaticVC20KeyResolver) ResolveKey(ctx context.Context, verificationMethod string) (crypto.PublicKey, error)
ResolveKey returns the static key regardless of verification method.
type SubmissionRequirement ¶
type TransactionData ¶
type TransactionData struct {
// Type REQUIRED. String that identifies the type of transaction data. This value determines parameters that can be included in the transaction_data object. The specific values are out of scope for this specification. It is RECOMMENDED to use collision-resistant names for type values.
Type string `json:"type,omitempty" bson:"type,omitempty" validate:"required"`
// CredentialIDS REQUIRED. Non-empty array of strings each referencing a Credential requested by the Verifier that can be used to authorize this transaction. The string matches the id field in the DCQL Credential Query. If there is more than one element in the array, the Wallet MUST use only one of the referenced Credentials for transaction authorization.
CredentialIDS []string `json:"credential_ids,omitempty" bson:"credential_ids,omitempty" validate:"required,dive,required"`
}
func (*TransactionData) Base64Encode ¶
func (t *TransactionData) Base64Encode() (string, error)
Base64Encode encodes the TransactionData struct into a base64 URL-encoded string.
type TrustService ¶
type TrustService struct {
}
func (*TrustService) ExtractPublicKeyFromX5C ¶
func (ts *TrustService) ExtractPublicKeyFromX5C(x5cBase64 string, ext ...*cryptoutil.Extensions) (any, error)
type TrustedAuthority ¶
type TrustedAuthority struct {
// REQUIRED. A string uniquely identifying the type of information about the issuer trust framework. Types defined by this specification are listed below.
Type string `json:"type" yaml:"type" validate:"required,oneof=aki etsi_tl openid_federation"`
// REQUIRED. A non-empty array of strings, where each string (value) contains information specific to the used Trusted Authorities Query type that allows the identification of an issuer, a trust framework, or a federation that an issuer belongs to.
Values []string `json:"values" yaml:"values" validate:"required,min=1"`
}
func NewTrustedAuthorityAKI ¶
func NewTrustedAuthorityAKI(akiValues ...string) TrustedAuthority
NewTrustedAuthorityAKI creates a TrustedAuthority for Authority Key Identifier matching.
func NewTrustedAuthorityETSI ¶
func NewTrustedAuthorityETSI(tlURLs ...string) TrustedAuthority
NewTrustedAuthorityETSI creates a TrustedAuthority for ETSI Trusted List matching.
func NewTrustedAuthorityOpenIDFederation ¶
func NewTrustedAuthorityOpenIDFederation(trustAnchors ...string) TrustedAuthority
NewTrustedAuthorityOpenIDFederation creates a TrustedAuthority for OpenID Federation matching.
type TrustedAuthorityMatcher ¶
type TrustedAuthorityMatcher interface {
// MatchAKI checks if a credential's certificate chain contains a certificate
// with the given Authority Key Identifier (base64url-encoded).
MatchAKI(credentialCertChain [][]byte, aki string) bool
// MatchETSI checks if a credential's issuer is present in the ETSI Trusted List.
// The tlURL is the URL of the Trusted List or List of Trusted Lists.
MatchETSI(credentialCertChain [][]byte, tlURL string) bool
// MatchOpenIDFederation checks if a credential's issuer is part of an OpenID Federation
// with the given Trust Anchor entity identifier.
MatchOpenIDFederation(issuer string, trustAnchorEntityID string) bool
}
TrustedAuthorityMatcher provides methods for matching credentials against trusted authorities. Implementations should integrate with trust frameworks (go-trust, ETSI TL, etc.).
type VC20CreateRequest ¶
type VC20CreateRequest struct {
// CredentialID is the unique ID for the credential (optional, generated if empty)
CredentialID string
// Types are the credential types (e.g., ["VerifiableCredential", "UniversityDegreeCredential"])
Types []string
// Subject is the credential subject (the entity the credential is about)
Subject map[string]any
// AdditionalContexts are extra JSON-LD contexts to include
AdditionalContexts []string
// ValidFrom is when the credential becomes valid (defaults to now)
ValidFrom time.Time
// ValidUntil is when the credential expires (optional)
ValidUntil *time.Time
// CredentialStatus for revocation (optional)
CredentialStatus map[string]any
}
VC20CreateRequest contains parameters for creating a credential.
type VC20CreateResult ¶
type VC20CreateResult struct {
// CredentialJSON is the signed credential as JSON bytes
CredentialJSON []byte
// CredentialID is the credential's unique ID
CredentialID string
// Issuer is the issuer DID
Issuer string
// ValidFrom is when the credential is valid from
ValidFrom time.Time
// ValidUntil is when the credential expires (nil if no expiration)
ValidUntil *time.Time
}
VC20CreateResult contains the signed credential and metadata.
type VC20Handler ¶
type VC20Handler struct {
// contains filtered or unexported fields
}
VC20Handler handles W3C VC 2.0 Data Integrity credentials in OpenID4VP flows.
func NewVC20Handler ¶
func NewVC20Handler(opts ...VC20HandlerOption) (*VC20Handler, error)
NewVC20Handler creates a new W3C VC 2.0 handler for OpenID4VP.
func (*VC20Handler) CreateCredential ¶
func (h *VC20Handler) CreateCredential(ctx context.Context, req *VC20CreateRequest) (*VC20CreateResult, error)
CreateCredential creates and signs a new W3C VC 2.0 Data Integrity credential.
func (*VC20Handler) VerifyAndExtract ¶
func (h *VC20Handler) VerifyAndExtract(ctx context.Context, vpToken string) (*VC20VerificationResult, error)
VerifyAndExtract verifies a W3C VC VP token and extracts claims.
type VC20HandlerOption ¶
type VC20HandlerOption func(*VC20Handler)
VC20HandlerOption configures a VC20Handler.
func WithVC20AllowedSkew ¶
func WithVC20AllowedSkew(skew time.Duration) VC20HandlerOption
WithVC20AllowedSkew sets the allowed clock skew for time validation.
func WithVC20Clock ¶
func WithVC20Clock(clock func() time.Time) VC20HandlerOption
WithVC20Clock sets the clock function for time validation.
func WithVC20KeyResolver ¶
func WithVC20KeyResolver(resolver VC20KeyResolver) VC20HandlerOption
WithVC20KeyResolver sets the key resolver for VC20 verification.
func WithVC20RevocationCheck ¶
func WithVC20RevocationCheck(check bool) VC20HandlerOption
WithVC20RevocationCheck enables credential status checking.
func WithVC20SignerConfig ¶
func WithVC20SignerConfig(config *VC20SignerConfig) VC20HandlerOption
WithVC20SignerConfig sets the signing configuration for credential issuance.
func WithVC20StaticKey ¶
func WithVC20StaticKey(key crypto.PublicKey) VC20HandlerOption
WithVC20StaticKey sets a static public key for VC20 verification.
func WithVC20TrustedIssuers ¶
func WithVC20TrustedIssuers(issuers []string) VC20HandlerOption
WithVC20TrustedIssuers sets the list of trusted issuers.
type VC20KeyResolver ¶
type VC20KeyResolver interface {
// ResolveKey resolves a verification method to a public key.
// verificationMethod can be:
// - Full DID URL: "did:key:z6Mk...#key-1"
// - DID with fragment: "did:web:example.com#keys-1"
// - HTTP URL: "https://example.com/keys/1"
// Returns crypto.PublicKey which can be *ecdsa.PublicKey or ed25519.PublicKey
ResolveKey(ctx context.Context, verificationMethod string) (crypto.PublicKey, error)
}
VC20KeyResolver resolves verification method URIs to public keys. Implementations can resolve DIDs (did:key, did:web, did:jwk, etc.), fetch JWKS, or use go-trust for policy-based resolution.
type VC20SignerConfig ¶
type VC20SignerConfig struct {
// PrivateKey is the signing key (ecdsa.PrivateKey or ed25519.PrivateKey)
PrivateKey crypto.PrivateKey
// IssuerID is the DID or URI of the issuer (e.g., "did:web:example.com")
IssuerID string
// VerificationMethod is the full verification method URI (e.g., "did:web:example.com#key-1")
VerificationMethod string
// Cryptosuite specifies which suite to use: ecdsa-rdfc-2019, ecdsa-sd-2023, eddsa-rdfc-2022
Cryptosuite string
}
VC20SignerConfig holds issuer signing configuration.
type VC20VerificationResult ¶
type VC20VerificationResult struct {
// Credential metadata
ID string `json:"id,omitempty"`
Issuer string `json:"issuer"`
Subject string `json:"subject,omitempty"`
Types []string `json:"type"`
IssuanceDate time.Time `json:"validFrom"`
ExpirationDate *time.Time `json:"validUntil,omitempty"`
// Credential content
CredentialSubject map[string]any `json:"credentialSubject"`
// Proof metadata
ProofType string `json:"proofType"`
Cryptosuite string `json:"cryptosuite"`
VerificationMethod string `json:"verificationMethod"`
ProofPurpose string `json:"proofPurpose"`
ProofCreated time.Time `json:"proofCreated"`
// Selective disclosure info (for ecdsa-sd-2023)
IsSelectiveDisclosure bool `json:"isSelectiveDisclosure"`
DisclosedPaths []string `json:"disclosedPaths,omitempty"`
// All claims as map for generic access
Claims map[string]any `json:"claims"`
// Raw credential JSON
RawCredential json.RawMessage `json:"rawCredential"`
}
VC20VerificationResult contains the result of W3C VC verification.
func (*VC20VerificationResult) GetClaims ¶
func (r *VC20VerificationResult) GetClaims() map[string]any
GetClaims returns all claims from the credential.
func (*VC20VerificationResult) GetCredentialSubject ¶
func (r *VC20VerificationResult) GetCredentialSubject() map[string]any
GetCredentialSubject returns the credential subject claims.
type VPBuildOptions ¶
type VPBuildOptions struct {
// HolderDID is the DID of the presentation holder
HolderDID string
// VerificationMethod is the full verification method URI (e.g., did:key:z6Mk...#key-1)
VerificationMethod string
// Nonce is the challenge/nonce from the verifier (required for OpenID4VP)
Nonce string
// Domain is the audience/domain for the presentation
Domain string
// Cryptosuite specifies which cryptosuite to use for signing
// Supported: "ecdsa-rdfc-2019", "eddsa-rdfc-2022"
Cryptosuite string
// Created timestamp for the proof (defaults to now)
Created time.Time
}
VPBuildOptions contains options for building a Verifiable Presentation.
type VPBuilder ¶
type VPBuilder struct {
// contains filtered or unexported fields
}
VPBuilder builds W3C Verifiable Presentations for OpenID4VP flows.
func NewVPBuilder ¶
func NewVPBuilder(opts ...VPBuilderOption) *VPBuilder
NewVPBuilder creates a new VPBuilder with the given options.
func (*VPBuilder) BuildVC20Presentation ¶
func (b *VPBuilder) BuildVC20Presentation( credentials [][]byte, privateKey crypto.PrivateKey, opts *VPBuildOptions, ) ([]byte, error)
BuildVC20Presentation creates a signed W3C Verifiable Presentation. The credentials parameter should be JSON bytes of W3C VC 2.0 credentials. The privateKey should match the cryptosuite (ed25519.PrivateKey for EdDSA, *ecdsa.PrivateKey for ECDSA).
type VPBuilderOption ¶
type VPBuilderOption func(*VPBuilder)
VPBuilderOption configures a VPBuilder.
func WithDefaultCryptosuite ¶
func WithDefaultCryptosuite(suite string) VPBuilderOption
WithDefaultCryptosuite sets the default cryptosuite for VP signing.
func WithHolderDID ¶
func WithHolderDID(did string) VPBuilderOption
WithHolderDID sets the holder DID for presentations.
type VPFormatsSupported ¶
type VPFormatsSupported struct {
// LDPVC is the configuration for W3C VC Data Integrity format (ldp_vc)
LDPVC *LDPVCFormat `json:"ldp_vc,omitempty" yaml:"ldp_vc,omitempty"`
// JWTVCJson is the configuration for JWT-based W3C VC format (jwt_vc_json)
JWTVCJson *JWTVCFormat `json:"jwt_vc_json,omitempty" yaml:"jwt_vc_json,omitempty"`
// SDJWT is the configuration for SD-JWT VC format (dc+sd-jwt)
SDJWT *SDJWTVCFormat `json:"dc+sd-jwt,omitempty" yaml:"dc+sd-jwt,omitempty"`
// MsoMdoc is the configuration for ISO mdoc format (mso_mdoc)
MsoMdoc *MsoMdocFormat `json:"mso_mdoc,omitempty" yaml:"mso_mdoc,omitempty"`
}
VPFormatsSupported defines format-specific parameters for Verifier or Wallet metadata. Used in client_metadata and Wallet metadata to indicate supported formats and algorithms.
func NewVC20VPFormatsSupported ¶
func NewVC20VPFormatsSupported(cryptosuites []string) VPFormatsSupported
NewVC20VPFormatsSupported creates a VPFormatsSupported configuration for W3C VC 2.0 Data Integrity format with the specified cryptosuites.
type VPResponse ¶
type VPTokenValidator ¶
type VPTokenValidator struct {
// Nonce from the Authorization Request
Nonce string
// ClientID (or Origin for DC API)
ClientID string
// ValidateFormat enables SD-JWT format validation (not cryptographic verification).
// This only validates that the JWT structure is parseable — it does NOT verify
// the actual cryptographic signature. Use TrustEvaluator for signature verification.
ValidateFormat bool
// CheckRevocation enables revocation status checks
CheckRevocation bool
// DCQLQuery is the original DCQL query from the request
DCQLQuery *DCQL
}
VPTokenValidator validates VP Token according to Section 8.6 NOTE: This validator performs format and protocol validation only. Cryptographic signature verification must be done separately by the caller (e.g. via jwt.Parse with a resolved key). TrustEvaluator handles trust/policy evaluation — it does NOT perform signature verification itself.
func (*VPTokenValidator) Validate ¶
func (v *VPTokenValidator) Validate(vpToken string) error
Validate validates the VP Token according to OpenID4VP spec Section 8.6
type VerificationFailedError ¶
Example ¶
package main
import (
"fmt"
"github.com/SUNET/vc/pkg/openid4vp"
)
func main() {
err := &openid4vp.VerificationFailedError{
Step: "signature_verification",
Err: fmt.Errorf("invalid signature"),
}
fmt.Println(err.Error())
}
Output: verification failed on 'signature_verification': invalid signature
func (*VerificationFailedError) Error ¶
func (e *VerificationFailedError) Error() string
func (*VerificationFailedError) Unwrap ¶
func (e *VerificationFailedError) Unwrap() error
type VerificationRejectedError ¶
Example ¶
package main
import (
"fmt"
"github.com/SUNET/vc/pkg/openid4vp"
)
func main() {
err := &openid4vp.VerificationRejectedError{
Step: "trust_evaluation",
Reason: "issuer not trusted",
}
fmt.Println(err.Error())
}
Output: verification rejected on 'trust_evaluation': issuer not trusted
func (*VerificationRejectedError) Error ¶
func (e *VerificationRejectedError) Error() string
type VerifierInfo ¶
type VerifierInfo struct {
// Format: REQUIRED. A string that identifies the format of the attestation and how it is encoded. Ecosystems SHOULD use collision-resistant identifiers. Further processing of the attestation is determined by the type of the attestation, which is specified in a format-specific way.
Format string `json:"format" bson:"format" validate:"required"`
// Data: REQUIRED. An object or string containing an attestation (e.g. a JWT). The payload structure is defined on a per format level. It is at the discretion of the Wallet whether it uses the information from verifier_info. Factors that influence such Wallet's decision include, but are not limited to, trust framework the Wallet supports, specific policies defined by the Issuers or ecosystem, and profiles of this specification. If the Wallet uses information from verifier_info, the Wallet MUST validate the signature and ensure binding.
Data string `json:"data" bson:"data" validate:"required"`
// credential_ids: OPTIONAL. A non-empty array of strings each referencing a Credential requested by the Verifier for which the attestation is relevant. Each string matches the id field in a DCQL Credential Query. If omitted, the attestation is relevant to all requested Credentials.
CredentialIDS []string `json:"credential_ids,omitempty" bson:"credential_ids,omitempty" validate:"omitempty,dive,required"`
}
Source Files
¶
- authorization_request_methods.go
- claims_extractor.go
- context.go
- dcql.go
- direct_post.go
- encryption_key_cache.go
- errors.go
- openid4vp.go
- presentation_builder.go
- qr_generator.go
- request_object.go
- request_object_cache.go
- response_parameters.go
- trust_service.go
- validator.go
- vc20_handler.go
- vc20_vp_builder.go
- verification_errors.go
- vp_types.go