Skip to content

Commit f4290e1

Browse files
Merge pull request #156 from supertokens/jwks-issue
fix: JWKS leaking goroutine issue
2 parents 74ab7b5 + c3af4e3 commit f4290e1

File tree

4 files changed

+36
-17
lines changed

4 files changed

+36
-17
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [unreleased]
99

10+
### Fixes:
11+
- Fixes JWKS Keyfunc call that resulted in a goroutine leak: https://github.com/supertokens/supertokens-golang/issues/155
12+
1013
## [0.8.1] - 2022-07-12
1114

1215
### Fixes:

recipe/thirdparty/providers/apple.go

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"strings"
2424
"time"
2525

26-
"github.com/MicahParks/keyfunc"
2726
"github.com/golang-jwt/jwt/v4"
2827
"github.com/supertokens/supertokens-golang/recipe/thirdparty/api"
2928
"github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels"
@@ -177,14 +176,8 @@ func verifyAndGetClaimsAppleIdToken(idToken string, clientId string) (jwt.MapCla
177176
// Get the JWKS URL.
178177
jwksURL := "https://appleid.apple.com/auth/keys"
179178

180-
// Create the keyfunc options. Refresh the JWKS every hour and log errors.
181-
refreshInterval := time.Hour
182-
options := keyfunc.Options{
183-
RefreshInterval: refreshInterval,
184-
}
185-
186179
// Create the JWKS from the resource at the given URL.
187-
jwks, err := keyfunc.Get(jwksURL, options)
180+
jwks, err := getJWKSFromURL(jwksURL)
188181
if err != nil {
189182
return claims, err
190183
}

recipe/thirdparty/providers/googleWorkspaces.go

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@ package providers
1818
import (
1919
"errors"
2020
"strings"
21-
"time"
2221

23-
"github.com/MicahParks/keyfunc"
2422
"github.com/golang-jwt/jwt/v4"
2523
"github.com/supertokens/supertokens-golang/recipe/thirdparty/api"
2624
"github.com/supertokens/supertokens-golang/recipe/thirdparty/tpmodels"
@@ -140,14 +138,8 @@ func verifyAndGetClaims(idToken string, clientId string) (jwt.MapClaims, error)
140138
// Get the JWKS URL.
141139
jwksURL := "https://www.googleapis.com/oauth2/v3/certs"
142140

143-
// Create the keyfunc options. Refresh the JWKS every hour and log errors.
144-
refreshInterval := time.Hour
145-
options := keyfunc.Options{
146-
RefreshInterval: refreshInterval,
147-
}
148-
149141
// Create the JWKS from the resource at the given URL.
150-
jwks, err := keyfunc.Get(jwksURL, options)
142+
jwks, err := getJWKSFromURL(jwksURL)
151143
if err != nil {
152144
return claims, err
153145
}

recipe/thirdparty/providers/utils.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ import (
2121
"fmt"
2222
"io/ioutil"
2323
"net/http"
24+
"sync"
25+
"time"
26+
27+
"github.com/MicahParks/keyfunc"
2428
)
2529

2630
func doGetRequest(req *http.Request) (interface{}, error) {
@@ -47,3 +51,30 @@ func doGetRequest(req *http.Request) (interface{}, error) {
4751
}
4852
return result, nil
4953
}
54+
55+
var jwksKeys = map[string]*keyfunc.JWKS{}
56+
var jwksKeysLock = sync.Mutex{}
57+
58+
func getJWKSFromURL(url string) (*keyfunc.JWKS, error) {
59+
if jwks, ok := jwksKeys[url]; ok {
60+
return jwks, nil
61+
}
62+
63+
jwksKeysLock.Lock()
64+
defer jwksKeysLock.Unlock()
65+
66+
// Check again to see if it was added while we were waiting for the lock
67+
if jwks, ok := jwksKeys[url]; ok {
68+
return jwks, nil
69+
}
70+
71+
options := keyfunc.Options{
72+
RefreshInterval: time.Hour,
73+
}
74+
jwks, err := keyfunc.Get(url, options)
75+
if err != nil {
76+
return nil, err
77+
}
78+
jwksKeys[url] = jwks
79+
return jwks, nil
80+
}

0 commit comments

Comments
 (0)