s12v / go-jwks

A Go library to retrieve RSA public keys from a JWKS (JSON Web Key Set) endpoint
MIT License
42 stars 16 forks source link
jwk jwks jwt rsa

Build Status codecov

go-jwks

A Go library to retrieve RSA public keys from a JWKS (JSON Web Key Set) endpoint.

Installation

Using Go modules

go get github.com/s12v/go-jwks@v0.2.1

Dependencies

Example

GetEncryptionKey returns *jose.JSONWebKey for a given key id:

package main

import (
    "log"
    "time"

    "github.com/s12v/go-jwks"
    "github.com/square/go-jose"
)

func main() {
    jwksSource := jwks.NewWebSource("https://www.googleapis.com/oauth2/v3/certs")
    jwksClient := jwks.NewDefaultClient(
        jwksSource,
        time.Hour,    // Refresh keys every 1 hour
        12*time.Hour, // Expire keys after 12 hours
    )

    var jwk *jose.JSONWebKey
    jwk, err := jwksClient.GetEncryptionKey("c6af7caa0895fd01e778dceaa7a7988347d8f25c")
    if err != nil {
        log.Fatal(err)
    }

    log.Printf("key: %v, alg: %v, use: %v", jwk.KeyID, jwk.Algorithm, jwk.Use)
}

Log:

2018/07/30 01:22:35 Fetchng JWKS from https://www.googleapis.com/oauth2/v3/certs
2018/07/30 01:22:36 key: c6af7caa0895fd01e778dceaa7a7988347d8f25c, alg: RS256, use: sig

Caching

Key refresh and TTL

There are two caching parameters:

On the first request, the key is synchronously fetched from the key server and stored in the cache. On the next request after refresh interval, the key will be refreshed in the background (not affect response time). Only 1 key refresh is executed at the same time.

If the key is not requested during ttl interval, it will be removed from cache.

Cache implementations

Default cache is github.com/patrickmn/go-cache in-memory cache. You can provide your own cache implementation, see cache.go:

type Cache interface {
    // Get an item from the cache and itsexpiration time.
    // Returns the item or nil, and a bool indicating whether the key was found
    GetWithExpiration(k string) (interface{}, time.Time, bool)
    // Add an item to the cache, replacing any existing item.
    Set(k string, x interface{})
}

and pass it to func NewClient(...)

Source

Default source is WebSource. You can provide your own implementation, see source.go:

type JWKSSource interface {
    JSONWebKeySet() (*jose.JSONWebKeySet, error)
}