### Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/configuration.md Example of using HTTPClientOptions. ```go package main import ( "log" "time" "github.com/MicahParks/jwkset" "golang.org/x/time/rate" ) func main() { localStore := jwkset.NewMemoryStorage() // ... add local keys ... options := jwkset.HTTPClientOptions{ Given: localStore, HTTPURLs: map[string]jwkset.Storage{ "https://auth.example.com/.well-known/jwks.json": nil, "https://backup.example.com/.well-known/jwks.json": nil, }, PrioritizeHTTP: false, RateLimitWaitMax: 5 * time.Minute, RefreshUnknownKID: rate.NewLimiter(rate.Every(10*time.Minute), 1), } client, err := jwkset.NewHTTPClient(options) if err != nil { log.Fatal(err) } _ = client } ``` -------------------------------- ### Usage Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/configuration.md Example of creating a JWK with specific options. ```go package main import ( "crypto/ed25519" "crypto/rand" "log" "github.com/MicahParks/jwkset" ) func main() { pub, _, _ := ed25519.GenerateKey(rand.Reader) options := jwkset.JWKOptions{ Marshal: jwkset.JWKMarshalOptions{ Private: false, // Don't include private key in JSON }, Metadata: jwkset.JWKMetadataOptions{ ALG: jwkset.AlgEdDSA, KID: "my-key", USE: jwkset.UseSig, KEYOPS: []jwkset.KEYOPS{jwkset.KeyOpsSign, jwkset.KeyOpsVerify}, }, Validate: jwkset.JWKValidateOptions{ SkipAll: false, SkipUse: false, SkipKeyOps: false, SkipMetadata: false, SkipX5UScheme: false, CheckX509ValidTime: false, StrictPadding: false, }, X509: jwkset.JWKX509Options{ X5C: nil, X5U: "", }, } jwk, err := jwkset.NewJWKFromKey(pub, options) if err != nil { log.Fatal(err) } _ = jwk } ``` -------------------------------- ### Storage.KeyReplaceAll Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/storage.md Example demonstrating how to atomically replace all keys in storage with a new set. ```Go package main import ( "context" "log" "github.com/MicahParks/jwkset" ) func main() { ctx := context.Background() store := jwkset.NewMemoryStorage() newKeys := []jwkset.JWK{} // Build new key set // ... populate newKeys ... err := store.KeyReplaceAll(ctx, newKeys) if err != nil { log.Fatal(err) } println("Keys replaced") } ``` -------------------------------- ### Example: With Refresh Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/configuration.md Example of using HTTPClientStorageOptions with refresh interval. ```go package main import ( "context" "log" "time" "github.com/MicahParks/jwkset" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() options := jwkset.HTTPClientStorageOptions{ Ctx: ctx, HTTPTimeout: 30 * time.Second, RefreshInterval: 1 * time.Hour, RefreshErrorHandler: func(ctx context.Context, err error) { log.Printf("HTTP refresh error: %v", err) }, } store, err := jwkset.NewStorageFromHTTP( "https://example.com/.well-known/jwks.json", options, ) if err != nil { log.Fatal(err) } // store refreshes every hour in background // Context cancellation stops the refresh goroutine _ = store } ``` -------------------------------- ### Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/configuration.md Example of marshaling JWKs with and without private material. ```go package main import ( "context" "log" "github.com/MicahParks/jwkset" ) func main() { // Create storage with keys store := jwkset.NewMemoryStorage() // ... add keys ... ctx := context.Background() // Get public keys only publicJSON, err := store.JSON(ctx) if err != nil { log.Fatal(err) } // Get all keys with private material privateJSON, err := store.JSONPrivate(ctx) if err != nil { log.Fatal(err) } _ = publicJSON _ = privateJSON } ``` -------------------------------- ### ErrGetX5U Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/errors.md Demonstrates an example of ErrGetX5U being triggered when fetching certificates from a URL fails. ```go package main import ( "errors" "log" "net/url" "github.com/MicahParks/jwkset" ) func main() { u, _ := url.ParseRequestURI("https://invalid.example.com/certs.pem") certs, err := jwkset.DefaultGetX5U(u) if err != nil { if errors.Is(err, jwkset.ErrGetX5U) { log.Println("Failed to fetch certificates from X5U:", err) } } _ = certs } ``` -------------------------------- ### Storage.JSON Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/storage.md Example showing how to retrieve public keys from storage in JWK Set JSON format. ```Go package main import ( "context" "encoding/json" "log" "github.com/MicahParks/jwkset" ) func main() { ctx := context.Background() store := jwkset.NewMemoryStorage() // ... add keys to store ... data, err := store.JSON(ctx) if err != nil { log.Fatal(err) } var jwks map[string]interface{} json.Unmarshal(data, &jwks) println(string(data)) } ``` -------------------------------- ### Storage.JSONPrivate Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/storage.md Example demonstrating how to retrieve all keys, including private material, in JWK Set JSON format. ```Go package main import ( "context" "log" "github.com/MicahParks/jwkset" ) func main() { ctx := context.Background() store := jwkset.NewMemoryStorage() // ... add keys to store ... data, err := store.JSONPrivate(ctx) if err != nil { log.Fatal(err) } println(string(data)) } ``` -------------------------------- ### Checking Errors during HTTP Client Setup Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/errors.md Example of checking for various errors when setting up an HTTP client. ```go package main import ( "context" "errors" "log" "github.com/MicahParks/jwkset" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() urls := []string{"https://example.com/.well-known/jwks.json"} client, err := jwkset.NewDefaultHTTPClientCtx(ctx, urls) if err != nil { if errors.Is(err, jwkset.ErrNewClient) { log.Println("Client creation failed:", err) } else if errors.Is(err, jwkset.ErrInvalidHTTPStatusCode) { log.Println("HTTP error on initial request:", err) } else { log.Println("Unknown error:", err) } } _ = client } ``` -------------------------------- ### ErrX509Mismatch Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/errors.md Demonstrates an example of ErrX509Mismatch being triggered when trying to create a JWK with mismatched certificate and key options. ```go package main import ( "crypto/x509" "errors" "log" "github.com/MicahParks/jwkset" ) func main() { var cert *x509.Certificate // ... load cert from PEM ... // Try to create JWK with mismatched ALG options := jwkset.JWKOptions{ X509: jwkset.JWKX509Options{ X5C: []*x509.Certificate{cert}, }, Metadata: jwkset.JWKMetadataOptions{ ALG: jwkset.AlgRS256, // Wrong if cert is EdDSA }, } _, err := jwkset.NewJWKFromX5C(options) if err != nil { if errors.Is(err, jwkset.ErrX509Mismatch) { log.Println("Certificate doesn't match key options") } } } ``` -------------------------------- ### Example: Creating a JWK from X.509 Certificate Chain Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/configuration.md Demonstrates how to create a JWK using an X.509 certificate chain and a URI. ```go package main import ( "crypto/x509" "log" "github.com/MicahParks/jwkset" ) func main() { var certs []*x509.Certificate // ... load certs from PEM ... options := jwkset.JWKOptions{ X509: jwkset.JWKX509Options{ X5C: certs, X5U: "https://example.com/certs.pem", }, } jwk, err := jwkset.NewJWKFromX5C(options) if err != nil { log.Fatal(err) } _ = jwk } ``` -------------------------------- ### Example: Creating a JWK from an ECDSA Key Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/configuration.md Demonstrates how to create a JWK from an existing ECDSA key using JWKMetadataOptions. ```go package main import ( "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "log" "github.com/MicahParks/jwkset" ) func main() { // Create ECDSA P-256 key key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) options := jwkset.JWKOptions{ Metadata: jwkset.JWKMetadataOptions{ ALG: jwkset.AlgES256, KID: "my-ecdsa-key", USE: jwkset.UseSig, KEYOPS: []jwkset.KEYOPS{jwkset.KeyOpsSign, jwkset.KeyOpsVerify}, }, } jwk, err := jwkset.NewJWKFromKey(key, options) if err != nil { log.Fatal(err) } _ = jwk } ``` -------------------------------- ### ErrKeyNotFound Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/errors.md Demonstrates how to check for ErrKeyNotFound when reading a key from storage. ```go package main import ( "context" "errors" "log" "github.com/MicahParks/jwkset" ) func main() { store := jwkset.NewMemoryStorage() ctx := context.Background() jwk, err := store.KeyRead(ctx, "nonexistent-key") if err != nil { if errors.Is(err, jwkset.ErrKeyNotFound) { log.Println("Key not found in storage") } } _ = jwk } ``` -------------------------------- ### Install jwkset command line tool Source: https://github.com/micahparks/jwkset/blob/main/README.md Installs the jwkset command line tool for generating JWK Sets. ```bash go install github.com/MicahParks/jwkset/cmd/jwkset@latest ``` -------------------------------- ### Marshaling Workflow Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/marshal.md Demonstrates the workflow for creating, marshaling, and unmarshaling JWKs and JWK Sets. ```go package main import ( "crypto/ed25519" "crypto/rand" "encoding/json" "log" "github.com/MicahParks/jwkset" ) func main() { // 1. Create a JWK from key material pub, priv, _ := ed25519.GenerateKey(rand.Reader) jwk, err := jwkset.NewJWKFromKey(priv, jwkset.JWKOptions{ Metadata: jwkset.JWKMetadataOptions{ KID: "my-key", ALG: jwkset.AlgEdDSA, }, }) if err != nil { log.Fatal(err) } // 2. Get the Marshal representation marshal := jwk.Marshal() println("KID:", marshal.KID) println("KTY:", marshal.KTY) // 3. Serialize to JSON data, err := json.Marshal(marshal) if err != nil { log.Fatal(err) } println("JSON:", string(data)) // 4. Recreate JWK from JSON newJWK, err := jwkset.NewJWKFromRawJSON( data, jwkset.JWKMarshalOptions{}, jwkset.JWKValidateOptions{}, ) if err != nil { log.Fatal(err) } println("Recreated JWK with KID:", newJWK.Marshal().KID) // 5. Create JWK Set from multiple keys var keys []jwkset.JWK keys = append(keys, jwk) // ... add more keys ... // Convert to JWKSMarshal for JSON serialization store := jwkset.NewMemoryStorage() store.KeyWrite(nil, jwk) jwks, err := store.Marshal(nil) if err != nil { log.Fatal(err) } data, err = json.MarshalIndent(jwks, "", " ") if err != nil { log.Fatal(err) } println(string(data)) } ``` -------------------------------- ### Creating options with algorithm specification Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/types.md Example of creating JWKOptions with metadata and validation settings. ```go package main import ( "log" "github.com/MicahParks/jwkset" ) func main() { options := jwkset.JWKOptions{ Metadata: jwkset.JWKMetadataOptions{ ALG: jwkset.AlgEdDSA, KID: "key-1", USE: jwkset.UseSig, KEYOPS: []jwkset.KEYOPS{jwkset.KeyOpsSign, jwkset.KeyOpsVerify}, }, Validate: jwkset.JWKValidateOptions{ SkipUse: false, SkipKeyOps: false, SkipMetadata: false, }, } // Use options to create JWK // ... ``` -------------------------------- ### JWKMarshal Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/marshal.md Example of how to marshal a JWK object to its intermediate representation and then serialize it to JSON. ```Go package main import ( "encoding/json" "log" "github.com/MicahParks/jwkset" ) func main() { // Create JWK from key var jwk jwkset.JWK // ... create jwk ... // Get intermediate representation marshal := jwk.Marshal() // Serialize to JSON data, err := json.MarshalIndent(marshal, "", " ") if err != nil { log.Fatal(err) } println(string(data)) } ``` -------------------------------- ### ErrX509Infer Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/errors.md Demonstrates an example of ErrX509Infer being triggered when the PEM block type is unknown. ```go package main import ( "encoding/pem" "errors" "log" "github.com/MicahParks/jwkset" ) func main() { block := &pem.Block{ Type: "UNKNOWN KEY", Bytes: []byte{}, } _, err := jwkset.LoadX509KeyInfer(block) if err != nil { if errors.Is(err, jwkset.ErrX509Infer) { log.Println("Cannot infer key type from PEM block") } } } ``` -------------------------------- ### ErrUnsupportedKey Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/errors.md Example demonstrating an ErrUnsupportedKey trigger condition by attempting to use an unsupported key type. ```go package main import ( "errors" "log" "github.com/MicahParks/jwkset" ) func main() { // Attempt to use unsupported key type jwk, err := jwkset.NewJWKFromKey(12345, jwkset.JWKOptions{}) if err != nil { if errors.Is(err, jwkset.ErrUnsupportedKey) { log.Println("Key type not supported by jwkset") } } } ``` -------------------------------- ### ErrKeyUnmarshalParameter Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/errors.md Demonstrates an example of ErrKeyUnmarshalParameter being triggered when a required parameter for an EC JWK is missing. ```go package main import ( "encoding/json" "errors" "log" "github.com/MicahParks/jwkset" ) func main() { // EC JWK missing Y coordinate rawJSON := []byte(`{ "kty": "EC", "crv": "P-256", "x": "WKn-ZIGevcwGIyyrzFoZNBdaq9_TsqzGl96oc0CWuis" }`) _, err := jwkset.NewJWKFromRawJSON( rawJSON, jwkset.JWKMarshalOptions{}, jwkset.JWKValidateOptions{}, ) if err != nil { if errors.Is(err, jwkset.ErrKeyUnmarshalParameter) { log.Println("Invalid parameter in JWK:", err) } } } ``` -------------------------------- ### NewHTTPClient Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/http-client.md Creates a JWK Set client that can fetch keys from multiple HTTP URLs and/or local storage. ```go package main import ( "context" "log" "github.com/MicahParks/jwkset" ) func main() { ctx := context.Background() store := jwkset.NewMemoryStorage() options := jwkset.HTTPClientOptions{ Given: store, HTTPURLs: map[string]jwkset.Storage{ "https://example.com/.well-known/jwks.json": nil, // Will be auto-created }, } client, err := jwkset.NewHTTPClient(options) if err != nil { log.Fatal(err) } // client now supports reading from both given storage and HTTP URL jwk, err := client.KeyRead(ctx, "key-id") if err != nil { log.Fatal(err) } } ``` -------------------------------- ### ErrNewClient Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/errors.md Illustrates handling ErrNewClient when no sources are provided for an HTTP client. ```go package main import ( "errors" "log" "github.com/MicahParks/jwkset" ) func main() { // No URLs provided _, err := jwkset.NewDefaultHTTPClient([]string{}) if err != nil { if errors.Is(err, jwkset.ErrNewClient) { log.Println("Failed to create client:", err) } } } ``` -------------------------------- ### Example: Strict Validation Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/configuration.md Demonstrates how to configure JWK validation for strict checking, including certificate expiry and HTTPS for X5U. ```go package main import ( "crypto/x509" "log" "time" "github.com/MicahParks/jwkset" ) func main() { var cert *x509.Certificate // ... load cert from PEM ... options := jwkset.JWKOptions{ X509: jwkset.JWKX509Options{ X5C: []*x509.Certificate{cert}, }, Validate: jwkset.JWKValidateOptions{ CheckX509ValidTime: true, // Check cert expiry SkipAll: false, // Don't skip any checks SkipUse: false, SkipKeyOps: false, SkipMetadata: false, SkipX5UScheme: false, // Enforce HTTPS for X5U StrictPadding: true, // Strict base64url padding }, } // This JWK will be thoroughly validated jwk, err := jwkset.NewJWKFromX5C(options) if err != nil { log.Fatal(err) } _ = jwk } ``` -------------------------------- ### ToStorage Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/marshal.md Converts JWKSMarshal to a Storage implementation. ```go package main import ( "context" "encoding/json" "log" "github.com/MicahParks/jwkset" ) func main() { // Fetch and parse JWK Set from remote source var data []byte // ... fetch and read JSON ... var jwks jwkset.JWKSMarshal err := json.Unmarshal(data, &jwks) if err != nil { log.Fatal(err) } // Convert to storage store, err := jwks.ToStorage() if err != nil { log.Fatal(err) } // Use storage to read keys ctx := context.Background() jwk, err := store.KeyRead(ctx, "key-id") if err != nil { log.Fatal(err) } println("Retrieved key:", jwk.Marshal().KID) } ``` -------------------------------- ### Example: Lenient Validation Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/configuration.md Shows how to configure JWK validation to skip all checks, which is not recommended for production environments. ```go package main import ( "log" "github.com/MicahParks/jwkset" ) func main() { options := jwkset.JWKOptions{ Validate: jwkset.JWKValidateOptions{ SkipAll: true, // Skip all validation (not recommended for production) }, } // Load keys without strict validation // var key any // jwk, _ := jwkset.NewJWKFromKey(key, options) _ = options } ``` -------------------------------- ### Minimal configuration Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/README.md Example of the bare minimum JWK options, relying on default values. ```go jwkset.JWKOptions{ Metadata: jwkset.JWKMetadataOptions{KID: "key-1"}, } ``` -------------------------------- ### Minimal JWK Configuration Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/configuration.md This example demonstrates the bare minimum configuration required to create a JWK from an Ed25519 public key. Other fields will default to their zero/default values, enabling validation, disabling X.509 support, and marshaling only public components. ```go package main import ( "crypto/ed25519" "crypto/rand" "log" "github.com/MicahParks/jwkset" ) func main() { pub, _, _ := ed25519.GenerateKey(rand.Reader) // Minimal options options := jwkset.JWKOptions{ Metadata: jwkset.JWKMetadataOptions{ KID: "key-1", }, } jwk, err := jwkset.NewJWKFromKey(pub, options) if err != nil { log.Fatal(err) } _ = jwk } ``` -------------------------------- ### NewDefaultHTTPClient Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/http-client.md Creates a JWK Set client with sensible defaults for common use cases. Automatically refreshes remote sources hourly and implements smart caching. ```go package main import ( "context" "log" "github.com/MicahParks/jwkset" ) func main() { urls := []string{ "https://example.com/.well-known/jwks.json", } client, err := jwkset.NewDefaultHTTPClient(urls) if err != nil { log.Fatal(err) } ctx := context.Background() jwk, err := client.KeyRead(ctx, "key-id") if err != nil { log.Fatal(err) } } ``` -------------------------------- ### NewDefaultHTTPClientCtx Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/http-client.md Same as NewDefaultHTTPClient but with explicit context for controlling the refresh goroutine lifetime. ```go package main import ( "context" "log" "time" "github.com/MicahParks/jwkset" ) func main() { ctx, cancel := context.WithCancel(context.Background()) defer cancel() urls := []string{ "https://example.com/.well-known/jwks.json", } client, err := jwkset.NewDefaultHTTPClientCtx(ctx, urls) if err != nil { log.Fatal(err) } // Use client... time.Sleep(2 * time.Minute) // Refresh goroutine continues in background // Will stop when ctx is canceled (by defer above at function exit) } ``` -------------------------------- ### ErrInvalidHTTPStatusCode Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/errors.md Shows how to handle ErrInvalidHTTPStatusCode when creating storage from an HTTP source. ```go package main import ( "errors" "log" "github.com/MicahParks/jwkset" ) func main() { options := jwkset.HTTPClientStorageOptions{ HTTPExpectedStatus: 200, } _, err := jwkset.NewStorageFromHTTP( "https://example.com/invalid.json", options, ) if err != nil { if errors.Is(err, jwkset.ErrInvalidHTTPStatusCode) { log.Println("HTTP error:", err) } } } ``` -------------------------------- ### Checking IANA registration Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/types.md Example of checking if algorithms, curves, or key uses are IANA registered. ```go package main import ( "log" "github.com/MicahParks/jwkset" ) func main() { // Check if algorithm is registered if !jwkset.AlgEdDSA.IANARegistered() { log.Fatal("Algorithm not registered") } // Check if curve is supported if !jwkset.CrvEd25519.IANARegistered() { log.Fatal("Curve not supported") } // Check if key use is valid if !jwkset.UseSig.IANARegistered() { log.Fatal("Use value invalid") } } ``` -------------------------------- ### String Types (Enumerations) Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/INDEX.md Examples of common string types (enumerations) used in the jwkset package, such as algorithms, curves, key types, key operations, and key uses. ```go // Algorithm alg := jwkset.AlgRS256 // "RS256" alg := jwkset.AlgEdDSA // "EdDSA" // Curve crv := jwkset.CrvP256 // "P-256" crv := jwkset.CrvEd25519 // "Ed25519" // Key type kty := jwkset.KtyRSA // "RSA" kty := jwkset.KtyOKP // "OKP" // Key operation op := jwkset.KeyOpsSign // "sign" op := jwkset.KeyOpsVerify // "verify" // Key use use := jwkset.UseSig // "sig" use := jwkset.UseEnc // "enc" ``` -------------------------------- ### Wrapped Error Chains Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/errors.md Demonstrates checking for base errors in wrapped error chains using errors.Is. ```go package main import ( "crypto/ed25519" "crypto/rand" "errors" "log" "github.com/MicahParks/jwkset" ) func main() { pub, _, _ := ed25519.GenerateKey(rand.Reader) _, err := jwkset.NewJWKFromKey(pub, jwkset.JWKOptions{ Metadata: jwkset.JWKMetadataOptions{ ALG: jwkset.AlgRS256, // Wrong }, }) // err is wrapped with context, but we can still check the base error if errors.Is(err, jwkset.ErrOptions) { log.Println("Found ErrOptions in error chain") } // Print full error chain log.Println(err) } ``` -------------------------------- ### Usage of jwkset command line tool Source: https://github.com/micahparks/jwkset/blob/main/README.md Example usage of the jwkset command line tool to generate a JWK Set from PEM encoded keys or certificates. ```bash jwkset mykey.pem mycert.crt ``` -------------------------------- ### ErrJWKValidation Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/errors.md Example demonstrating an ErrJWKValidation trigger condition with an invalid key use value. ```go package main import ( "errors" "log" "github.com/MicahParks/jwkset" ) func main() { // Create JWK with invalid key use options := jwkset.JWKOptions{ Metadata: jwkset.JWKMetadataOptions{ USE: jwkset.USE("invalid"), }, } // ... attempt to create JWK ... _, err := jwkset.NewJWKFromKey([]byte("key"), options) if err != nil { if errors.Is(err, jwkset.ErrJWKValidation) { log.Println("Validation error:", err) } } } ``` -------------------------------- ### Self-host with Docker Source: https://github.com/micahparks/jwkset/blob/main/website/README.md Run the pre-built Docker container to self-host the website. ```bash docker run --rm -p 8080:8080 micahparks/jwksetcom ``` -------------------------------- ### ErrOptions Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/errors.md Example demonstrating an ErrOptions trigger condition where an Ed25519 key is used with a non-EdDSA algorithm. ```go package main import ( "crypto/ed25519" "crypto/rand" "errors" "log" "github.com/MicahParks/jwkset" ) func main() { pub, _, _ := ed25519.GenerateKey(rand.Reader) // This will return ErrOptions: Ed25519 key with wrong algorithm options := jwkset.JWKOptions{ Metadata: jwkset.JWKMetadataOptions{ ALG: jwkset.AlgRS256, // Wrong for Ed25519 }, } _, err := jwkset.NewJWKFromKey(pub, options) if err != nil { if errors.Is(err, jwkset.ErrOptions) { log.Println("Options error:", err) } } } ``` -------------------------------- ### JWKSlice Example Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/marshal.md Converts JWKSMarshal to a slice of JWK objects. ```go package main import ( "encoding/json" "log" "github.com/MicahParks/jwkset" ) func main() { // Unmarshal JSON to JWKSMarshal var data []byte // ... read JSON ... var jwks jwkset.JWKSMarshal err := json.Unmarshal(data, &jwks) if err != nil { log.Fatal(err) } // Convert to JWK slice keys, err := jwks.JWKSlice() if err != nil { log.Fatal(err) } for _, key := range keys { println("Key ID:", key.Marshal().KID) } } ``` -------------------------------- ### Loading Certificate Chain Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/x509-utilities.md Reads a PEM file containing a certificate chain, loads all certificates using LoadCertificates, and then creates a JWK from the certificate chain with specified options, including the certificate chain (X5C) and a Key ID (KID). ```go package main import ( "io/ioutil" "log" "github.com/MicahParks/jwkset" ) func main() { // Read PEM file with certificate chain pemData, err := ioutil.ReadFile("cert-chain.pem") if err != nil { log.Fatal(err) } // Load all certificates certs, err := jwkset.LoadCertificates(pemData) if err != nil { log.Fatal(err) } // Create JWK from certificate chain options := jwkset.JWKOptions{ X509: jwkset.JWKX509Options{ X5C: certs, }, Metadata: jwkset.JWKMetadataOptions{ KID: "cert-chain-key", }, } jwk, err := jwkset.NewJWKFromX5C(options) if err != nil { log.Fatal(err) } println("Created JWK from certificate chain") println("Number of certificates:", len(jwk.X509().X5C)) } ``` -------------------------------- ### Creating JWK from Loaded Key Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/x509-utilities.md Reads a PEM file, decodes the PEM block, loads the key using LoadX509KeyInfer, and then creates a JWK from the loaded key with specified options, including a Key ID (KID). ```go package main import ( "encoding/pem" "io/ioutil" "log" "github.com/MicahParks/jwkset" ) func main() { // Read and parse PEM file pemData, err := ioutil.ReadFile("key.pem") if err != nil { log.Fatal(err) } block, _ := pem.Decode(pemData) if block == nil { log.Fatal("No PEM block found") } // Load key key, err := jwkset.LoadX509KeyInfer(block) if err != nil { log.Fatal(err) } // Create JWK options := jwkset.JWKOptions{ Metadata: jwkset.JWKMetadataOptions{ KID: "imported-key", }, } jwk, err := jwkset.NewJWKFromKey(key, options) if err != nil { log.Fatal(err) } println("Created JWK from PEM file") } ``` -------------------------------- ### HTTPClientOptions Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/configuration.md Configuration for HTTP client with multiple sources. ```go type HTTPClientOptions struct { Given Storage HTTPURLs map[string]Storage PrioritizeHTTP bool RateLimitWaitMax time.Duration RefreshUnknownKID *rate.Limiter } ``` -------------------------------- ### Storage.KeyReadAll Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/storage.md Reads all keys from storage as a snapshot. ```go func (s Storage) KeyReadAll(ctx context.Context) ([]JWK, error) ``` ```go package main import ( "context" "log" "github.com/MicahParks/jwkset" ) func main() { ctx := context.Background() store := jwkset.NewMemoryStorage() // ... store.KeyWrite(ctx, jwk1) ... // ... store.KeyWrite(ctx, jwk2) ... allKeys, err := store.KeyReadAll(ctx) if err != nil { log.Fatal(err) } println("Total keys:", len(allKeys)) for _, jwk := range allKeys { println("Key ID:", jwk.Marshal().KID) } } ``` -------------------------------- ### LoadCertificate Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/x509-utilities.md Loads a single X.509 certificate from raw certificate bytes. ```Go package main import ( "log" "github.com/MicahParks/jwkset" ) func main() { // Read raw certificate bytes from PEM file var certBytes []byte // ... load certBytes from file ... cert, err := jwkset.LoadCertificate(certBytes) if err != nil { log.Fatal(err) } println("Loaded certificate for:", cert.Subject.CommonName) } ``` -------------------------------- ### LoadCertificates Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/x509-utilities.md Loads multiple X.509 certificates from PEM-encoded data. ```Go package main import ( "io/ioutil" "log" "github.com/MicahParks/jwkset" ) func main() { // Read PEM file pemData, err := ioutil.ReadFile("certs.pem") if err != nil { log.Fatal(err) } // Load all certificates certs, err := jwkset.LoadCertificates(pemData) if err != nil { log.Fatal(err) } println("Loaded", len(certs), "certificates") for i, cert := range certs { println(i, ":", cert.Subject.CommonName) } } ``` -------------------------------- ### Checking for Specific Errors Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/errors.md Example of using a switch statement with errors.Is to check for different error types. ```go package main import ( "context" "errors" "log" "github.com/MicahParks/jwkset" ) func main() { store := jwkset.NewMemoryStorage() ctx := context.Background() jwk, err := store.KeyRead(ctx, "key-id") if err != nil { switch { case errors.Is(err, jwkset.ErrKeyNotFound): log.Println("Key not found") case errors.Is(err, jwkset.ErrJWKValidation): log.Println("Key validation failed") default: log.Println("Other error:", err) } } _ = jwk } ``` -------------------------------- ### Loading Multiple Keys from File Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/x509-utilities.md Reads a PEM file containing multiple PEM blocks, decodes each block, and infers and loads the key. It then processes the key based on its type, supporting Ed25519 and ECDSA private and public keys. ```go package main import ( "crypto/ed25519" "crypto/ecdsa" "encoding/pem" "io/ioutil" "log" "github.com/MicahParks/jwkset" ) func main() { // Read file containing multiple PEM blocks pemData, err := ioutil.ReadFile("keys.pem") if err != nil { log.Fatal(err) } // Parse all PEM blocks for { block, rest := pem.Decode(pemData) if block == nil { break } pemData = rest // Infer and load key key, err := jwkset.LoadX509KeyInfer(block) if err != nil { log.Printf("Error loading %s block: %v", block.Type, err) continue } // Process key based on type switch k := key.(type) { case ed25519.PrivateKey: println("Loaded Ed25519 private key") case *ecdsa.PrivateKey: println("Loaded ECDSA private key for curve:", k.Curve.Params().Name) case ed25519.PublicKey: println("Loaded Ed25519 public key") case *ecdsa.PublicKey: println("Loaded ECDSA public key for curve:", k.Curve.Params().Name) } } } ``` -------------------------------- ### Strict validation Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/README.md Example of JWK options with strict validation enabled, including X.509 checking and HTTPS enforcement. ```go jwkset.JWKOptions{ Validate: jwkset.JWKValidateOptions{ CheckX509ValidTime: true, SkipX5UScheme: false, StrictPadding: true, }, } ``` -------------------------------- ### DefaultGetX5U Function Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/jwk.md Default implementation for fetching X.509 certificates from an X5U URI. ```go func DefaultGetX5U(u *url.URL) ([]*x509.Certificate, error) ``` ```go package main import ( "log" "net/url" "github.com/MicahParks/jwkset" ) func main() { u, err := url.ParseRequestURI("https://example.com/certs.pem") if err != nil { log.Fatal(err) } certs, err := jwkset.DefaultGetX5U(u) if err != nil { log.Fatal(err) } println("Fetched", len(certs), "certificates") } ``` -------------------------------- ### LoadX509KeyInfer Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/x509-utilities.md Loads an X.509 key from a PEM block by inferring the key type from the PEM block type. ```Go package main import ( "crypto/ed25519" "encoding/pem" "io/ioutil" "log" "github.com/MicahParks/jwkset" ) func main() { // Read PEM file pemData, err := ioutil.ReadFile("private.pem") if err != nil { log.Fatal(err) } // Decode first PEM block block, _ := pem.Decode(pemData) if block == nil { log.Fatal("No PEM block found") } // Infer and load key key, err := jwkset.LoadX509KeyInfer(block) if err != nil { log.Fatal(err) } // Type assert based on PEM block type if privKey, ok := key.(ed25519.PrivateKey); ok { println("Loaded Ed25519 private key") pub := privKey.Public() println("Public key length:", len(pub.(ed25519.PublicKey))) } } ``` -------------------------------- ### HTTPClientOptions Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/http-client.md Configuration options for NewHTTPClient. ```go type HTTPClientOptions struct { Given Storage // Keys from local storage HTTPURLs map[string]Storage // URL -> Storage mapping PrioritizeHTTP bool // Prioritize HTTP keys over local RateLimitWaitMax time.Duration // Max wait for rate limit RefreshUnknownKID *rate.Limiter // Rate limit for unknown key refreshes } ``` ```go package main import ( "log" time "time" "github.com/MicahParks/jwkset" "golang.org/x/time/rate" ) func main() { options := jwkset.HTTPClientOptions{ Given: jwkset.NewMemoryStorage(), HTTPURLs: map[string]jwkset.Storage{ "https://example.com/.well-known/jwks.json": nil, }, PrioritizeHTTP: true, RateLimitWaitMax: 2 * time.Minute, RefreshUnknownKID: rate.NewLimiter(rate.Every(10*time.Minute), 1), } client, err := jwkset.NewHTTPClient(options) if err != nil { log.Fatal(err) } // Use client } ``` -------------------------------- ### NewJWKFromX5U Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/jwk.md Creates a JWK by fetching X.509 certificate chain from a URI. ```Go func NewJWKFromX5U(options JWKOptions) (JWK, error) ``` ```Go package main import ( "log" "github.com/MicahParks/jwkset" ) func main() { options := jwkset.JWKOptions{ X509: jwkset.JWKX509Options{ X5U: "https://example.com/certs.pem", }, Metadata: jwkset.JWKMetadataOptions{ KID: "remote-cert-key", }, } jwk, err := jwkset.NewJWKFromX5U(options) if err != nil { log.Fatal(err) } println("Created JWK from X5U") } ``` -------------------------------- ### HTTPClientStorageOptions Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/configuration.md Configuration for HTTP JWK Set fetching via NewStorageFromHTTP. ```go type HTTPClientStorageOptions struct { Client *http.Client Ctx context.Context HTTPExpectedStatus int HTTPMethod string HTTPTimeout time.Duration NoErrorReturnFirstHTTPReq bool RefreshErrorHandler func(ctx context.Context, err error) RefreshInterval time.Duration RequireSupportedKeys bool Storage Storage ValidateOptions JWKValidateOptions } ``` -------------------------------- ### Create a JWK Set client from the server's HTTP URL Source: https://github.com/micahparks/jwkset/blob/main/README.md Creates a JWK Set client using the default HTTP client, providing a slice of server URLs. ```go jwks, err := jwkset.NewDefaultHTTPClient([]string{server.URL}) if err != nil { log.Fatalf("Failed to create client JWK set. Error: %s", err) } ``` -------------------------------- ### NewJWKFromX5C Source: https://github.com/micahparks/jwkset/blob/main/_autodocs/api-reference/jwk.md Creates a JWK from X.509 certificate chain data. ```Go func NewJWKFromX5C(options JWKOptions) (JWK, error) ``` ```Go package main import ( "crypto/x509" "log" "github.com/MicahParks/jwkset" ) func main() { // Assume cert is an *x509.Certificate loaded from PEM var cert *x509.Certificate // ... load cert from PEM file ... options := jwkset.JWKOptions{ X509: jwkset.JWKX509Options{ X5C: []*x509.Certificate{cert}, }, Metadata: jwkset.JWKMetadataOptions{ KID: "cert-key-1", }, } jwk, err := jwkset.NewJWKFromX5C(options) if err != nil { log.Fatal(err) } println("Created JWK from certificate") } ```