sdjwtvc

package
v0.5.8 Latest Latest
Warning

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

Go to latest
Published: May 20, 2026 License: BSD-2-Clause Imports: 29 Imported by: 0

README

SD-JWT VC Package (sdjwtvc)

This package implements SD-JWT-based Verifiable Credentials (SD-JWT VC) per draft-ietf-oauth-sd-jwt-vc-13.

Specifications

This implementation is compliant with:

Key Features

SD-JWT VC Compliance (draft-13)
Media Type (Section 3.1)
  • Uses application/dc+sd-jwt media type
  • JWT header typ claim: dc+sd-jwt
  • Also accepts vc+sd-jwt during transition period
Required Claims (Section 3.2.2)
  • vct: Verifiable Credential Type identifier (REQUIRED)
  • iss: Issuer identifier (OPTIONAL but recommended)
  • iat: Issuance time (OPTIONAL)
  • exp: Expiration time (OPTIONAL)
  • cnf: Confirmation method for Key Binding (OPTIONAL, REQUIRED for Key Binding)
  • _sd_alg: Hash algorithm (automatically set based on hash method used)
Type Metadata (Section 6)

Full support for VCTM (Verifiable Credential Type Metadata):

  • Type identification (vct field)
  • Display metadata (Section 8):
    • Locale-specific rendering
    • Simple rendering (logo, colors)
    • SVG templates with properties
  • Claim metadata (Section 9):
    • Claim paths for nested structures
    • Display labels per locale
    • Selective disclosure rules (sd: "always", "allowed", "never")
    • Mandatory claim indicators
    • SVG template placeholders
  • Type extension (extends field)
  • Integrity protection (Section 7):
    • Subresource Integrity hashes
    • vct#integrity, extends#integrity, uri#integrity
SD-JWT Core Features (draft-22)
  • Selective Disclosure:
    • Object properties (Section 4.2.1)
    • Array elements (Section 4.2.2)
    • Recursive structures (Section 4.2.6)
  • Security:
    • Cryptographically secure random salts (128-bit entropy)
    • Decoy digests to obscure claim count (Section 4.2.5)
    • Hash-based disclosure protection
  • Hash Algorithms:
    • SHA-256 (default)
    • SHA-384
    • SHA-512
    • SHA3-256
    • SHA3-512

Examples

See example_test.go for runnable examples (go test -run Example).

API Reference

Credential Creation
BuildCredential
func (c *Client) BuildCredential(
    issuer string,
    keyID string,
    privateKey any,
    credentialType string,
    documentData []byte,
    holderJWK map[string]any,
    vctm *VCTM,
    opts *CredentialOptions,
) (string, error)

Creates a complete SD-JWT VC credential.

Parameters:

  • issuer: Issuer identifier (used in iss claim)
  • keyID: Key identifier for JWT header kid
  • privateKey: Signing key (*ecdsa.PrivateKey or *rsa.PrivateKey)
  • credentialType: Credential type identifier (used in vct claim)
  • documentData: JSON-encoded credential claims
  • holderJWK: Holder's public key in JWK format (for key binding)
  • vctm: Verifiable Credential Type Metadata
  • opts: Optional parameters (nil for defaults)

Returns: Complete SD-JWT string with disclosures

Credential Verification
ParseAndVerify
func (c *Client) ParseAndVerify(
    sdJWT string,
    publicKey any,
    opts *VerificationOptions,
) (*VerificationResult, error)

Parses and verifies an SD-JWT VC credential.

Parameters:

  • sdJWT: The SD-JWT string (format: <JWT>~<Disclosure1>~...~[<KB-JWT>])
  • publicKey: Issuer's public key (*ecdsa.PublicKey or *rsa.PublicKey)
  • opts: Verification options (nil for defaults)

Returns: VerificationResult with parsed claims and validity status

VerificationResult
type VerificationResult struct {
    Valid             bool              // Overall validity (true if no errors)
    Header            map[string]any    // JWT header
    Claims            map[string]any    // All claims (including disclosed)
    DisclosedClaims   map[string]any    // Only selectively disclosed claims
    Disclosures       []Disclosure      // Parsed disclosure structures
    VCTM              *VCTM            // Type metadata (if present in header)
    KeyBindingValid   bool              // Whether KB-JWT signature verified
    KeyBindingClaims  map[string]any    // KB-JWT claims (if present)
    Errors            []error           // Any validation errors encountered
}
VerificationOptions
type VerificationOptions struct {
    RequireKeyBinding bool              // Whether KB-JWT must be present
    ExpectedNonce     string            // Nonce to validate in KB-JWT
    ExpectedAudience  string            // Audience to validate in KB-JWT
    AllowedClockSkew  time.Duration     // Allowed time skew (default: 5 min)
    ValidateTime      bool              // Whether to validate exp/iat (default: true)
}
Key Binding
CreateKeyBindingJWT
func CreateKeyBindingJWT(
    sdJWT string,
    nonce string,
    audience string,
    holderPrivateKey any,
    hashAlg string,
) (string, error)

