jwks

package module
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Sep 13, 2022 License: Apache-2.0 Imports: 10 Imported by: 0

README

Go Report Card Go Reference

public-jwk-set

This is a minimal public JWK Set server-side implementation. For a JWK Set client, see github.com/MicahParks/keyfunc. Cryptographic keys can be added, deleted, and read from the JWK Set. A JSON representation of the JWK Set can be created for hosting via HTTPS. This project includes an in-memory storage implementation, but an interface is provided for more advanced use cases. For the JSON representation, only public key material will be included. For example, any HMAC keys stored within the JWK Set will not be included in the JSON representation.

This project only depends on packages from the standard Go library. It has no external dependencies.

The following key types have a JSON representation:

Key type Go type External link
EC *ecdsa.PrivateKey Elliptic Curve Digital Signature Algorithm (ECDSA)
OKP ed25519.PrivateKey Edwards-curve Digital Signature Algorithm (EdDSA)
RSA *rsa.PrivateKey Rivest–Shamir–Adleman (RSA)

Other key types, such as HMAC (OCT, []byte) can also be placed inside the JWK Set, but they will not be included in the JSON representation.

Example HTTP server

package main

import (
	"context"
	"crypto/rand"
	"crypto/rsa"
	"log"
	"net/http"
	"os"

	jwks "github.com/MicahParks/public-jwk-set"
)

const (
	logFmt = "%s\nError: %s"
)

func main() {
	ctx := context.Background()
	logger := log.New(os.Stdout, "", 0)

	jwkSet := jwks.NewMemory()

	key, err := rsa.GenerateKey(rand.Reader, 4096)
	if err != nil {
		logger.Fatalf(logFmt, "Failed to generate RSA key.", err)
	}

	err = jwkSet.Store.WriteKey(ctx, jwks.NewKey(key, "my-key-id"))
	if err != nil {
		logger.Fatalf(logFmt, "Failed to store RSA key.", err)
	}

	http.HandleFunc("/jwks.json", func(writer http.ResponseWriter, request *http.Request) {
		// TODO Cache the JWK Set so storage isn't called for every request.
		response, err := jwkSet.JSON(request.Context())
		if err != nil {
			logger.Printf(logFmt, "Failed to get JWK Set JSON.", err)
			writer.WriteHeader(http.StatusInternalServerError)
			return
		}

		writer.Header().Set("Content-Type", "application/json")
		_, _ = writer.Write(response)
	})

	logger.Print("Visit: http://localhost:8080/jwks.json")
	logger.Fatalf("Failed to listen and serve: %s", http.ListenAndServe(":8080", nil))
}

Test coverage

Test coverage is currently greater than 95%.

$ go test -cover -race
PASS
coverage: 98.5% of statements
ok      github.com/MicahParks/public-jwk-set    0.021s

References

This project was built and tested using various RFCs and services. The services are listed below:

See also:

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrKeyNotFound = errors.New("key not found")

ErrKeyNotFound is returned by a Storage implementation when a key is not found.

Functions

This section is empty.

Types

type JWKSet

type JWKSet struct {
	Store Storage
}

JWKSet is a set of JSON Web Keys.

func NewMemory

func NewMemory() JWKSet

NewMemory creates a new in-memory JWKSet.

func (JWKSet) JSON

func (j JWKSet) JSON(ctx context.Context) (json.RawMessage, error)

JSON creates the JSON representation of the JWKSet.

type KeyType

type KeyType string

KeyType is a set of "JSON Web Key Types" from https://www.iana.org/assignments/jose/jose.xhtml as mentioned in https://www.rfc-editor.org/rfc/rfc7517#section-4.1

const (
	// KeyTypeEC is the key type for ECDSA.
	KeyTypeEC KeyType = "EC"
	// KeyTypeOKP is the key type for EdDSA.
	KeyTypeOKP KeyType = "OKP"
	// KeyTypeRSA is the key type for RSA.
	KeyTypeRSA KeyType = "RSA"
	// KeyTypeOct is the key type for octet sequences, such as HMAC.
	KeyTypeOct KeyType = "oct"
)

func (KeyType) String added in v0.0.3

func (kty KeyType) String() string

type KeyWithMeta

type KeyWithMeta struct {
	Key   interface{}
	KeyID string
}

KeyWithMeta is holds a Key and its metadata.

func NewKey added in v0.0.3

func NewKey(key interface{}, keyID string) KeyWithMeta

NewKey creates a new KeyWithMeta.

type Storage

type Storage interface {
	// DeleteKey deletes a key from the storage. It will return ok as true if the key was present for deletion.
	DeleteKey(ctx context.Context, keyID string) (ok bool, err error)

	// ReadKey reads a key from the storage. If the key is not present, it returns ErrKeyNotFound. Any pointers returned
	// should be considered read-only.
	ReadKey(ctx context.Context, keyID string) (KeyWithMeta, error)

	// SnapshotKeys reads a snapshot of all keys from storage. As with ReadKey, any pointers returned should be
	// considered read-only.
	SnapshotKeys(ctx context.Context) ([]KeyWithMeta, error)

	// WriteKey writes a key to the storage. If the key already exists, it will be overwritten. After writing a key,
	// any pointers written should be considered owned by the underlying storage.
	WriteKey(ctx context.Context, meta KeyWithMeta) error
}

Storage handles storage operations for a JWKSet.

func NewMemoryStorage

func NewMemoryStorage() Storage

NewMemoryStorage creates a new in-memory Storage implementation.

Jump to

Keyboard shortcuts

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