Skip to content

Commit 57e8507

Browse files
authored
feat: tolerate initial JWK error (#1475)
1 parent 4a72ded commit 57e8507

File tree

6 files changed

+37
-20
lines changed

6 files changed

+37
-20
lines changed

.github/actions/build-push-image/action.yaml

-3
Original file line numberDiff line numberDiff line change
@@ -79,9 +79,6 @@ runs:
7979

8080
- name: Build & Push Docker Image
8181
uses: docker/build-push-action@v6
82-
env:
83-
DOCKER_BUILD_SUMMARY: false
84-
DOCKER_BUILD_RECORD_UPLOAD: false
8582
with:
8683
# This is a limitation of GitHub. Only organization members can push to GitHub Container Registry
8784
# For now, we will disable the push to the GitHub Container Registry for external contributors

router-tests/authentication_test.go

+6-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package integration_test
22

33
import (
44
"bytes"
5+
"go.uber.org/zap"
56
"io"
67
"net/http"
78
"strings"
@@ -29,7 +30,7 @@ func configureAuth(t *testing.T) ([]authentication.Authenticator, *jwks.Server)
2930
authServer, err := jwks.NewServer(t)
3031
require.NoError(t, err)
3132
t.Cleanup(authServer.Close)
32-
tokenDecoder, _ := authentication.NewJwksTokenDecoder(authServer.JWKSURL(), time.Second*5)
33+
tokenDecoder, _ := authentication.NewJwksTokenDecoder(zap.NewNop(), authServer.JWKSURL(), time.Second*5)
3334
authOptions := authentication.HttpHeaderAuthenticatorOptions{
3435
Name: jwksName,
3536
URL: authServer.JWKSURL(),
@@ -613,7 +614,7 @@ func TestAuthenticationWithCustomHeaders(t *testing.T) {
613614
authServer, err := jwks.NewServer(t)
614615
require.NoError(t, err)
615616
t.Cleanup(authServer.Close)
616-
tokenDecoder, _ := authentication.NewJwksTokenDecoder(authServer.JWKSURL(), time.Second*5)
617+
tokenDecoder, _ := authentication.NewJwksTokenDecoder(zap.NewNop(), authServer.JWKSURL(), time.Second*5)
617618
authOptions := authentication.HttpHeaderAuthenticatorOptions{
618619
Name: jwksName,
619620
URL: authServer.JWKSURL(),
@@ -748,7 +749,7 @@ func TestAuthenticationMultipleProviders(t *testing.T) {
748749
require.NoError(t, err)
749750
t.Cleanup(authServer2.Close)
750751

751-
tokenDecoder1, _ := authentication.NewJwksTokenDecoder(authServer1.JWKSURL(), time.Second*5)
752+
tokenDecoder1, _ := authentication.NewJwksTokenDecoder(zap.NewNop(), authServer1.JWKSURL(), time.Second*5)
752753
authenticator1HeaderValuePrefixes := []string{"Bearer"}
753754
authenticator1, err := authentication.NewHttpHeaderAuthenticator(authentication.HttpHeaderAuthenticatorOptions{
754755
Name: "1",
@@ -758,7 +759,7 @@ func TestAuthenticationMultipleProviders(t *testing.T) {
758759
})
759760
require.NoError(t, err)
760761

761-
tokenDecoder2, _ := authentication.NewJwksTokenDecoder(authServer2.JWKSURL(), time.Second*5)
762+
tokenDecoder2, _ := authentication.NewJwksTokenDecoder(zap.NewNop(), authServer2.JWKSURL(), time.Second*5)
762763
authenticator2HeaderValuePrefixes := []string{"", "Bearer", "Token"}
763764
authenticator2, err := authentication.NewHttpHeaderAuthenticator(authentication.HttpHeaderAuthenticatorOptions{
764765
Name: "2",
@@ -858,7 +859,7 @@ func TestAuthenticationOverWebsocket(t *testing.T) {
858859
require.NoError(t, err)
859860
defer authServer.Close()
860861

861-
tokenDecoder, _ := authentication.NewJwksTokenDecoder(authServer.JWKSURL(), time.Second*5)
862+
tokenDecoder, _ := authentication.NewJwksTokenDecoder(zap.NewNop(), authServer.JWKSURL(), time.Second*5)
862863
jwksOpts := authentication.HttpHeaderAuthenticatorOptions{
863864
Name: jwksName,
864865
URL: authServer.JWKSURL(),

router-tests/modules/set_scopes_test.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/wundergraph/cosmo/router/core"
1010
"github.com/wundergraph/cosmo/router/pkg/authentication"
1111
"github.com/wundergraph/cosmo/router/pkg/config"
12+
"go.uber.org/zap"
1213
"io"
1314
"net/http"
1415
"strings"
@@ -26,7 +27,7 @@ func configureAuth(t *testing.T) ([]authentication.Authenticator, *jwks.Server)
2627
authServer, err := jwks.NewServer(t)
2728
require.NoError(t, err)
2829
t.Cleanup(authServer.Close)
29-
tokenDecoder, _ := authentication.NewJwksTokenDecoder(authServer.JWKSURL(), time.Second*5)
30+
tokenDecoder, _ := authentication.NewJwksTokenDecoder(zap.NewNop(), authServer.JWKSURL(), time.Second*5)
3031
authOptions := authentication.HttpHeaderAuthenticatorOptions{
3132
Name: jwksName,
3233
URL: authServer.JWKSURL(),

router-tests/websocket_test.go

+8-7
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"encoding/json"
66
"errors"
77
"fmt"
8+
"go.uber.org/zap"
89
"io"
910
"math/big"
1011
"net"
@@ -73,7 +74,7 @@ func TestWebSockets(t *testing.T) {
7374
authServer, err := jwks.NewServer(t)
7475
require.NoError(t, err)
7576
t.Cleanup(authServer.Close)
76-
tokenDecoder, _ := authentication.NewJwksTokenDecoder(authServer.JWKSURL(), time.Second*5)
77+
tokenDecoder, _ := authentication.NewJwksTokenDecoder(zap.NewNop(), authServer.JWKSURL(), time.Second*5)
7778
authOptions := authentication.HttpHeaderAuthenticatorOptions{
7879
Name: jwksName,
7980
URL: authServer.JWKSURL(),
@@ -123,7 +124,7 @@ func TestWebSockets(t *testing.T) {
123124
authServer, err := jwks.NewServer(t)
124125
require.NoError(t, err)
125126
t.Cleanup(authServer.Close)
126-
tokenDecoder, _ := authentication.NewJwksTokenDecoder(authServer.JWKSURL(), time.Second*5)
127+
tokenDecoder, _ := authentication.NewJwksTokenDecoder(zap.NewNop(), authServer.JWKSURL(), time.Second*5)
127128
authOptions := authentication.HttpHeaderAuthenticatorOptions{
128129
Name: jwksName,
129130
URL: authServer.JWKSURL(),
@@ -173,7 +174,7 @@ func TestWebSockets(t *testing.T) {
173174
authServer, err := jwks.NewServer(t)
174175
require.NoError(t, err)
175176
t.Cleanup(authServer.Close)
176-
tokenDecoder, _ := authentication.NewJwksTokenDecoder(authServer.JWKSURL(), time.Second*5)
177+
tokenDecoder, _ := authentication.NewJwksTokenDecoder(zap.NewNop(), authServer.JWKSURL(), time.Second*5)
177178
authOptions := authentication.HttpHeaderAuthenticatorOptions{
178179
Name: jwksName,
179180
URL: authServer.JWKSURL(),
@@ -232,7 +233,7 @@ func TestWebSockets(t *testing.T) {
232233
authServer, err := jwks.NewServer(t)
233234
require.NoError(t, err)
234235
t.Cleanup(authServer.Close)
235-
tokenDecoder, _ := authentication.NewJwksTokenDecoder(authServer.JWKSURL(), time.Second*5)
236+
tokenDecoder, _ := authentication.NewJwksTokenDecoder(zap.NewNop(), authServer.JWKSURL(), time.Second*5)
236237
authOptions := authentication.HttpHeaderAuthenticatorOptions{
237238
Name: jwksName,
238239
URL: authServer.JWKSURL(),
@@ -290,7 +291,7 @@ func TestWebSockets(t *testing.T) {
290291
authServer, err := jwks.NewServer(t)
291292
require.NoError(t, err)
292293
t.Cleanup(authServer.Close)
293-
tokenDecoder, _ := authentication.NewJwksTokenDecoder(authServer.JWKSURL(), time.Second*5)
294+
tokenDecoder, _ := authentication.NewJwksTokenDecoder(zap.NewNop(), authServer.JWKSURL(), time.Second*5)
294295
authOptions := authentication.WebsocketInitialPayloadAuthenticatorOptions{
295296
TokenDecoder: tokenDecoder,
296297
Key: "Authorization",
@@ -351,7 +352,7 @@ func TestWebSockets(t *testing.T) {
351352
authServer, err := jwks.NewServer(t)
352353
require.NoError(t, err)
353354
t.Cleanup(authServer.Close)
354-
tokenDecoder, _ := authentication.NewJwksTokenDecoder(authServer.JWKSURL(), time.Second*5)
355+
tokenDecoder, _ := authentication.NewJwksTokenDecoder(zap.NewNop(), authServer.JWKSURL(), time.Second*5)
355356
authOptions := authentication.WebsocketInitialPayloadAuthenticatorOptions{
356357
TokenDecoder: tokenDecoder,
357358
Key: "Authorization",
@@ -400,7 +401,7 @@ func TestWebSockets(t *testing.T) {
400401
authServer, err := jwks.NewServer(t)
401402
require.NoError(t, err)
402403
t.Cleanup(authServer.Close)
403-
tokenDecoder, _ := authentication.NewJwksTokenDecoder(authServer.JWKSURL(), time.Second*5)
404+
tokenDecoder, _ := authentication.NewJwksTokenDecoder(zap.NewNop(), authServer.JWKSURL(), time.Second*5)
404405
authOptions := authentication.WebsocketInitialPayloadAuthenticatorOptions{
405406
TokenDecoder: tokenDecoder,
406407
Key: "Authorization",

router/cmd/instance.go

+10-3
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,12 @@ func NewRouter(params Params, additionalOptions ...core.Option) (*core.Router, e
6161
if name == "" {
6262
name = fmt.Sprintf("jwks-#%d", i)
6363
}
64-
tokenDecoder, _ := authentication.NewJwksTokenDecoder(auth.JWKS.URL, auth.JWKS.RefreshInterval)
64+
providerLogger := logger.With(zap.String("provider_name", name))
65+
tokenDecoder, err := authentication.NewJwksTokenDecoder(providerLogger, auth.JWKS.URL, auth.JWKS.RefreshInterval)
66+
if err != nil {
67+
providerLogger.Error("Could not create JWKS token decoder", zap.Error(err))
68+
return nil, err
69+
}
6570
opts := authentication.HttpHeaderAuthenticatorOptions{
6671
Name: name,
6772
URL: auth.JWKS.URL,
@@ -71,7 +76,8 @@ func NewRouter(params Params, additionalOptions ...core.Option) (*core.Router, e
7176
}
7277
authenticator, err := authentication.NewHttpHeaderAuthenticator(opts)
7378
if err != nil {
74-
logger.Fatal("Could not create HttpHeader authenticator", zap.Error(err), zap.String("name", name))
79+
providerLogger.Error("Could not create HttpHeader authenticator", zap.Error(err))
80+
return nil, err
7581
}
7682
authenticators = append(authenticators, authenticator)
7783

@@ -83,7 +89,8 @@ func NewRouter(params Params, additionalOptions ...core.Option) (*core.Router, e
8389
}
8490
authenticator, err = authentication.NewWebsocketInitialPayloadAuthenticator(opts)
8591
if err != nil {
86-
logger.Fatal("Could not create WebsocketInitialPayload authenticator", zap.Error(err))
92+
providerLogger.Error("Could not create WebsocketInitialPayload authenticator", zap.Error(err))
93+
return nil, err
8794
}
8895
authenticators = append(authenticators, authenticator)
8996
}

router/pkg/authentication/jwks_token_decoder.go

+11-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package authentication
22

33
import (
44
"fmt"
5+
"go.uber.org/zap"
56
"time"
67

78
"github.com/MicahParks/keyfunc/v2"
@@ -29,10 +30,19 @@ func (j *jwksTokenDecoder) Decode(tokenString string) (Claims, error) {
2930
return Claims(claims), nil
3031
}
3132

32-
func NewJwksTokenDecoder(url string, refreshInterval time.Duration) (TokenDecoder, error) {
33+
func NewJwksTokenDecoder(logger *zap.Logger, url string, refreshInterval time.Duration) (TokenDecoder, error) {
3334

3435
jwks, err := keyfunc.Get(url, keyfunc.Options{
3536
RefreshInterval: refreshInterval,
37+
// Allow the JWKS to be empty initially, but it can recover on refresh.
38+
TolerateInitialJWKHTTPError: true,
39+
RefreshErrorHandler: func(err error) {
40+
logger.Error("Could not refresh JWKS. Trying again in the next interval.",
41+
zap.Error(err),
42+
zap.String("url", url),
43+
zap.String("interval", refreshInterval.String()),
44+
)
45+
},
3646
})
3747
if err != nil {
3848
return nil, fmt.Errorf("error initializing JWKS from %q: %w", url, err)

0 commit comments

Comments
 (0)