Creates a Key Binding JWT to prove possession of the holder's key.

Parameters:

  • sdJWT: The SD-JWT string (without KB-JWT)
  • nonce: Freshness value from verifier
  • audience: Verifier's identifier
  • holderPrivateKey: Holder's private key
  • hashAlg: Hash algorithm ("sha-256", "sha-384", "sha-512", etc.)

Returns: KB-JWT string to append to SD-JWT

Compliance Notes

Media Type Transition

Per Section 3.2.1 of draft-13:

"Note that this draft used vc+sd-jwt as the value of the typ header from its inception in July 2023 until November 2024 when it was changed to dc+sd-jwt... It is RECOMMENDED that Verifiers and Holders accept both vc+sd-jwt and dc+sd-jwt as the value of the typ header for a reasonable transitional period."

This package uses dc+sd-jwt as the default but systems should accept both values.

VCTM vs Core SD-JWT

The VCTM (Verifiable Credential Type Metadata) is defined in SD-JWT VC specification (Section 6), NOT in the core SD-JWT specification. VCTM provides:

  • Display metadata: How to render credentials in wallets
  • Claim metadata: Validation rules and selective disclosure policies
  • Type relationships: Extension and composition of credential types

The core SD-JWT spec (draft-22) only defines the selective disclosure mechanism itself.

Hash Algorithm Selection

The _sd_alg claim is automatically set based on the hash method provided:

// SHA-256 (most common)
credential, _ := client.MakeCredential(sha256.New(), data, vctm)
// Sets _sd_alg to "sha-256"

// SHA3-512
credential, _ := client.MakeCredential(sha3.New512(), data, vctm)
// Sets _sd_alg to "sha3-512"

References

Documentation

Index

Examples

Constants

This section is empty.

Variables

View Source
var SDJWTClaimMapping = map[string]string{

	"sub": "sub",
	"iss": "iss",
	"iat": "iat",
	"exp": "exp",
	"nbf": "nbf",

	"family_name":           "family_name",
	"given_name":            "given_name",
	"middle_name":           "middle_name",
	"nickname":              "nickname",
	"preferred_username":    "preferred_username",
	"profile":               "profile",
	"picture":               "picture",
	"website":               "website",
	"email":                 "email",
	"email_verified":        "email_verified",
	"gender":                "gender",
	"birthdate":             "birthdate",
	"zoneinfo":              "zoneinfo",
	"locale":                "locale",
	"phone_number":          "phone_number",
	"phone_number_verified": "phone_number_verified",
	"address":               "address",
	"updated_at":            "updated_at",

	"birth_date":        "birthdate",
	"date_of_birth":     "birthdate",
	"first_name":        "given_name",
	"last_name":         "family_name",
	"full_name":         "name",
	"age_over_18":       "age_over_18",
	"age_over_21":       "age_over_21",
	"nationality":       "nationality",
	"place_of_birth":    "place_of_birth",
	"document_number":   "document_number",
	"issuing_authority": "issuing_authority",
	"issuing_country":   "issuing_country",
	"issue_date":        "iat",
	"expiry_date":       "exp",
}

SDJWTClaimMapping provides standard mappings from SD-JWT VC claims to OIDC claims. These follow common credential schemas and OIDC standard claims.

Functions

func Base64Decode

func Base64Decode(s string) (string, error)

Base64Decode decodes a base64url-encoded string to a string

func Combine

func Combine(token string, disclosures []string, keyBinding string) string

Combine combines the token, disclosures and keyBinding into an SD-JWT format

Example
package main

