Documentation
¶
Overview ¶
Package jwks provides remote JSON Web Key Set (JWKS) fetching and caching.
The main entry point is NewRemoteKeySet, which returns a *RemoteKeySet that fetches keys from a JWKS endpoint. Keys are cached in memory and refreshed using stale-while-refresh semantics: cached keys are returned immediately when fresh, and stale entries trigger a background refresh so callers never block on a cache miss after the initial fetch.
Key lookup ¶
Use RemoteKeySet.Keys to retrieve all current keys, or RemoteKeySet.Key to look up a specific key by its "kid" header. When a key ID is not found in the cached set, the RemoteKeySet performs an immediate refresh before reporting a KeyNotFoundError.
Caching ¶
A default in-memory CacheStore is installed automatically. Replace it with WithCache if you need a custom implementation. The cache stores one entry per JWKS URL, keyed by URL.
When to use this package directly ¶
Most callers should use the [metadata] or [rp] packages, which construct a RemoteKeySet as part of provider discovery. Use this package directly when you have a JWKS URL and need key retrieval without OIDC discovery.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrKeyNotFound indicates the requested key was not found. ErrKeyNotFound = errors.New("jwks key not found") // ErrFetchFailed indicates JWKS fetch failure. ErrFetchFailed = errors.New("jwks fetch failed") )
Functions ¶
This section is empty.
Types ¶
type CacheEntry ¶
type CacheEntry struct {
// contains filtered or unexported fields
}
CacheEntry is an opaque cached JWKS entry. Its fields are intentionally unexported.
type CacheStore ¶
type CacheStore interface {
Get(key string) (value *CacheEntry, ok bool)
Set(key string, value *CacheEntry)
Delete(key string)
}
CacheStore is the minimal cache interface used by the jwks package. Implementations must be safe for concurrent use.
type FetchError ¶
FetchError indicates a fetch operation failed.
func (*FetchError) Is ¶
func (e *FetchError) Is(target error) bool
Is supports errors.Is matching against ErrFetchFailed.
type KeyNotFoundError ¶
KeyNotFoundError indicates a specific key ID could not be found.
func (*KeyNotFoundError) Is ¶
func (e *KeyNotFoundError) Is(target error) bool
Is supports errors.Is matching against ErrKeyNotFound.
type Option ¶
type Option func(*RemoteKeySet)
Option configures a RemoteKeySet.
func WithCache ¶
func WithCache(store CacheStore) Option
WithCache configures the cache implementation.
func WithDefaultTTL ¶
WithDefaultTTL configures the fallback TTL when cache headers are absent.
func WithExpiryDelta ¶
WithExpiryDelta configures a small delta used to proactively refresh near-expiry keys.
func WithHTTPClient ¶
WithHTTPClient configures the HTTP client.
func WithMinRefreshInterval ¶
WithMinRefreshInterval configures minimum time between unknown-kid refreshes.
type RemoteKeySet ¶
type RemoteKeySet struct {
// contains filtered or unexported fields
}
RemoteKeySet fetches and caches a remote JWKS endpoint.
func NewRemoteKeySet ¶
func NewRemoteKeySet(jwksURL string, opts ...Option) (*RemoteKeySet, error)
NewRemoteKeySet creates a new remote key set client. Keys are fetched from the given JWKS URL and cached in an in-memory store. Cached keys are returned immediately when fresh; stale entries trigger a background refresh so callers never block after the initial fetch. Use WithCache to supply a custom CacheStore.
Example ¶
package main
import (
"context"
"crypto/tls"
"fmt"
"net/http"
"net/http/httptest"
"github.com/Kunde21/lanyard/jwks"
)
func main() {
server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
fmt.Fprint(w, `{"keys":[{
"kty":"RSA",
"kid":"key-1",
"use":"sig",
"alg":"RS256",
"n":"2ieuB-8BJ19bpi_0iqt8mi-31jPpO4NHNFeH-AeG7dIwBlhVVUGbJ2yhvHALutgeMfzn5OtbX75Szul7lmAxrGSAkYqg1SuRzJOJJ0-5rxWrismoIDBjSL4jCTL0HYFWePQzoB_RFPaLqiuye5FQV02iG2b8f-EgpCxTkN8rudtoCurIFDLxc4eu7TkLrS5prfcAj74Yub2qXlJtE0Q5syjxbiNI5gg_Tqok_Klfi7glU8cj1ahsvDqPXiMqKnQ3zZr_UTnkT3Vb_q3nyBukSZUF-gduBnAg17sCayPw1EBBFhq04VJRYDDL30b6oq8eaFfnhMD0xo6HG7gZY71caQ",
"e":"AQAB"
}]}`)
}))
defer server.Close()
ks, err := jwks.NewRemoteKeySet(
server.URL+"/jwks",
jwks.WithHTTPClient(&http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}),
)
if err != nil {
fmt.Println(err)
return
}
keys, err := ks.Keys(context.Background())
if err != nil {
fmt.Println(err)
return
}
fmt.Println(len(keys) > 0)
}
Output: true
func (*RemoteKeySet) Key ¶
func (r *RemoteKeySet) Key(ctx context.Context, kid string) (jose.JSONWebKey, error)
Key returns a specific key by kid.
func (*RemoteKeySet) Keys ¶
func (r *RemoteKeySet) Keys(ctx context.Context) ([]jose.JSONWebKey, error)
Keys returns keys from cache, refreshing stale or missing values as needed.