11package auth
22
33import (
4- "context"
54 "fmt"
65 "net/http"
7- "os"
86 "strings"
97
108 "github.com/formancehq/stack/libs/go-libs/collectionutils"
119 "github.com/formancehq/stack/libs/go-libs/logging"
1210 "github.com/hashicorp/go-retryablehttp"
13- "github.com/zitadel/oidc/v2/pkg/client/rp"
1411 "github.com/zitadel/oidc/v2/pkg/oidc"
1512 "github.com/zitadel/oidc/v2/pkg/op"
1613 "go.uber.org/zap"
1714)
1815
1916type jwtAuth struct {
20- logger logging.Logger
21- httpClient * http.Client
22- accessTokenVerifier op.AccessTokenVerifier
23-
24- issuer string
17+ logger logging.Logger
18+ httpClient * http.Client
19+ verifiers map [string ]op.AccessTokenVerifier // issuer -> verifier
2520 checkScopes bool
2621 service string
2722}
@@ -35,17 +30,16 @@ func newOtlpHttpClient(maxRetries int) *http.Client {
3530func newJWTAuth (
3631 logger logging.Logger ,
3732 readKeySetMaxRetries int ,
38- issuer string ,
33+ verifiers map [ string ]op. AccessTokenVerifier ,
3934 service string ,
4035 checkScopes bool ,
4136) * jwtAuth {
4237 return & jwtAuth {
43- logger : logger ,
44- httpClient : newOtlpHttpClient (readKeySetMaxRetries ),
45- accessTokenVerifier : nil ,
46- issuer : issuer ,
47- checkScopes : checkScopes ,
48- service : service ,
38+ logger : logger ,
39+ httpClient : newOtlpHttpClient (readKeySetMaxRetries ),
40+ verifiers : verifiers ,
41+ checkScopes : checkScopes ,
42+ service : service ,
4943 }
5044}
5145
@@ -66,13 +60,28 @@ func (ja *jwtAuth) Authenticate(w http.ResponseWriter, r *http.Request) (bool, e
6660 token := strings .TrimPrefix (authHeader , strings .ToLower (oidc .PrefixBearer ))
6761 token = strings .TrimPrefix (token , oidc .PrefixBearer )
6862
69- accessTokenVerifier , err := ja .getAccessTokenVerifier (r .Context ())
70- if err != nil {
71- ja .logger .Error ("unable to create access token verifier" , zap .Error (err ))
72- return false , fmt .Errorf ("unable to create access token verifier: %w" , err )
63+ // Pre-parse the token to extract the issuer claim, so we can select
64+ // the correct verifier (each issuer has its own key set).
65+ var preClaims oidc.TokenClaims
66+ if _ , err := oidc .ParseToken (token , & preClaims ); err != nil {
67+ ja .logger .Error ("unable to parse token" , zap .Error (err ))
68+ return false , fmt .Errorf ("unable to parse token: %w" , err )
7369 }
7470
75- claims , err := op .VerifyAccessToken [* oidc.AccessTokenClaims ](r .Context (), token , accessTokenVerifier )
71+ verifier , ok := ja .verifiers [preClaims .Issuer ]
72+ if ! ok {
73+ issuers := make ([]string , 0 , len (ja .verifiers ))
74+ for iss := range ja .verifiers {
75+ issuers = append (issuers , iss )
76+ }
77+ ja .logger .Error ("untrusted issuer" ,
78+ zap .String ("got" , preClaims .Issuer ),
79+ zap .Strings ("trusted" , issuers ),
80+ )
81+ return false , fmt .Errorf ("issuer does not match: got: %s, trusted: %v" , preClaims .Issuer , issuers )
82+ }
83+
84+ claims , err := op .VerifyAccessToken [* oidc.AccessTokenClaims ](r .Context (), token , verifier )
7685 if err != nil {
7786 ja .logger .Error ("unable to verify access token" , zap .Error (err ))
7887 return false , fmt .Errorf ("unable to verify access token: %w" , err )
@@ -97,26 +106,3 @@ func (ja *jwtAuth) Authenticate(w http.ResponseWriter, r *http.Request) (bool, e
97106
98107 return true , nil
99108}
100-
101- func (ja * jwtAuth ) getAccessTokenVerifier (ctx context.Context ) (op.AccessTokenVerifier , error ) {
102- if ja .accessTokenVerifier == nil {
103- //discoveryConfiguration, err := client.Discover(ja.Issuer, ja.httpClient)
104- //if err != nil {
105- // return nil, err
106- //}
107-
108- // todo: ugly quick fix
109- authServicePort := "8080"
110- if fromEnv := os .Getenv ("AUTH_SERVICE_PORT" ); fromEnv != "" {
111- authServicePort = fromEnv
112- }
113- keySet := rp .NewRemoteKeySet (ja .httpClient , fmt .Sprintf ("http://auth:%s/keys" , authServicePort ))
114-
115- ja .accessTokenVerifier = op .NewAccessTokenVerifier (
116- os .Getenv ("STACK_PUBLIC_URL" )+ "/api/auth" ,
117- keySet ,
118- )
119- }
120-
121- return ja .accessTokenVerifier , nil
122- }
0 commit comments