import (
	"fmt"

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

func main() {
	signedJWT := "eyJhbGciOiJFUzI1NiJ9.eyJ2Y3QiOiJpZCJ9.c2ln"
	disclosures := []string{"ZGlzYzE", "ZGlzYzI"}

	sdJWT := sdjwtvc.Combine(signedJWT, disclosures, "")
	fmt.Println(sdJWT)
}
Output:
eyJhbGciOiJFUzI1NiJ9.eyJ2Y3QiOiJpZCJ9.c2ln~ZGlzYzE~ZGlzYzI~

func CombineWithKeyBinding

func CombineWithKeyBinding(sdJWT string, kbJWT string) string

CombineWithKeyBinding combines an SD-JWT with a Key Binding JWT to create SD-JWT+KB Format: <SD-JWT without trailing ~><KB-JWT>

Example
package main

import (
	"fmt"

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

func main() {
	sdJWT := "eyJhbGciOiJFUzI1NiJ9.eyJ2Y3QiOiJpZCJ9.c2ln~ZGlzYzE~ZGlzYzI~"
	kbJWT := "eyJ0eXAiOiJrYitqd3QifQ.eyJub25jZSI6Im4ifQ.a2JzaWc"

	combined := sdjwtvc.CombineWithKeyBinding(sdJWT, kbJWT)
	fmt.Println(combined)
}
Output:
eyJhbGciOiJFUzI1NiJ9.eyJ2Y3QiOiJpZCJ9.c2ln~ZGlzYzE~ZGlzYzI~eyJ0eXAiOiJrYitqd3QifQ.eyJub25jZSI6Im4ifQ.a2JzaWc

func CreateKeyBindingJWT

func CreateKeyBindingJWT(
	sdJWT string,
	nonce string,
	audience string,
	holderPrivateKey any,
	hashAlg string,
) (string, error)

CreateKeyBindingJWT creates a Key Binding JWT for an SD-JWT Per section 4.3: binds the SD-JWT to the Holder's key Parameters: - sdJWT: the SD-JWT string (without KB-JWT) - nonce: freshness value from Verifier - audience: identifier of the Verifier - holderPrivateKey: Holder's private key for signing - hashAlg: hash algorithm to use (must match _sd_alg from SD-JWT)

func ExtractClaimsByJSONPath

func ExtractClaimsByJSONPath(documentData map[string]any, jsonPathMap map[string]string) (map[string]any, error)

ExtractClaimsByJSONPath extracts specific claim values from document data using JSONPath queries. Takes a map of label->JSONPath expressions and returns a map of label->extracted values. Example: {"given-name": "$.name.given"} extracts the value at path $.name.given and maps it to "given-name". Paths that do not match any value in the document data are silently skipped.

func ExtractSDJWTClaims added in v0.5.7

func ExtractSDJWTClaims(vpToken string) (map[string]any, error)

ExtractSDJWTClaims extracts claims from an SD-JWT VP token without full verification. Use this for testing or when verification is handled separately.

func IsSDJWTFormat added in v0.5.7

func IsSDJWTFormat(vpToken string) bool

IsSDJWTFormat checks if the VP token appears to be in SD-JWT format.

func MapSDJWTToOIDC added in v0.5.7

func MapSDJWTToOIDC(sdJWTClaims map[string]any) map[string]any

MapSDJWTToOIDC maps SD-JWT claims to OIDC claims using the standard mapping.

func Sign

func Sign(header, body jwt.MapClaims, signingMethod jwt.SigningMethod, signingKey any) (string, error)

Sign signs the JWT with the provided header, body, signing method, and signing key

func SignWithSigner

func SignWithSigner(ctx context.Context, header, body jwt.MapClaims, signer Signer) (string, error)

SignWithSigner signs the JWT using a Signer interface (for HSM support).

func ValidateClaimPaths

func ValidateClaimPaths(claims map[string]any, vctm *VCTM, strict bool) error

ValidateClaimPaths validates that all claims in the document have corresponding paths in VCTM. This is a stricter validation that ensures no extra claims are present. It operates on document-data semantics, matching ValidateDocument: VCTM-mandatory envelope claims supplied by the issuer pipeline are not required, and the extras check ignores standard JWT/SD-JWT claims (see isStandardClaim).

func ValidateClaims

func ValidateClaims(claims map[string]any, vctm *VCTM) error

ValidateClaims validates a fully assembled claims set against VCTM metadata. All mandatory claims declared by the VCTM must be present, including JWT/ SD-JWT envelope claims such as iss, exp, cnf, vct, and iat. Use this when validating an assembled credential payload. To validate document-data prior to issuance — where envelope claims are filled in later by the issuer pipeline — use ValidateDocument instead.

func ValidateDocument

func ValidateDocument(documentData []byte, vctm *VCTM) error

ValidateDocument validates document data against VCTM metadata. documentData should be JSON-encoded document claims as supplied by the data source — i.e. the input to the issuer pipeline before JWT/SD-JWT envelope claims (iss, exp, cnf, vct, iat, ...) are added at signing time. Those envelope claims are not expected to be present here even when the VCTM marks them mandatory; see isIssuerSuppliedClaim.

Types

type Claim

type Claim struct {
	// Path indicates the claim(s) being addressed per section 9.1 (REQUIRED)
	// Array of strings, null values, or non-negative integers
	// - string: select key in object
	// - null: select all elements in array
	// - integer: select specific array index
	Path []*string `json:"path"`

	// Display contains locale-specific display information per section 9.2 (OPTIONAL)
	Display []ClaimDisplay `json:"display,omitempty"`

	// SD indicates selective disclosure rules per section 9.4 (OPTIONAL, default: "allowed")
	// Values: "always", "allowed", "never"
	// - "always": Issuer MUST make the claim selectively disclosable
	// - "allowed": Issuer MAY make the claim selectively disclosable
	// - "never": Issuer MUST NOT make the claim selectively disclosable
	// It is RECOMMENDED to use either "always" or "never" to avoid ambiguity.
	SD string `json:"sd,omitempty"`

	// Mandatory indicates if claim must be present per section 9.3 (OPTIONAL, default: false)
	Mandatory bool `json:"mandatory,omitempty"`

	// SVGID is the identifier for SVG template placeholders per section 8.1.2.2 (OPTIONAL)
	// Must be unique, alphanumeric + underscores, cannot start with digit
	SVGID string `json:"svg_id,omitempty"`
}

Claim represents credential claim metadata per SD-JWT VC draft-13 section 9 Provides information for displaying and validating claims

func (*Claim) JSONPath

func (c *Claim) JSONPath() string

JSONPath returns the JSON path for the claim. A nil element in Path means "select all elements of an array" per SD-JWT VC §9.1, and is emitted as the JSONPath wildcard "[*]".

type ClaimDisplay

type ClaimDisplay struct {
	// Locale is the language tag per RFC 5646 (REQUIRED)
	// Per draft-12+ this field is named "locale" in JSON (changed from "lang" in earlier drafts)
	Locale string `json:"locale"`

	// Label is a human-readable label for end users (REQUIRED)
	Label string `json:"label"`

	// Description is a human-readable description for end users (OPTIONAL)
	Description string `json:"description,omitempty"`
}

ClaimDisplay provides locale-specific claim display information per SD-JWT VC draft-13 section 9.2

type Client

type Client struct {
	// HTTPClient is the HTTP client used for outbound requests (e.g. VCTM
	// fetches). When nil, a default client with a 30-second timeout is used.
	HTTPClient *http.Client
}

Client is the SD-JWT VC client.

func New

func New() *Client

New creates a new Client with sensible defaults.

Example
package main

import (
	"fmt"

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

func main() {
	client := sdjwtvc.New()
	fmt.Printf("%T\n", client)
}
Output:
*sdjwtvc.Client

func (*Client) BuildCredentialWithSigner

func (c *Client) BuildCredentialWithSigner(ctx context.Context, issuer string, signer Signer, vctmRaw []byte, documentData []byte, holderJWK any, opts *CredentialOptions) (string, error)

BuildCredentialWithSigner creates a complete SD-JWT credential using a Signer interface. This allows signing with HSMs via PKCS#11 or other external signing services. The caller provides the raw VCTM bytes directly, eliminating SSRF risk. The vct claim is derived from the VCTM's VCT field.

func (*Client) MakeCredential

func (c *Client) MakeCredential(hashMethod hash.Hash, data map[string]any, vctm *VCTM, decoyCount int) (map[string]any, []string, error)

MakeCredential creates a SD-JWT credential with optional decoy digests. It implements recursive selective disclosure per oauth-selective-disclosure-jwt-22. Per section 4.2.5: decoy digests obscure the actual number of claims. Use decoyCount = 0 for no decoy digests (standard behavior).

func (*Client) ParseAndVerify

func (c *Client) ParseAndVerify(sdJWT string, publicKey any, opts *VerificationOptions) (*VerificationResult, error)

ParseAndVerify parses and verifies an SD-JWT credential Per draft-13 Section 3.4 (Verification and Processing) and draft-22 Section 6 (Verification) Parameters:

  • sdJWT: the SD-JWT string (format: <Issuer-signed JWT>~<Disclosure 1>~...~<Disclosure N>~[<KB-JWT>])
  • publicKey: issuer's public key for signature verification
  • opts: verification options (can be nil for defaults)

type CredentialCache

type CredentialCache struct {
	Claims     []Discloser    `json:"claims"`
	Credential map[string]any `json:"credential"`
}

CredentialCache holds credential claims and data

type CredentialOptions

type CredentialOptions struct {
	// DecoyDigests: number of decoy digests to add per _sd array (§4.2.5)
	DecoyDigests int
	// ExpirationDays: number of days until credential expires (default: 365)
	ExpirationDays int
	// TokenStatusList contains the Token Status List reference for credential revocation per draft-ietf-oauth-status-list
	TokenStatusList *TokenStatusListReference
	// Integrity is the pre-computed SRI hash of the VCTM document (e.g. "sha256-...").
	// When non-empty it is set as the "vct#integrity" claim in the issued credential
	// per SD-JWT VC draft-14 Section 6.
	Integrity string
}

CredentialOptions contains optional parameters for credential building

type Discloser

type Discloser struct {
	Salt      string `json:"-"`
	ClaimName string `json:"claim_name"` // Empty for array elements
	Value     any    `json:"value"`
	IsArray   bool   `json:"-"` // True for array element disclosures
}

Discloser represents a selective disclosure element per SD-JWT draft-22 Used to create Disclosures for selectively disclosable claims See: https://datatracker.ietf.org/doc/draft-ietf-oauth-selective-disclosure-jwt/22/

func ParseSelectiveDisclosure

func ParseSelectiveDisclosure(selectiveDisclosure []string) ([]Discloser, error)

ParseSelectiveDisclosure parses selective disclosure strings and returns a slice of Discloser objects. Each disclosure is a base64url-encoded JSON array containing either: - [salt, claim_name, claim_value] for object properties - [salt, claim_value] for array elements Returns a slice of Discloser objects representing the disclosed claims. Example: ["WyJzYWx0IiwgImdpdmVuX25hbWUiLCAiSm9obiJd"] -> []Discloser{{Salt: "salt", ClaimName: "given_name", Value: "John"}}

Example
package main

import (
	"fmt"

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

func main() {
	// Base64url-encoded disclosure: ["salt123", "given_name", "John"]
	disclosures := []string{"WyJzYWx0MTIzIiwiZ2l2ZW5fbmFtZSIsIkpvaG4iXQ"}

	parsed, err := sdjwtvc.ParseSelectiveDisclosure(disclosures)
	if err != nil {
		fmt.Println("error:", err)
		return
	}

	fmt.Println("claim:", parsed[0].ClaimName)
	fmt.Println("value:", parsed[0].Value)
}
Output:
claim: given_name
value: John

func (*Discloser) Hash

func (d *Discloser) Hash(hasher hash.Hash) (string, string, []any, error)

Hash returns the hash of the discloser and its base64 representation Per draft-22 section 4.2.3: hash the base64url-encoded Disclosure

type Disclosure

type Disclosure struct {
	Salt  string // Random salt for privacy
	Claim string // Claim name
	Value any    // Claim value
	Raw   string // Raw disclosure string
	Hash  string // Base64url-encoded hash
}

Disclosure represents a parsed disclosure

type KeyBindingJWT

type KeyBindingJWT struct {
	Nonce    string `json:"nonce"`             // REQUIRED: ensures freshness
	Audience string `json:"aud"`               // REQUIRED: intended receiver
	IssuedAt int64  `json:"iat"`               // REQUIRED: time of KB-JWT creation
	SDHash   string `json:"sd_hash,omitempty"` // REQUIRED: hash of SD-JWT
}

KeyBindingJWT represents a Key Binding JWT for SD-JWT+KB Per section 4.3: proves possession of the key referenced in the SD-JWT

type KeyResolver added in v0.5.7

type KeyResolver interface {
	// ResolveKey resolves a public key for the given issuer and key ID.
	ResolveKey(ctx context.Context, issuer string, keyID string) (crypto.PublicKey, error)
}

KeyResolver resolves public keys for SD-JWT verification. Implementations can fetch keys from JWKS endpoints, local stores, etc.

type Logo struct {
	// URI pointing to the image (REQUIRED)
	URI string `json:"uri"`

	// URIIntegrity provides Subresource Integrity protection per section 7 (OPTIONAL)
	URIIntegrity string `json:"uri#integrity,omitempty"`

	// AltText is alternative text for the image (OPTIONAL)
	AltText string `json:"alt_text,omitempty"`
}

Logo contains logo or image information per section 8.1.1.1 and 8.1.1.2

type ParsedCredential

type ParsedCredential struct {
	// Claims contains the credential claims (base JWT claims plus disclosed selective disclosures)
	Claims map[string]any
	// Disclosures contains the raw selective disclosure strings
	Disclosures []string
	// Header contains the JWT header
	Header map[string]any
	// Signature is the JWT signature
	Signature string
	// KeyBinding contains the key binding JWT parts if present
	KeyBinding []string
}

ParsedCredential represents a parsed SD-JWT credential with claims and disclosures

type Rendering

type Rendering struct {
	// Simple contains basic rendering properties per section 8.1.1 (OPTIONAL)
	// Used for applications that don't support SVG rendering
	Simple SimpleRendering `json:"simple"`

	// SVGTemplates contains SVG-based rendering per section 8.1.2 (OPTIONAL)
	// Array of SVG templates with different properties (landscape/portrait, light/dark, etc.)
	SVGTemplates []SVGTemplates `json:"svg_templates,omitempty"`
}

Rendering contains rendering methods for credential display per SD-JWT VC draft-13 section 8.1 Supports multiple rendering methods (simple, SVG templates)

type SDJWTHandler added in v0.5.7

type SDJWTHandler struct {
	// contains filtered or unexported fields
}

SDJWTHandler handles SD-JWT format credentials in OpenID4VP flows.

func NewSDJWTHandler added in v0.5.7

func NewSDJWTHandler(opts ...SDJWTHandlerOption) (*SDJWTHandler, error)

NewSDJWTHandler creates a new SD-JWT handler for OpenID4VP.

func (*SDJWTHandler) VerifyAndExtract added in v0.5.7

func (h *SDJWTHandler) VerifyAndExtract(ctx context.Context, vpToken string) (*SDJWTVerificationResult, error)

VerifyAndExtract verifies an SD-JWT VP token and extracts the disclosed claims.

type SDJWTHandlerOption added in v0.5.7

type SDJWTHandlerOption func(*SDJWTHandler)

SDJWTHandlerOption configures an SDJWTHandler.

func WithSDJWTKeyResolver added in v0.5.7

func WithSDJWTKeyResolver(resolver KeyResolver) SDJWTHandlerOption

WithSDJWTKeyResolver sets the key resolver for SD-JWT verification.

func WithSDJWTRequireKeyBinding added in v0.5.7

func WithSDJWTRequireKeyBinding(nonce, audience string) SDJWTHandlerOption

WithSDJWTRequireKeyBinding requires key binding JWT to be present.

func WithSDJWTStaticKey added in v0.5.7

func WithSDJWTStaticKey(key crypto.PublicKey) SDJWTHandlerOption

WithSDJWTStaticKey sets a static public key for SD-JWT verification.

func WithSDJWTTrustedIssuers added in v0.5.7

func WithSDJWTTrustedIssuers(issuers []string) SDJWTHandlerOption

WithSDJWTTrustedIssuers sets the list of trusted issuers.

func WithSDJWTVerificationOptions added in v0.5.7

func WithSDJWTVerificationOptions(opts *VerificationOptions) SDJWTHandlerOption

WithSDJWTVerificationOptions sets the verification options.

type SDJWTVerificationResult added in v0.5.7

type SDJWTVerificationResult struct {
	Valid           bool
	Issuer          string
	Subject         string
	VCT             string // Verifiable Credential Type
	Claims          map[string]any
	DisclosedClaims map[string]any
	KeyBindingValid bool
	ExpiresAt       *time.Time
	IssuedAt        *time.Time
	VCTM            *VCTM
}

SDJWTVerificationResult contains the result of SD-JWT verification and claim extraction.

func (*SDJWTVerificationResult) GetClaims added in v0.5.7

func (r *SDJWTVerificationResult) GetClaims() map[string]any

GetClaims returns all claims (both standard and disclosed).

func (*SDJWTVerificationResult) GetDisclosedClaims added in v0.5.7

func (r *SDJWTVerificationResult) GetDisclosedClaims() map[string]any

GetDisclosedClaims returns only the selectively disclosed claims.

type SVGTemplateProperties

type SVGTemplateProperties struct {
	// Orientation: "portrait" or "landscape" (OPTIONAL)
	Orientation string `json:"orientation,omitempty"`

	// ColorScheme: "light" or "dark" (OPTIONAL)
	ColorScheme string `json:"color_scheme,omitempty"`

	// Contrast: "normal" or "high" (OPTIONAL)
	Contrast string `json:"contrast,omitempty"`
}

SVGTemplateProperties specifies SVG template characteristics per section 8.1.2.1 Used to select the best template for display based on device and user preferences

type SVGTemplates

type SVGTemplates struct {
	// URI pointing to the SVG template (REQUIRED)
	URI string `json:"uri"`

	// URLIntegrity provides Subresource Integrity protection per section 7 (OPTIONAL)
	// Note: Field name uses "URL" but JSON uses "uri#integrity" to match spec
	URLIntegrity string `json:"uri#integrity,omitempty"`

	// Properties specifies template properties per section 8.1.2.1 (OPTIONAL for single template, REQUIRED for multiple)
	Properties SVGTemplateProperties `json:"properties"`
}

SVGTemplates contains SVG template information per section 8.1.2

type Signer

type Signer interface {
	Sign(ctx context.Context, data []byte) ([]byte, error)
	Algorithm() string
	KeyID() string
	PublicKey() any
}

Signer defines the interface for cryptographic signing operations.

type SimpleRendering

type SimpleRendering struct {
	Logo Logo `json:"logo"`

	// BackgroundImage contains background image information (OPTIONAL per section 8.1.1.2)
	BackgroundImage *Logo `json:"background_image,omitempty"`

	// BackgroundColor is an RGB color value per W3C CSS Color (OPTIONAL per section 8.1.1)
	BackgroundColor string `json:"background_color,omitempty"`

	// TextColor is an RGB color value per W3C CSS Color (OPTIONAL per section 8.1.1)
	TextColor string `json:"text_color,omitempty"`
}

SimpleRendering provides basic rendering properties per section 8.1.1 Intended for applications that don't support SVG rendering

type StaticKeyResolver added in v0.5.7

type StaticKeyResolver struct {
	Key crypto.PublicKey
}

StaticKeyResolver is a simple key resolver that returns a fixed key.

func (*StaticKeyResolver) ResolveKey added in v0.5.7

func (r *StaticKeyResolver) ResolveKey(ctx context.Context, issuer string, keyID string) (crypto.PublicKey, error)

ResolveKey returns the static key regardless of issuer/keyID.

type Token

type Token string

Token represents an SD-JWT token string that can be split into components

func (Token) Parse

func (t Token) Parse() (*ParsedCredential, error)

Parse parses an SD-JWT token into credential claims and selective disclosures Returns the parsed credential with claims, disclosures, header, signature, and optional key binding

func (Token) Split

func (t Token) Split() (string, string, string, []string, []string, error)

Split splits the token into header, body, signature, selective disclosure, keybinding, or error

Example
package main

import (
	"fmt"

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

func main() {
	// SD-JWT format: <header>.<payload>.<signature>~<disclosure1>~<disclosure2>~
	token := sdjwtvc.Token("eyJhbGciOiJFUzI1NiJ9.eyJ2Y3QiOiJpZCJ9.c2ln~ZGlzY2xvc3VyZTE~ZGlzY2xvc3VyZTI~")

	header, body, sig, disclosures, kb, err := token.Split()
	if err != nil {
		fmt.Println("error:", err)
		return
	}

	fmt.Println("header:", header)
	fmt.Println("body:", body)
	fmt.Println("sig:", sig)
	fmt.Println("disclosures:", len(disclosures))
	fmt.Println("kb:", kb)
}
Output:
header: eyJhbGciOiJFUzI1NiJ9
body: eyJ2Y3QiOiJpZCJ9
sig: c2ln
disclosures: 2
kb: []

type TokenStatusListReference

type TokenStatusListReference struct {
	// Index is the index within the section for this credential's status
	Index int64
	// URI is the full Status List Token URI (e.g., https://example.com/statuslists/0)
	URI string
}

TokenStatusListReference contains the status list reference to embed in a credential per draft-ietf-oauth-status-list Section 5 (Referenced Token)

type VCTM

type VCTM struct {
	// VCT is the verifiable credential type identifier (REQUIRED per section 6.2)
	// Must match the vct claim value in the SD-JWT VC
	VCT string `json:"vct"`

	// Name is a human-readable name for developers (OPTIONAL per section 6.2)
	Name string `json:"name,omitempty"`

	// Description is a human-readable description for developers (OPTIONAL per section 6.2)
	Description string `json:"description,omitempty"`

	// Comment allows for additional developer notes (extension)
	Comment string `json:"$comment,omitempty"`

	// Display contains rendering information per section 8
	// Array of display objects for different locales (OPTIONAL per section 6.2)
	Display []VCTMDisplay `json:"display,omitempty"`

	// Claims contains claim metadata per section 9
	// Array of claim information for validation and display (OPTIONAL per section 6.2)
	Claims []Claim `json:"claims,omitempty"`

	// Extends references another type that this type extends (OPTIONAL per section 6.4)
	// URI of the parent type metadata
	Extends string `json:"extends,omitempty"`

	// ExtendsIntegrity provides integrity protection per section 7
	// Uses Subresource Integrity format (OPTIONAL)
	ExtendsIntegrity string `json:"extends#integrity,omitempty"`
}

VCTM is the Verifiable Credential Type Metadata per SD-JWT VC draft-13 section 6. Type Metadata provides information about credential types including: - Display properties for rendering credentials in wallets - Claim metadata for validation and selective disclosure rules - Extensibility through the extends mechanism This enables issuers, verifiers, and wallets to process credentials consistently.

Example
package main

import (
	"fmt"

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

func strPtr(s string) *string { return &s }

func main() {
	vctm := &sdjwtvc.VCTM{
		VCT:         "https://example.com/credentials/identity",
		Name:        "Identity Credential",
		Description: "A verifiable identity credential",
		Display: []sdjwtvc.VCTMDisplay{
			{
				Locale:      "en-US",
				Name:        "Identity Credential",
				Description: "Official identity document",
				Rendering: &sdjwtvc.Rendering{
					Simple: sdjwtvc.SimpleRendering{
						Logo: sdjwtvc.Logo{
							URI:     "https://example.com/logo.png",
							AltText: "Logo",
						},
						BackgroundColor: "#003366",
						TextColor:       "#FFFFFF",
					},
				},
			},
		},
		Claims: []sdjwtvc.Claim{
			{
				Path: []*string{strPtr("given_name")},
				Display: []sdjwtvc.ClaimDisplay{
					{Locale: "en-US", Label: "Given Name"},
				},
				SD:        "always",
				Mandatory: true,
			},
			{
				Path: []*string{strPtr("family_name")},
				Display: []sdjwtvc.ClaimDisplay{
					{Locale: "en-US", Label: "Family Name"},
				},
				SD:        "always",
				Mandatory: true,
			},
		},
	}

	fmt.Println("VCT:", vctm.VCT)
	fmt.Println("Name:", vctm.Name)
	fmt.Println("Claims:", len(vctm.Claims))
}
Output:
VCT: https://example.com/credentials/identity
Name: Identity Credential
Claims: 2

func (*VCTM) Attributes

func (v *VCTM) Attributes() map[string]map[string][]string

Attributes parse vctm claims and return a map of labels and their paths for each locale

Example
package main

import (
	"fmt"

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

func strPtr(s string) *string { return &s }

func main() {
	vctm := &sdjwtvc.VCTM{
		VCT: "https://example.com/credentials/identity",
		Claims: []sdjwtvc.Claim{
			{
				Path: []*string{strPtr("given_name")},
				Display: []sdjwtvc.ClaimDisplay{
					{Locale: "en-US", Label: "Given Name"},
					{Locale: "sv-SE", Label: "Förnamn"},
				},
				SD: "always",
			},
		},
	}

	attrs := vctm.Attributes()
	fmt.Println("en-US Given Name path:", attrs["en-US"]["Given Name"])
	fmt.Println("sv-SE Förnamn path:", attrs["sv-SE"]["Förnamn"])
}
Output:
en-US Given Name path: [given_name]
sv-SE Förnamn path: [given_name]

func (*VCTM) AttributesWithoutObjects

func (v *VCTM) AttributesWithoutObjects() map[string]map[string][]string

AttributesWithoutObjects parse vctm claims and return a map of labels and their paths for each locale, excluding claims that represent objects (claims with nested paths)

func (*VCTM) ClaimJSONPath

func (v *VCTM) ClaimJSONPath() (*VCTMJSONPath, error)

ClaimJSONPath returns the JSON paths for the VCTM claims

func (*VCTM) SRIIntegrity

func (v *VCTM) SRIIntegrity(rawBytes []byte) (string, error)

SRIIntegrity computes the Subresource Integrity (SRI) hash of the VCTM document as defined in W3C SRI spec and SD-JWT VC draft-14 Section 6. The rawBytes parameter should be the original VCTM document bytes (not re-marshalled) to preserve exact byte-level integrity. If rawBytes is nil, the VCTM is marshalled to JSON. Returns a string like "sha256-<base64-hash>".

Example
package main

import (
	"fmt"

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

func main() {
	vctm := &sdjwtvc.VCTM{
		VCT:  "https://example.com/credentials/identity",
		Name: "Identity Credential",
	}

	integrity, err := vctm.SRIIntegrity(nil)
	if err != nil {
		fmt.Println("error:", err)
		return
	}
	fmt.Println("has prefix:", integrity[:7])
}
Output:
has prefix: sha256-

type VCTMDisplay

type VCTMDisplay struct {
	// Locale is the language tag per RFC 5646 (REQUIRED per section 8)
	// Per draft-12+ this field is named "locale" in JSON (changed from "lang" in earlier drafts)
	Locale string `json:"locale"`

	// Name is a human-readable name for end users (REQUIRED per section 8)
	Name string `json:"name"`

	// Description is a human-readable description for end users (OPTIONAL per section 8)
	Description string `json:"description,omitempty"`

	// Rendering contains rendering methods per section 8.1 (OPTIONAL)
	Rendering *Rendering `json:"rendering,omitempty"`
}

VCTMDisplay represents display information for a credential type per SD-JWT VC draft-13 section 8 Each display object provides locale-specific rendering information for wallets

type VCTMJSONPath

type VCTMJSONPath struct {
	Displayable map[string]string `json:"displayable"`
	AllClaims   []string          `json:"all_claims"`
}

VCTMJSONPath holds JSON path information for VCTM claims

type ValidationError

type ValidationError struct {
	Field   string
	Message string
}

ValidationError represents a validation error with details

func (*ValidationError) Error

func (e *ValidationError) Error() string

type ValidationErrors

type ValidationErrors struct {
	Errors []ValidationError
}

ValidationErrors represents multiple validation errors

func (*ValidationErrors) AddError

func (e *ValidationErrors) AddError(field, message string)

AddError adds a validation error

func (*ValidationErrors) Error

func (e *ValidationErrors) Error() string

func (*ValidationErrors) HasErrors

func (e *ValidationErrors) HasErrors() bool

HasErrors returns true if there are validation errors

type VerificationOptions

type VerificationOptions struct {
	// RequireKeyBinding: whether KB-JWT must be present
	RequireKeyBinding bool
	// ExpectedNonce: nonce to validate in KB-JWT (required if KB-JWT present)
	ExpectedNonce string
	// ExpectedAudience: audience to validate in KB-JWT (required if KB-JWT present)
	ExpectedAudience string
	// AllowedClockSkew: allowed time skew for exp/iat validation (default: 5 minutes)
	AllowedClockSkew time.Duration
	// ValidateTime: whether to validate exp/iat claims (default: true)
	ValidateTime bool
	// TrustEvaluator: optional trust evaluator for validating issuer's key
	// When set and x5c header is present, the certificate chain will be validated
	// against the trust framework. If not set, the provided public key is used directly.
	TrustEvaluator trust.TrustEvaluator
	// TrustContext: context for trust evaluation (optional, defaults to context.Background())
	TrustContext context.Context
	// CredentialType: credential type for policy routing (e.g., "PID", "mDL")
	// If set, this is passed to the TrustEvaluator for policy-based routing.
	// If not set, it will be extracted from the 'vct' claim if present.
	CredentialType string
	// CryptoExt provides extended algorithm and certificate support
	// (e.g. brainpool curves).
	CryptoExt *cryptoutil.Extensions
}

VerificationOptions contains options for verification

type VerificationResult

type VerificationResult struct {
	Valid            bool           // Overall validity
	Header           map[string]any // JWT header
	Claims           map[string]any // All claims (including disclosed)
	DisclosedClaims  map[string]any // Only the selectively disclosed claims
	Disclosures      []Disclosure   // Parsed disclosures
	VCTM             *VCTM          // Verifiable Credential Type Metadata
	KeyBindingValid  bool           // Whether KB-JWT is valid (if present)
	KeyBindingClaims map[string]any // KB-JWT claims (if present)
	Errors           []error        // Any validation errors
}

VerificationResult contains the result of SD-JWT verification

Jump to

Keyboard shortcuts

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