From 250c4ad95d91a04baa02272d0c2aac31eb1ca187 Mon Sep 17 00:00:00 2001 From: David Haraga Date: Fri, 24 Oct 2025 18:02:01 +0200 Subject: [PATCH] feat: multi tenant support - support for multiple issuers --- pkg/client/client.go | 11 +++++--- pkg/client/client_test.go | 4 +-- pkg/client/profile/jwt_profile.go | 2 +- pkg/client/rp/relying_party.go | 26 +++++++++++++++---- pkg/client/rp/relying_party_test.go | 2 +- pkg/client/rp/verifier.go | 6 ++--- pkg/client/rp/verifier_test.go | 12 ++++----- pkg/client/rp/verifier_tokens_example_test.go | 2 +- pkg/client/rs/resource_server.go | 2 +- pkg/client/tokenexchange/tokenexchange.go | 4 +-- pkg/oidc/verifier.go | 9 +++---- pkg/oidc/verifier_test.go | 2 +- pkg/op/verifier_access_token.go | 6 ++--- pkg/op/verifier_access_token_test.go | 12 ++++----- pkg/op/verifier_id_token_hint.go | 6 ++--- pkg/op/verifier_id_token_hint_test.go | 12 ++++----- pkg/op/verifier_jwt_profile.go | 8 ++++-- pkg/op/verifier_jwt_profile_test.go | 6 ++--- 18 files changed, 78 insertions(+), 54 deletions(-) diff --git a/pkg/client/client.go b/pkg/client/client.go index b3a56eda..6927674d 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -7,6 +7,7 @@ import ( "io" "net/http" "net/url" + "slices" "strings" "time" @@ -27,11 +28,15 @@ var ( // Discover calls the discovery endpoint of the provided issuer and returns its configuration // It accepts an optional argument "wellknownUrl" which can be used to overide the dicovery endpoint url -func Discover(ctx context.Context, issuer string, httpClient *http.Client, wellKnownUrl ...string) (*oidc.DiscoveryConfiguration, error) { +func Discover(ctx context.Context, issuers []string, httpClient *http.Client, wellKnownUrl ...string) (*oidc.DiscoveryConfiguration, error) { ctx, span := Tracer.Start(ctx, "Discover") defer span.End() - wellKnown := strings.TrimSuffix(issuer, "/") + oidc.DiscoveryEndpoint + wellKnown := "" + if len(issuers) > 0 { + wellKnown = strings.TrimSuffix(issuers[0], "/") + oidc.DiscoveryEndpoint + } + if len(wellKnownUrl) == 1 && wellKnownUrl[0] != "" { wellKnown = wellKnownUrl[0] } @@ -48,7 +53,7 @@ func Discover(ctx context.Context, issuer string, httpClient *http.Client, wellK logger.Debug("discover", "config", discoveryConfig) } - if false && discoveryConfig.Issuer != issuer { + if !slices.Contains(issuers, discoveryConfig.Issuer) { return nil, oidc.ErrIssuerInvalid } return discoveryConfig, nil diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index a24416fb..ea29b4af 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -5,9 +5,9 @@ import ( "net/http" "testing" + "github.com/datasapiens/oidc/v3/pkg/oidc" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - "github.com/datasapiens/oidc/v3/pkg/oidc" ) func TestDiscover(t *testing.T) { @@ -45,7 +45,7 @@ func TestDiscover(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := Discover(context.Background(), tt.args.issuer, http.DefaultClient, tt.args.wellKnownUrl...) + got, err := Discover(context.Background(), []string{tt.args.issuer}, http.DefaultClient, tt.args.wellKnownUrl...) require.ErrorIs(t, err, tt.wantErr) if tt.wantFields == nil { return diff --git a/pkg/client/profile/jwt_profile.go b/pkg/client/profile/jwt_profile.go index 84ae6f45..9f3ec4ed 100644 --- a/pkg/client/profile/jwt_profile.go +++ b/pkg/client/profile/jwt_profile.go @@ -82,7 +82,7 @@ func NewJWTProfileTokenSource(ctx context.Context, issuer, clientID, keyID strin opt(source) } if source.tokenEndpoint == "" { - config, err := client.Discover(ctx, issuer, source.httpClient) + config, err := client.Discover(ctx, []string{issuer}, source.httpClient) if err != nil { return nil, err } diff --git a/pkg/client/rp/relying_party.go b/pkg/client/rp/relying_party.go index 18cc74e6..7bae7ec6 100644 --- a/pkg/client/rp/relying_party.go +++ b/pkg/client/rp/relying_party.go @@ -102,7 +102,7 @@ var DefaultUnauthorizedHandler UnauthorizedHandler = func(w http.ResponseWriter, } type relyingParty struct { - issuer string + issuers []string DiscoveryEndpoint string endpoints Endpoints oauthConfig *oauth2.Config @@ -128,7 +128,15 @@ func (rp *relyingParty) OAuthConfig() *oauth2.Config { } func (rp *relyingParty) Issuer() string { - return rp.issuer + if len(rp.issuers) == 0 { + return "" + } + + return rp.issuers[0] +} + +func (rp *relyingParty) Issuers() []string { + return rp.issuers } func (rp *relyingParty) IsPKCE() bool { @@ -169,7 +177,7 @@ func (rp *relyingParty) GetRevokeEndpoint() string { func (rp *relyingParty) IDTokenVerifier() *IDTokenVerifier { if rp.idTokenVerifier == nil { - rp.idTokenVerifier = NewIDTokenVerifier(rp.issuer, rp.oauthConfig.ClientID, NewRemoteKeySet(rp.httpClient, rp.endpoints.JKWsURL), rp.verifierOpts...) + rp.idTokenVerifier = NewIDTokenVerifier(rp.issuers, rp.oauthConfig.ClientID, NewRemoteKeySet(rp.httpClient, rp.endpoints.JKWsURL), rp.verifierOpts...) } return rp.idTokenVerifier } @@ -236,8 +244,16 @@ func NewRelyingPartyOAuth(config *oauth2.Config, options ...Option) (RelyingPart // issuer, clientID, clientSecret, redirectURI, scopes and possible configOptions // it will run discovery on the provided issuer and use the found endpoints func NewRelyingPartyOIDC(ctx context.Context, issuer, clientID, clientSecret, redirectURI string, scopes []string, options ...Option) (RelyingParty, error) { + + return NewRelyingPartyOIDCWithIssuers(ctx, []string{issuer}, clientID, clientSecret, redirectURI, scopes, options...) +} + +// NewRelyingPartyOIDCWithIssuers creates an (OIDC) RelyingParty with the given +// issuers, clientID, clientSecret, redirectURI, scopes and possible configOptions +// it will run discovery on the provided issuers and use the found endpoints +func NewRelyingPartyOIDCWithIssuers(ctx context.Context, issuers []string, clientID, clientSecret, redirectURI string, scopes []string, options ...Option) (RelyingParty, error) { rp := &relyingParty{ - issuer: issuer, + issuers: issuers, oauthConfig: &oauth2.Config{ ClientID: clientID, ClientSecret: clientSecret, @@ -256,7 +272,7 @@ func NewRelyingPartyOIDC(ctx context.Context, issuer, clientID, clientSecret, re } } ctx = logCtxWithRPData(ctx, rp, "function", "NewRelyingPartyOIDC") - discoveryConfiguration, err := client.Discover(ctx, rp.issuer, rp.httpClient, rp.DiscoveryEndpoint) + discoveryConfiguration, err := client.Discover(ctx, rp.issuers, rp.httpClient, rp.DiscoveryEndpoint) if err != nil { return nil, err } diff --git a/pkg/client/rp/relying_party_test.go b/pkg/client/rp/relying_party_test.go index 3f634d08..872dad2b 100644 --- a/pkg/client/rp/relying_party_test.go +++ b/pkg/client/rp/relying_party_test.go @@ -20,7 +20,7 @@ import ( func Test_verifyTokenResponse(t *testing.T) { verifier := &IDTokenVerifier{ - Issuer: tu.ValidIssuer, + Issuers: []string{tu.ValidIssuer}, MaxAgeIAT: 2 * time.Minute, ClientID: tu.ValidClientID, Offset: time.Second, diff --git a/pkg/client/rp/verifier.go b/pkg/client/rp/verifier.go index 19b597e2..0a6c67f1 100644 --- a/pkg/client/rp/verifier.go +++ b/pkg/client/rp/verifier.go @@ -49,7 +49,7 @@ func VerifyIDToken[C oidc.Claims](ctx context.Context, token string, v *IDTokenV return nilClaims, err } - if err = oidc.CheckIssuer(claims, v.Issuer); err != nil { + if err = oidc.CheckIssuer(claims, v.Issuers); err != nil { return nilClaims, err } @@ -110,9 +110,9 @@ func VerifyAccessToken(accessToken, atHash string, sigAlgorithm jose.SignatureAl } // NewIDTokenVerifier returns a oidc.Verifier suitable for ID token verification. -func NewIDTokenVerifier(issuer, clientID string, keySet oidc.KeySet, options ...VerifierOption) *IDTokenVerifier { +func NewIDTokenVerifier(issuers []string, clientID string, keySet oidc.KeySet, options ...VerifierOption) *IDTokenVerifier { v := &IDTokenVerifier{ - Issuer: issuer, + Issuers: issuers, ClientID: clientID, KeySet: keySet, Offset: time.Second, diff --git a/pkg/client/rp/verifier_test.go b/pkg/client/rp/verifier_test.go index 0557e8bd..bbead555 100644 --- a/pkg/client/rp/verifier_test.go +++ b/pkg/client/rp/verifier_test.go @@ -5,16 +5,16 @@ import ( "testing" "time" + tu "github.com/datasapiens/oidc/v3/internal/testutil" + "github.com/datasapiens/oidc/v3/pkg/oidc" jose "github.com/go-jose/go-jose/v4" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - tu "github.com/datasapiens/oidc/v3/internal/testutil" - "github.com/datasapiens/oidc/v3/pkg/oidc" ) func TestVerifyTokens(t *testing.T) { verifier := &IDTokenVerifier{ - Issuer: tu.ValidIssuer, + Issuers: []string{tu.ValidIssuer}, MaxAgeIAT: 2 * time.Minute, Offset: time.Second, SupportedSignAlgs: []string{string(tu.SignatureAlgorithm)}, @@ -93,7 +93,7 @@ func TestVerifyTokens(t *testing.T) { func TestVerifyIDToken(t *testing.T) { verifier := &IDTokenVerifier{ - Issuer: tu.ValidIssuer, + Issuers: []string{tu.ValidIssuer}, MaxAgeIAT: 2 * time.Minute, Offset: time.Second, SupportedSignAlgs: []string{string(tu.SignatureAlgorithm)}, @@ -341,7 +341,7 @@ func TestNewIDTokenVerifier(t *testing.T) { }, }, want: &IDTokenVerifier{ - Issuer: tu.ValidIssuer, + Issuers: []string{tu.ValidIssuer}, Offset: time.Minute, MaxAgeIAT: time.Hour, ClientID: tu.ValidClientID, @@ -355,7 +355,7 @@ func TestNewIDTokenVerifier(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got := NewIDTokenVerifier(tt.args.issuer, tt.args.clientID, tt.args.keySet, tt.args.options...) + got := NewIDTokenVerifier([]string{tt.args.issuer}, tt.args.clientID, tt.args.keySet, tt.args.options...) assert.Equal(t, tt.want, got) }) } diff --git a/pkg/client/rp/verifier_tokens_example_test.go b/pkg/client/rp/verifier_tokens_example_test.go index d90e4d02..5a2aa978 100644 --- a/pkg/client/rp/verifier_tokens_example_test.go +++ b/pkg/client/rp/verifier_tokens_example_test.go @@ -71,7 +71,7 @@ const idToken = `eyJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ.eyJhY3IiOiJzb21ldGhpbmciLCJh const accessToken = `eyJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ.eyJhdWQiOlsidW5pdCIsInRlc3QiXSwiYmFyIjp7ImNvdW50IjoyMiwidGFncyI6WyJzb21lIiwidGFncyJdfSwiZXhwIjo0ODAyMjM4NjgyLCJmb28iOiJIZWxsbywgV29ybGQhIiwiaWF0IjoxNjc4MTAxMDIxLCJpc3MiOiJsb2NhbC5jb20iLCJqdGkiOiI5ODc2IiwibmJmIjoxNjc4MTAxMDIxLCJzdWIiOiJ0aW1AbG9jYWwuY29tIn0.Zrz3LWSRjCMJZUMaI5dUbW4vGdSmEeJQ3ouhaX0bcW9rdFFLgBI4K2FWJhNivq8JDmCGSxwLu3mI680GWmDaEoAx1M5sCO9lqfIZHGZh-lfAXk27e6FPLlkTDBq8Bx4o4DJ9Fw0hRJGjUTjnYv5cq1vo2-UqldasL6CwTbkzNC_4oQFfRtuodC4Ql7dZ1HRv5LXuYx7KPkOssLZtV9cwtJp5nFzKjcf2zEE_tlbjcpynMwypornRUp1EhCWKRUGkJhJeiP71ECY5pQhShfjBu9Nc5wDpSnZmnk2S4YsPrRK3QkE-iEkas8BfsOCrGoErHjEJexAIDjasGO5PFLWfCA` func ExampleVerifyTokens_customClaims() { - v := rp.NewIDTokenVerifier("local.com", "555666", tu.KeySet{}, + v := rp.NewIDTokenVerifier([]string{"local.com"}, "555666", tu.KeySet{}, rp.WithNonce(func(ctx context.Context) string { return "12345" }), ) diff --git a/pkg/client/rs/resource_server.go b/pkg/client/rs/resource_server.go index 5a98768d..44b52e36 100644 --- a/pkg/client/rs/resource_server.go +++ b/pkg/client/rs/resource_server.go @@ -73,7 +73,7 @@ func newResourceServer(ctx context.Context, issuer string, authorizer func() (an optFunc(rs) } if rs.introspectURL == "" || rs.tokenURL == "" { - config, err := client.Discover(ctx, rs.issuer, rs.httpClient) + config, err := client.Discover(ctx, []string{issuer}, rs.httpClient) if err != nil { return nil, err } diff --git a/pkg/client/tokenexchange/tokenexchange.go b/pkg/client/tokenexchange/tokenexchange.go index 3ab50f09..aacd80b2 100644 --- a/pkg/client/tokenexchange/tokenexchange.go +++ b/pkg/client/tokenexchange/tokenexchange.go @@ -6,10 +6,10 @@ import ( "net/http" "time" - "github.com/go-jose/go-jose/v4" "github.com/datasapiens/oidc/v3/pkg/client" httphelper "github.com/datasapiens/oidc/v3/pkg/http" "github.com/datasapiens/oidc/v3/pkg/oidc" + "github.com/go-jose/go-jose/v4" ) type TokenExchanger interface { @@ -55,7 +55,7 @@ func newOAuthTokenExchange(ctx context.Context, issuer string, authorizer func() } if te.tokenEndpoint == "" { - config, err := client.Discover(ctx, issuer, te.httpClient) + config, err := client.Discover(ctx, []string{issuer}, te.httpClient) if err != nil { return nil, err } diff --git a/pkg/oidc/verifier.go b/pkg/oidc/verifier.go index 90856173..fa98d4f7 100644 --- a/pkg/oidc/verifier.go +++ b/pkg/oidc/verifier.go @@ -65,7 +65,7 @@ var ( // functions. Use package specific constructor functions to know // which values need to be set. type Verifier struct { - Issuer string + Issuers []string MaxAgeIAT time.Duration Offset time.Duration ClientID string @@ -115,10 +115,9 @@ func CheckSubject(claims Claims) error { return nil } -func CheckIssuer(claims Claims, issuer string) error { - return nil - if claims.GetIssuer() != issuer { - return fmt.Errorf("%w: Expected: %s, got: %s", ErrIssuerInvalid, issuer, claims.GetIssuer()) +func CheckIssuer(claims Claims, issuers []string) error { + if !slices.Contains(issuers, claims.GetIssuer()) { + return fmt.Errorf("%w: Expected one of: %v, got: %s", ErrIssuerInvalid, issuers, claims.GetIssuer()) } return nil } diff --git a/pkg/oidc/verifier_test.go b/pkg/oidc/verifier_test.go index a0154146..282a4efb 100644 --- a/pkg/oidc/verifier_test.go +++ b/pkg/oidc/verifier_test.go @@ -100,7 +100,7 @@ func TestCheckIssuer(t *testing.T) { } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - err := CheckIssuer(tt.claims, issuer) + err := CheckIssuer(tt.claims, []string{issuer}) assert.ErrorIs(t, err, tt.wantErr) }) } diff --git a/pkg/op/verifier_access_token.go b/pkg/op/verifier_access_token.go index 4d739e45..0ff75983 100644 --- a/pkg/op/verifier_access_token.go +++ b/pkg/op/verifier_access_token.go @@ -19,8 +19,8 @@ func WithSupportedAccessTokenSigningAlgorithms(algs ...string) AccessTokenVerifi // NewAccessTokenVerifier returns a AccessTokenVerifier suitable for access token verification. func NewAccessTokenVerifier(issuer string, keySet oidc.KeySet, opts ...AccessTokenVerifierOpt) *AccessTokenVerifier { verifier := &AccessTokenVerifier{ - Issuer: issuer, - KeySet: keySet, + Issuers: []string{issuer}, + KeySet: keySet, } for _, opt := range opts { opt(verifier) @@ -44,7 +44,7 @@ func VerifyAccessToken[C oidc.Claims](ctx context.Context, token string, v *Acce return nilClaims, err } - if err := oidc.CheckIssuer(claims, v.Issuer); err != nil { + if err := oidc.CheckIssuer(claims, v.Issuers); err != nil { return nilClaims, err } diff --git a/pkg/op/verifier_access_token_test.go b/pkg/op/verifier_access_token_test.go index 98f0bfd6..23fa81d9 100644 --- a/pkg/op/verifier_access_token_test.go +++ b/pkg/op/verifier_access_token_test.go @@ -5,10 +5,10 @@ import ( "testing" "time" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" tu "github.com/datasapiens/oidc/v3/internal/testutil" "github.com/datasapiens/oidc/v3/pkg/oidc" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestNewAccessTokenVerifier(t *testing.T) { @@ -29,8 +29,8 @@ func TestNewAccessTokenVerifier(t *testing.T) { keySet: tu.KeySet{}, }, want: &AccessTokenVerifier{ - Issuer: tu.ValidIssuer, - KeySet: tu.KeySet{}, + Issuers: []string{tu.ValidIssuer}, + KeySet: tu.KeySet{}, }, }, { @@ -43,7 +43,7 @@ func TestNewAccessTokenVerifier(t *testing.T) { }, }, want: &AccessTokenVerifier{ - Issuer: tu.ValidIssuer, + Issuers: []string{tu.ValidIssuer}, KeySet: tu.KeySet{}, SupportedSignAlgs: []string{"ABC", "DEF"}, }, @@ -59,7 +59,7 @@ func TestNewAccessTokenVerifier(t *testing.T) { func TestVerifyAccessToken(t *testing.T) { verifier := &AccessTokenVerifier{ - Issuer: tu.ValidIssuer, + Issuers: []string{tu.ValidIssuer}, MaxAgeIAT: 2 * time.Minute, Offset: time.Second, SupportedSignAlgs: []string{string(tu.SignatureAlgorithm)}, diff --git a/pkg/op/verifier_id_token_hint.go b/pkg/op/verifier_id_token_hint.go index a1dff722..01e9d4b0 100644 --- a/pkg/op/verifier_id_token_hint.go +++ b/pkg/op/verifier_id_token_hint.go @@ -19,8 +19,8 @@ func WithSupportedIDTokenHintSigningAlgorithms(algs ...string) IDTokenHintVerifi func NewIDTokenHintVerifier(issuer string, keySet oidc.KeySet, opts ...IDTokenHintVerifierOpt) *IDTokenHintVerifier { verifier := &IDTokenHintVerifier{ - Issuer: issuer, - KeySet: keySet, + Issuers: []string{issuer}, + KeySet: keySet, } for _, opt := range opts { opt(verifier) @@ -60,7 +60,7 @@ func VerifyIDTokenHint[C oidc.Claims](ctx context.Context, token string, v *IDTo return nilClaims, err } - if err := oidc.CheckIssuer(claims, v.Issuer); err != nil { + if err := oidc.CheckIssuer(claims, v.Issuers); err != nil { return nilClaims, err } diff --git a/pkg/op/verifier_id_token_hint_test.go b/pkg/op/verifier_id_token_hint_test.go index 4ba76abc..c15439dc 100644 --- a/pkg/op/verifier_id_token_hint_test.go +++ b/pkg/op/verifier_id_token_hint_test.go @@ -6,10 +6,10 @@ import ( "testing" "time" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" tu "github.com/datasapiens/oidc/v3/internal/testutil" "github.com/datasapiens/oidc/v3/pkg/oidc" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestNewIDTokenHintVerifier(t *testing.T) { @@ -30,8 +30,8 @@ func TestNewIDTokenHintVerifier(t *testing.T) { keySet: tu.KeySet{}, }, want: &IDTokenHintVerifier{ - Issuer: tu.ValidIssuer, - KeySet: tu.KeySet{}, + Issuers: []string{tu.ValidIssuer}, + KeySet: tu.KeySet{}, }, }, { @@ -44,7 +44,7 @@ func TestNewIDTokenHintVerifier(t *testing.T) { }, }, want: &IDTokenHintVerifier{ - Issuer: tu.ValidIssuer, + Issuers: []string{tu.ValidIssuer}, KeySet: tu.KeySet{}, SupportedSignAlgs: []string{"ABC", "DEF"}, }, @@ -67,7 +67,7 @@ func Test_IDTokenHintExpiredError(t *testing.T) { func TestVerifyIDTokenHint(t *testing.T) { verifier := &IDTokenHintVerifier{ - Issuer: tu.ValidIssuer, + Issuers: []string{tu.ValidIssuer}, MaxAgeIAT: 2 * time.Minute, Offset: time.Second, SupportedSignAlgs: []string{string(tu.SignatureAlgorithm)}, diff --git a/pkg/op/verifier_jwt_profile.go b/pkg/op/verifier_jwt_profile.go index e3ce496b..e7d7e8e6 100644 --- a/pkg/op/verifier_jwt_profile.go +++ b/pkg/op/verifier_jwt_profile.go @@ -34,7 +34,7 @@ func NewJWTProfileVerifierKeySet(keySet oidc.KeySet, issuer string, maxAgeIAT, o func newJWTProfileVerifier(storage JWTProfileKeyStorage, keySet oidc.KeySet, issuer string, maxAgeIAT, offset time.Duration, opts ...JWTProfileVerifierOption) *JWTProfileVerifier { j := &JWTProfileVerifier{ Verifier: oidc.Verifier{ - Issuer: issuer, + Issuers: []string{issuer}, MaxAgeIAT: maxAgeIAT, Offset: offset, }, @@ -73,7 +73,11 @@ func VerifyJWTAssertion(ctx context.Context, assertion string, v *JWTProfileVeri return nil, err } - if err = oidc.CheckAudience(request, v.Issuer); err != nil { + if len(v.Issuers) == 0 { + return nil, errors.New("no issuers provided") + } + + if err = oidc.CheckAudience(request, v.Issuers[0]); err != nil { return nil, err } diff --git a/pkg/op/verifier_jwt_profile_test.go b/pkg/op/verifier_jwt_profile_test.go index fa5c86a1..2d69d553 100644 --- a/pkg/op/verifier_jwt_profile_test.go +++ b/pkg/op/verifier_jwt_profile_test.go @@ -5,17 +5,17 @@ import ( "testing" "time" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" tu "github.com/datasapiens/oidc/v3/internal/testutil" "github.com/datasapiens/oidc/v3/pkg/oidc" "github.com/datasapiens/oidc/v3/pkg/op" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestNewJWTProfileVerifier(t *testing.T) { want := &op.JWTProfileVerifier{ Verifier: oidc.Verifier{ - Issuer: tu.ValidIssuer, + Issuers: []string{tu.ValidIssuer}, MaxAgeIAT: time.Minute, Offset: time.Second, },