Documentation
¶
Index ¶
- func ExtractClaim(token string, claimName string) (any, error)
- func ExtractKIDFromCompactJWT(compactToken string) (string, error)
- func GetSigningMethodFromKey(privateKey any) (jwt.SigningMethod, string)
- func MakeJWT(ctx context.Context, header, body jwt.MapClaims, signer pki.Signer) (string, error)
- func ParseJWKToPublicKey(jwkData any) (crypto.PublicKey, error)
- func ParseJWTWithJWKHeader(token string) (jwt.MapClaims, map[string]any, map[string]any, string, error)
- func ParseSigningKey(signingKeyPath string) (crypto.PrivateKey, error)
- func ParseX5CHeader(x5cRaw any, ext ...*cryptoutil.Extensions) ([]*x509.Certificate, error)
- type JWKS
- type JWKWithMetadata
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func ExtractClaim ¶
ExtractClaim extracts a specific claim from a JWT without validation
Example ¶
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/SUNET/vc/pkg/jose"
)
// makeTestJWT constructs a compact JWT from header and payload maps with a fake signature.
func makeTestJWT(header, payload map[string]any) string {
h, _ := json.Marshal(header)
p, _ := json.Marshal(payload)
return base64.RawURLEncoding.EncodeToString(h) + "." +
base64.RawURLEncoding.EncodeToString(p) + "." +
base64.RawURLEncoding.EncodeToString([]byte("fakesig"))
}
func main() {
token := makeTestJWT(
map[string]any{"alg": "ES256", "typ": "JWT"},
map[string]any{"sub": "user-123", "iss": "https://issuer.example.com"},
)
sub, err := jose.ExtractClaim(token, "sub")
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("sub:", sub)
iss, err := jose.ExtractClaim(token, "iss")
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("iss:", iss)
}
Output: sub: user-123 iss: https://issuer.example.com
Example (MissingClaim) ¶
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/SUNET/vc/pkg/jose"
)
// makeTestJWT constructs a compact JWT from header and payload maps with a fake signature.
func makeTestJWT(header, payload map[string]any) string {
h, _ := json.Marshal(header)
p, _ := json.Marshal(payload)
return base64.RawURLEncoding.EncodeToString(h) + "." +
base64.RawURLEncoding.EncodeToString(p) + "." +
base64.RawURLEncoding.EncodeToString([]byte("fakesig"))
}
func main() {
token := makeTestJWT(
map[string]any{"alg": "ES256"},
map[string]any{"sub": "user-123"},
)
_, err := jose.ExtractClaim(token, "nonexistent")
fmt.Println("error:", err)
}
Output: error: claim "nonexistent" not found
func ExtractKIDFromCompactJWT ¶
ExtractKIDFromCompactJWT extracts the "kid" field from the header of a compact-serialized JWT/JWE.
Example ¶
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/SUNET/vc/pkg/jose"
)
// makeTestJWT constructs a compact JWT from header and payload maps with a fake signature.
func makeTestJWT(header, payload map[string]any) string {
h, _ := json.Marshal(header)
p, _ := json.Marshal(payload)
return base64.RawURLEncoding.EncodeToString(h) + "." +
base64.RawURLEncoding.EncodeToString(p) + "." +
base64.RawURLEncoding.EncodeToString([]byte("fakesig"))
}
func main() {
token := makeTestJWT(
map[string]any{"alg": "ES256", "kid": "key-abc-123"},
map[string]any{"sub": "user"},
)
kid, err := jose.ExtractKIDFromCompactJWT(token)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("kid:", kid)
}
Output: kid: key-abc-123
Example (Missing) ¶
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/SUNET/vc/pkg/jose"
)
// makeTestJWT constructs a compact JWT from header and payload maps with a fake signature.
func makeTestJWT(header, payload map[string]any) string {
h, _ := json.Marshal(header)
p, _ := json.Marshal(payload)
return base64.RawURLEncoding.EncodeToString(h) + "." +
base64.RawURLEncoding.EncodeToString(p) + "." +
base64.RawURLEncoding.EncodeToString([]byte("fakesig"))
}
func main() {
token := makeTestJWT(
map[string]any{"alg": "ES256"},
map[string]any{"sub": "user"},
)
_, err := jose.ExtractKIDFromCompactJWT(token)
fmt.Println("error:", err)
}
Output: error: kid not found in JWT header
func GetSigningMethodFromKey ¶
func GetSigningMethodFromKey(privateKey any) (jwt.SigningMethod, string)
GetSigningMethodFromKey determines the JWT signing method and algorithm name from the private key
func MakeJWT ¶
MakeJWT creates a signed JWT using pki.Signer. The pki.Signer interface supports both software keys and HSM.
func ParseJWKToPublicKey ¶
ParseJWKToPublicKey parses a JWK (as a map or JSON bytes) to extract the public key.
func ParseJWTWithJWKHeader ¶
func ParseJWTWithJWKHeader(token string) (jwt.MapClaims, map[string]any, map[string]any, string, error)
ParseJWTWithJWKHeader parses and validates a JWT where the public key is embedded in the JWT header as a JWK Returns the parsed claims, the token header, the JWK header, the key thumbprint, and any error
func ParseSigningKey ¶
func ParseSigningKey(signingKeyPath string) (crypto.PrivateKey, error)
ParseSigningKey parses a private key from a PEM file (supports EC and RSA in various formats) Handles SEC1, PKCS1, and PKCS8 formats automatically.
func ParseX5CHeader ¶
func ParseX5CHeader(x5cRaw any, ext ...*cryptoutil.Extensions) ([]*x509.Certificate, error)
ParseX5CHeader parses the x5c header into a certificate chain. The x5c header is an array of base64-encoded DER certificates, with the leaf certificate first. Supports both standard and URL-safe base64 encoding. If ext is provided, certificates are parsed using extension-aware parsing (e.g. to support brainpool curves).
Types ¶
type JWKS ¶
type JWKS struct {
Keys []JWKWithMetadata `json:"keys"`
}
JWKS represents a JSON Web Key Set
Example ¶
package main
import (
"fmt"
"github.com/SUNET/vc/pkg/jose"
)
func main() {
jwks := &jose.JWKS{
Keys: []jose.JWKWithMetadata{
{
Kty: "EC",
Crv: "P-256",
Kid: "key-1",
Alg: "ES256",
Use: "sig",
X: "f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
Y: "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
},
},
}
fmt.Println("keys:", len(jwks.Keys))
fmt.Println("kty:", jwks.Keys[0].Kty)
fmt.Println("kid:", jwks.Keys[0].Kid)
fmt.Println("alg:", jwks.Keys[0].Alg)
fmt.Println("use:", jwks.Keys[0].Use)
}
Output: keys: 1 kty: EC kid: key-1 alg: ES256 use: sig
type JWKWithMetadata ¶
type JWKWithMetadata struct {
Kty string `json:"kty"`
Use string `json:"use,omitempty"`
Kid string `json:"kid,omitempty"`
Alg string `json:"alg,omitempty"`
// EC key fields
Crv string `json:"crv,omitempty"`
X string `json:"x,omitempty"`
Y string `json:"y,omitempty"`
// RSA key fields
N string `json:"n,omitempty"`
E string `json:"e,omitempty"`
}
JWKWithMetadata includes additional fields like alg, use, kid
func ParseJWK ¶
func ParseJWK(jwkMap map[string]any) (*JWKWithMetadata, error)
ParseJWK converts a JWK map (e.g., from a JWT header) to a JWKWithMetadata struct This is commonly used for DPoP and similar protocols where JWK is embedded in JWT headers
Example ¶
package main
import (
"fmt"
"github.com/SUNET/vc/pkg/jose"
)
func main() {
jwkMap := map[string]any{
"kty": "EC",
"crv": "P-256",
"x": "f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
"y": "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0",
"kid": "my-key-id",
"alg": "ES256",
}
jwk, err := jose.ParseJWK(jwkMap)
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("kty:", jwk.Kty)
fmt.Println("kid:", jwk.Kid)
fmt.Println("crv:", jwk.Crv)
}
Output: kty: EC kid: my-key-id crv: P-256