git.iko.soy/typeable/oauth2-proxy
on master help sign in
improved audience handling to support client credentials access tokens without aud claims (#1204)

* implementation draft * add cfg options skip-au-when-missing && client-id-verification-claim; enhance the provider data verification logic for sake of the added options * refactor configs, added logging and add additional claim verification * simplify logic by just having one configuration similar to oidc-email-claim * added internal oidc token verifier, so that aud check behavior can be managed with oauth2-proxy and is compatible with extra-jwt-issuers * refactored verification to reduce complexity * refactored verification to reduce complexity * added docs * adjust tests to support new OIDCAudienceClaim and OIDCExtraAudiences options * extend unit tests and ensure that audience is set with the value of aud claim configuration * revert filemodes and update docs * update docs * remove unneccesary logging, refactor audience existence check and added additional unit tests * fix linting issues after rebase on origin/main * cleanup: use new imports for migrated libraries after rebase on origin/main * adapt mock in keycloak_oidc_test.go * allow specifying multiple audience claims, fixed bug where jwt issuers client id was not the being considered and fixed bug where aud claims with multiple audiences has broken the whole validation * fixed formatting issue * do not pass the whole options struct to minimize complexity and dependency to the configuration structure * added changelog entry * update docs Co-authored-by: Sofia Weiler <sofia.weiler@aoe.com> Co-authored-by: Christian Zenker <christian.zenker@aoe.com>

commit25371ea4afdc1c2e28a04a3adb8fbe941df843c8 authorKevin Schu <kevin.schu@aoe.com> dateTue 15 Feb 2022, 17:12 (5 years ago) parentc5a98c6
20 files changed+536−52
CHANGELOG.md+1 docs/docs/configuration/alpha_config.md+2 docs/docs/configuration/overview.md+2 main_test.go+4 oauthproxy_test.go+10−2 pkg/apis/options/legacy_options.go+8 pkg/apis/options/legacy_options_test.go+2 pkg/apis/options/load_test.go+1 pkg/apis/options/options.go+17−13 pkg/apis/options/providers.go+8 pkg/oidc/oidc_suite_test.go+16 pkg/oidc/verify.go+100 pkg/oidc/verify_test.go+249 pkg/validation/options.go+38−14 providers/adfs_test.go+8−2 providers/azure_test.go+19−6 providers/keycloak_oidc_test.go+13−3 providers/oidc_test.go+7−2 providers/provider_data.go+4−1 providers/provider_data_test.go+27−9
CHANGELOG.md+1
@@ -10,6 +10,7 @@
1010
1111- [#1489](https://github.com/oauth2-proxy/oauth2-proxy/pull/1489) Fix Docker Buildx push to include build version (@JoelSpeed)
1212- [#1477](https://github.com/oauth2-proxy/oauth2-proxy/pull/1477) Remove provider documentation for `Microsoft Azure AD` (@omBratteng)
13+- [#1204](https://github.com/oauth2-proxy/oauth2-proxy/pull/1204) Added configuration for audience claim (`--oidc-extra-audience`) and ability to specify extra audiences (`--oidc-extra-audience`) allowed passing audience verification. This enables support for AWS Cognito and other issuers that have custom audience claims. Also, this adds the ability to allow multiple audiences. (@kschu91)
1314- [#1509](https://github.com/oauth2-proxy/oauth2-proxy/pull/1509) Update LoginGovProvider ValidateSession to pass access_token in Header (@pksheldon4)
1415- [#1474](https://github.com/oauth2-proxy/oauth2-proxy/pull/1474) Support configuration of minimal acceptable TLS version (@polarctos)
1516- [#1545](https://github.com/oauth2-proxy/oauth2-proxy/pull/1545) Fix issue with query string allowed group panic on skip methods (@andytson)
docs/docs/configuration/alpha_config.md+2
@@ -281,6 +281,8 @@ make up the header value
281281| `emailClaim` | _string_ | EmailClaim indicates which claim contains the user email,<br/>default set to 'email' |
282282| `groupsClaim` | _string_ | GroupsClaim indicates which claim contains the user groups<br/>default set to 'groups' |
283283| `userIDClaim` | _string_ | UserIDClaim indicates which claim contains the user ID<br/>default set to 'email' |
284+| `audienceClaims` | _[]string_ | AudienceClaim allows to define any claim that is verified against the client id<br/>By default `aud` claim is used for verification. |
285+| `extraAudiences` | _[]string_ | ExtraAudiences is a list of additional audiences that are allowed<br/>to pass verification in addition to the client id. |
284286
285287### Provider
286288
docs/docs/configuration/overview.md+2
@@ -136,6 +136,8 @@ An example [oauth2-proxy.cfg](https://github.com/oauth2-proxy/oauth2-proxy/blob/
136136| `--oidc-jwks-url` | string | OIDC JWKS URI for token verification; required if OIDC discovery is disabled | |
137137| `--oidc-email-claim` | string | which OIDC claim contains the user's email | `"email"` |
138138| `--oidc-groups-claim` | string | which OIDC claim contains the user groups | `"groups"` |
139+| `--oidc-audience-claim` | string | which OIDC claim contains the audience | `"aud"` |
140+| `--oidc-extra-audience` | string \| list | additional audiences which are allowed to pass verification | `"[]"` |
139141| `--pass-access-token` | bool | pass OAuth access_token to upstream via X-Forwarded-Access-Token header. When used with `--set-xauthrequest` this adds the X-Auth-Request-Access-Token header to the response | false |
140142| `--pass-authorization-header` | bool | pass OIDC IDToken to upstream via Authorization Bearer header | false |
141143| `--pass-basic-auth` | bool | pass HTTP Basic Auth, X-Forwarded-User, X-Forwarded-Email and X-Forwarded-Preferred-Username information to upstream | true |
main_test.go+4
@@ -76,6 +76,8 @@ providers:
7676 emailClaim: email
7777 userIDClaim: email
7878 insecureSkipNonce: true
79+ audienceClaims: [aud]
80+ extraAudiences: []
7981`
8082
8183 const testCoreConfig = `
@@ -148,6 +150,8 @@ redirect_url="http://localhost:4180/oauth2/callback"
148150 GroupsClaim: "groups",
149151 EmailClaim: "email",
150152 UserIDClaim: "email",
153+ AudienceClaims: []string{"aud"},
154+ ExtraAudiences: []string{},
151155 InsecureSkipNonce: true,
152156 },
153157 ApprovalPrompt: "force",
oauthproxy_test.go+10−2
@@ -21,6 +21,7 @@ import (
2121 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
2222 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/cookies"
2323 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
24+ internaloidc "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/oidc"
2425 sessionscookie "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/sessions/cookie"
2526 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/upstream"
2627 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/validation"
@@ -1737,7 +1738,14 @@ func TestGetJwtSession(t *testing.T) {
17371738
17381739 keyset := NoOpKeySet{}
17391740 verifier := oidc.NewVerifier("https://issuer.example.com", keyset,
1740− &oidc.Config{ClientID: "https://test.myapp.com", SkipExpiryCheck: true})
1741+ &oidc.Config{ClientID: "https://test.myapp.com", SkipExpiryCheck: true,
1742+ SkipClientIDCheck: true})
1743+ verificationOptions := &internaloidc.IDTokenVerificationOptions{
1744+ AudienceClaims: []string{"aud"},
1745+ ClientID: "https://test.myapp.com",
1746+ ExtraAudiences: []string{},
1747+ }
1748+ internalVerifier := internaloidc.NewVerifier(verifier, verificationOptions)
17411749
17421750 test, err := NewAuthOnlyEndpointTest("", func(opts *options.Options) {
17431751 opts.InjectRequestHeaders = []options.Header{
@@ -1808,7 +1816,7 @@ func TestGetJwtSession(t *testing.T) {
18081816 },
18091817 }
18101818 opts.SkipJwtBearerTokens = true
1811− opts.SetJWTBearerVerifiers(append(opts.GetJWTBearerVerifiers(), verifier))
1819+ opts.SetJWTBearerVerifiers(append(opts.GetJWTBearerVerifiers(), internalVerifier))
18121820 })
18131821 if err != nil {
18141822 t.Fatal(err)
pkg/apis/options/legacy_options.go+8
@@ -54,6 +54,8 @@ func NewLegacyOptions() *LegacyOptions {
5454 UserIDClaim: "email",
5555 OIDCEmailClaim: "email",
5656 OIDCGroupsClaim: "groups",
57+ OIDCAudienceClaims: []string{"aud"},
58+ OIDCExtraAudiences: []string{},
5759 InsecureOIDCSkipNonce: true,
5860 },
5961
@@ -500,6 +502,8 @@ type LegacyProvider struct {
500502 OIDCJwksURL string `flag:"oidc-jwks-url" cfg:"oidc_jwks_url"`
501503 OIDCEmailClaim string `flag:"oidc-email-claim" cfg:"oidc_email_claim"`
502504 OIDCGroupsClaim string `flag:"oidc-groups-claim" cfg:"oidc_groups_claim"`
505+ OIDCAudienceClaims []string `flag:"oidc-audience-claim" cfg:"oidc_audience_claims"`
506+ OIDCExtraAudiences []string `flag:"oidc-extra-audience" cfg:"oidc_extra_audiences"`
503507 LoginURL string `flag:"login-url" cfg:"login_url"`
504508 RedeemURL string `flag:"redeem-url" cfg:"redeem_url"`
505509 ProfileURL string `flag:"profile-url" cfg:"profile_url"`
@@ -550,6 +554,8 @@ func legacyProviderFlagSet() *pflag.FlagSet {
550554 flagSet.String("oidc-jwks-url", "", "OpenID Connect JWKS URL (ie: https://www.googleapis.com/oauth2/v3/certs)")
551555 flagSet.String("oidc-groups-claim", providers.OIDCGroupsClaim, "which OIDC claim contains the user groups")
552556 flagSet.String("oidc-email-claim", providers.OIDCEmailClaim, "which OIDC claim contains the user's email")
557+ flagSet.StringSlice("oidc-audience-claim", providers.OIDCAudienceClaims, "which OIDC claims are used as audience to verify against client id")
558+ flagSet.StringSlice("oidc-extra-audience", []string{}, "additional audiences allowed to pass audience verification")
553559 flagSet.String("login-url", "", "Authentication endpoint")
554560 flagSet.String("redeem-url", "", "Token redemption endpoint")
555561 flagSet.String("profile-url", "", "Profile access endpoint")
@@ -644,6 +650,8 @@ func (l *LegacyProvider) convert() (Providers, error) {
644650 UserIDClaim: l.UserIDClaim,
645651 EmailClaim: l.OIDCEmailClaim,
646652 GroupsClaim: l.OIDCGroupsClaim,
653+ AudienceClaims: l.OIDCAudienceClaims,
654+ ExtraAudiences: l.OIDCExtraAudiences,
647655 }
648656
649657 // This part is out of the switch section because azure has a default tenant
pkg/apis/options/legacy_options_test.go+2
@@ -116,6 +116,8 @@ var _ = Describe("Legacy Options", func() {
116116 opts.Providers[0].ClientID = "oauth-proxy"
117117 opts.Providers[0].ID = "google=oauth-proxy"
118118 opts.Providers[0].OIDCConfig.InsecureSkipNonce = true
119+ opts.Providers[0].OIDCConfig.AudienceClaims = []string{"aud"}
120+ opts.Providers[0].OIDCConfig.ExtraAudiences = []string{}
119121
120122 converted, err := legacyOpts.ToOptions()
121123 Expect(err).ToNot(HaveOccurred())
pkg/apis/options/load_test.go+1
@@ -42,6 +42,7 @@ var _ = Describe("Load", func() {
4242 UserIDClaim: "email",
4343 OIDCEmailClaim: "email",
4444 OIDCGroupsClaim: "groups",
45+ OIDCAudienceClaims: []string{"aud"},
4546 InsecureOIDCSkipNonce: true,
4647 },
4748
pkg/apis/options/options.go+17−13
@@ -4,8 +4,8 @@ import (
44 "crypto"
55 "net/url"
66
7− "github.com/coreos/go-oidc/v3/oidc"
87 ipapi "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/ip"
8+ internaloidc "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/oidc"
99 "github.com/oauth2-proxy/oauth2-proxy/v7/providers"
1010 "github.com/spf13/pflag"
1111)
@@ -70,25 +70,29 @@ type Options struct {
7070 redirectURL *url.URL
7171 provider providers.Provider
7272 signatureData *SignatureData
73− oidcVerifier *oidc.IDTokenVerifier
74− jwtBearerVerifiers []*oidc.IDTokenVerifier
73+ oidcVerifier *internaloidc.IDTokenVerifier
74+ jwtBearerVerifiers []*internaloidc.IDTokenVerifier
7575 realClientIPParser ipapi.RealClientIPParser
7676}
7777
7878// Options for Getting internal values
79−func (o *Options) GetRedirectURL() *url.URL { return o.redirectURL }
80−func (o *Options) GetProvider() providers.Provider { return o.provider }
81−func (o *Options) GetSignatureData() *SignatureData { return o.signatureData }
82−func (o *Options) GetOIDCVerifier() *oidc.IDTokenVerifier { return o.oidcVerifier }
83−func (o *Options) GetJWTBearerVerifiers() []*oidc.IDTokenVerifier { return o.jwtBearerVerifiers }
79+func (o *Options) GetRedirectURL() *url.URL { return o.redirectURL }
80+func (o *Options) GetProvider() providers.Provider { return o.provider }
81+func (o *Options) GetSignatureData() *SignatureData { return o.signatureData }
82+func (o *Options) GetOIDCVerifier() *internaloidc.IDTokenVerifier { return o.oidcVerifier }
83+func (o *Options) GetJWTBearerVerifiers() []*internaloidc.IDTokenVerifier {
84+ return o.jwtBearerVerifiers
85+}
8486func (o *Options) GetRealClientIPParser() ipapi.RealClientIPParser { return o.realClientIPParser }
8587
8688// Options for Setting internal values
87−func (o *Options) SetRedirectURL(s *url.URL) { o.redirectURL = s }
88−func (o *Options) SetProvider(s providers.Provider) { o.provider = s }
89−func (o *Options) SetSignatureData(s *SignatureData) { o.signatureData = s }
90−func (o *Options) SetOIDCVerifier(s *oidc.IDTokenVerifier) { o.oidcVerifier = s }
91−func (o *Options) SetJWTBearerVerifiers(s []*oidc.IDTokenVerifier) { o.jwtBearerVerifiers = s }
89+func (o *Options) SetRedirectURL(s *url.URL) { o.redirectURL = s }
90+func (o *Options) SetProvider(s providers.Provider) { o.provider = s }
91+func (o *Options) SetSignatureData(s *SignatureData) { o.signatureData = s }
92+func (o *Options) SetOIDCVerifier(s *internaloidc.IDTokenVerifier) { o.oidcVerifier = s }
93+func (o *Options) SetJWTBearerVerifiers(s []*internaloidc.IDTokenVerifier) {
94+ o.jwtBearerVerifiers = s
95+}
9296func (o *Options) SetRealClientIPParser(s ipapi.RealClientIPParser) { o.realClientIPParser = s }
9397
9498// NewOptions constructs a new Options with defaulted values
pkg/apis/options/providers.go+8
@@ -164,6 +164,12 @@ type OIDCOptions struct {
164164 // UserIDClaim indicates which claim contains the user ID
165165 // default set to 'email'
166166 UserIDClaim string `json:"userIDClaim,omitempty"`
167+ // AudienceClaim allows to define any claim that is verified against the client id
168+ // By default `aud` claim is used for verification.
169+ AudienceClaims []string `json:"audienceClaims,omitempty"`
170+ // ExtraAudiences is a list of additional audiences that are allowed
171+ // to pass verification in addition to the client id.
172+ ExtraAudiences []string `json:"extraAudiences,omitempty"`
167173}
168174
169175type LoginGovOptions struct {
@@ -191,6 +197,8 @@ func providerDefaults() Providers {
191197 UserIDClaim: providers.OIDCEmailClaim, // Deprecated: Use OIDCEmailClaim
192198 EmailClaim: providers.OIDCEmailClaim,
193199 GroupsClaim: providers.OIDCGroupsClaim,
200+ AudienceClaims: providers.OIDCAudienceClaims,
201+ ExtraAudiences: []string{},
194202 },
195203 },
196204 }
pkg/oidc/oidc_suite_test.gonew file+16
@@ -0,0 +1,16 @@
1+package oidc
2+
3+import (
4+ "testing"
5+
6+ "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
7+ . "github.com/onsi/ginkgo"
8+ . "github.com/onsi/gomega"
9+)
10+
11+func TestOIDCSuite(t *testing.T) {
12+ logger.SetOutput(GinkgoWriter)
13+
14+ RegisterFailHandler(Fail)
15+ RunSpecs(t, "OIDC")
16+}
pkg/oidc/verify.gonew file+100
@@ -0,0 +1,100 @@
1+package oidc
2+
3+import (
4+ "context"
5+ "fmt"
6+ "reflect"
7+
8+ "github.com/coreos/go-oidc/v3/oidc"
9+)
10+
11+// IDTokenVerifier Used to verify an ID Token and extends oidc.IDTokenVerifier from the underlying oidc library
12+type IDTokenVerifier struct {
13+ *oidc.IDTokenVerifier
14+ *IDTokenVerificationOptions
15+ allowedAudiences map[string]struct{}
16+}
17+
18+// IDTokenVerificationOptions options for the oidc.IDTokenVerifier that are required to verify an ID Token
19+type IDTokenVerificationOptions struct {
20+ AudienceClaims []string
21+ ClientID string
22+ ExtraAudiences []string
23+}
24+
25+// NewVerifier constructs a new IDTokenVerifier
26+func NewVerifier(iv *oidc.IDTokenVerifier, vo *IDTokenVerificationOptions) *IDTokenVerifier {
27+ allowedAudiences := make(map[string]struct{})
28+ allowedAudiences[vo.ClientID] = struct{}{}
29+ for _, extraAudience := range vo.ExtraAudiences {
30+ allowedAudiences[extraAudience] = struct{}{}
31+ }
32+ return &IDTokenVerifier{iv, vo, allowedAudiences}
33+}
34+
35+// Verify verifies incoming ID Token
36+func (v *IDTokenVerifier) Verify(ctx context.Context, rawIDToken string) (*oidc.IDToken, error) {
37+ token, err := v.IDTokenVerifier.Verify(ctx, rawIDToken)
38+ if err != nil {
39+ return nil, fmt.Errorf("failed to verify token: %v", err)
40+ }
41+
42+ claims := map[string]interface{}{}
43+ if err := token.Claims(&claims); err != nil {
44+ return nil, fmt.Errorf("failed to parse default id_token claims: %v", err)
45+ }
46+
47+ if isValidAudience, err := v.verifyAudience(token, claims); !isValidAudience {
48+ return nil, err
49+ }
50+
51+ return token, err
52+}
53+
54+func (v *IDTokenVerifier) verifyAudience(token *oidc.IDToken, claims map[string]interface{}) (bool, error) {
55+ for _, audienceClaim := range v.AudienceClaims {
56+ if audienceClaimValue, audienceClaimExists := claims[audienceClaim]; audienceClaimExists {
57+
58+ // audience claim value can be either interface{} or []interface{},
59+ // as per spec `aud` can be either a string or a list of strings
60+ switch audienceClaimValueType := audienceClaimValue.(type) {
61+ case []interface{}:
62+ token.Audience = v.interfaceSliceToString(audienceClaimValue)
63+ case interface{}:
64+ token.Audience = []string{audienceClaimValue.(string)}
65+ default:
66+ return false, fmt.Errorf("audience claim %s holds unsupported type %T",
67+ audienceClaim, audienceClaimValueType)
68+ }
69+
70+ return v.isValidAudience(audienceClaim, token.Audience, v.allowedAudiences)
71+ }
72+ }
73+
74+ return false, fmt.Errorf("audience claims %v do not exist in claims: %v",
75+ v.AudienceClaims, claims)
76+}
77+
78+func (v *IDTokenVerifier) isValidAudience(claim string, audience []string, allowedAudiences map[string]struct{}) (bool, error) {
79+ for _, aud := range audience {
80+ if _, allowedAudienceExists := allowedAudiences[aud]; allowedAudienceExists {
81+ return true, nil
82+ }
83+ }
84+
85+ return false, fmt.Errorf(
86+ "audience from claim %s with value %s does not match with any of allowed audiences %v",
87+ claim, audience, allowedAudiences)
88+}
89+
90+func (v *IDTokenVerifier) interfaceSliceToString(slice interface{}) []string {
91+ s := reflect.ValueOf(slice)
92+ if s.Kind() != reflect.Slice {
93+ panic(fmt.Sprintf("given a non-slice type %s", s.Kind()))
94+ }
95+ var strings []string
96+ for i := 0; i < s.Len(); i++ {
97+ strings = append(strings, s.Index(i).Interface().(string))
98+ }
99+ return strings
100+}
pkg/oidc/verify_test.gonew file+249
@@ -0,0 +1,249 @@
1+package oidc
2+
3+import (
4+ "context"
5+ "crypto/rand"
6+ "crypto/rsa"
7+ "encoding/json"
8+ "fmt"
9+
10+ "github.com/coreos/go-oidc/v3/oidc"
11+ . "github.com/onsi/ginkgo"
12+ . "github.com/onsi/gomega"
13+ "gopkg.in/square/go-jose.v2"
14+)
15+
16+var _ = Describe("Verify", func() {
17+ ctx := context.Background()
18+
19+ It("Succeeds with default aud behavior", func() {
20+ result, err := verify(ctx, &IDTokenVerificationOptions{
21+ AudienceClaims: []string{"aud"},
22+ ClientID: "1226737",
23+ ExtraAudiences: []string{},
24+ }, payload{
25+ Iss: "https://foo",
26+ Aud: "1226737",
27+ })
28+
29+ Expect(err).ToNot(HaveOccurred())
30+ Expect(result.Issuer).To(Equal("https://foo"))
31+ Expect(result.Audience).To(Equal([]string{"1226737"}))
32+ })
33+
34+ It("Fails with default aud behavior", func() {
35+ result, err := verify(ctx, &IDTokenVerificationOptions{
36+ AudienceClaims: []string{"aud"},
37+ ClientID: "7817818",
38+ ExtraAudiences: []string{},
39+ }, payload{
40+ Iss: "https://foo",
41+ Aud: "1226737",
42+ })
43+ Expect(err).To(MatchError("audience from claim aud with value [1226737] does not match with " +
44+ "any of allowed audiences map[7817818:{}]"))
45+ Expect(result).To(BeNil())
46+ })
47+
48+ It("Succeeds with extra audiences", func() {
49+ result, err := verify(ctx, &IDTokenVerificationOptions{
50+ AudienceClaims: []string{"aud"},
51+ ClientID: "7817818",
52+ ExtraAudiences: []string{"xyz", "1226737"},
53+ }, payload{
54+ Iss: "https://foo",
55+ Aud: "1226737",
56+ })
57+
58+ Expect(err).ToNot(HaveOccurred())
59+ Expect(result.Issuer).To(Equal("https://foo"))
60+ Expect(result.Audience).To(Equal([]string{"1226737"}))
61+ })
62+
63+ It("Fails with extra audiences", func() {
64+ result, err := verify(ctx, &IDTokenVerificationOptions{
65+ AudienceClaims: []string{"aud"},
66+ ClientID: "7817818",
67+ ExtraAudiences: []string{"xyz", "abc"},
68+ }, payload{
69+ Iss: "https://foo",
70+ Aud: "1226737",
71+ })
72+
73+ Expect(err).To(MatchError("audience from claim aud with value [1226737] does not match with any " +
74+ "of allowed audiences map[7817818:{} abc:{} xyz:{}]"))
75+ Expect(result).To(BeNil())
76+ })
77+
78+ It("Succeeds with non default aud behavior", func() {
79+ result, err := verify(ctx, &IDTokenVerificationOptions{
80+ AudienceClaims: []string{"client_id"},
81+ ClientID: "1226737",
82+ ExtraAudiences: []string{},
83+ }, payload{
84+ Iss: "https://foo",
85+ ClientID: "1226737",
86+ })
87+
88+ Expect(err).ToNot(HaveOccurred())
89+ Expect(result.Issuer).To(Equal("https://foo"))
90+ Expect(result.Audience).To(Equal([]string{"1226737"}))
91+ })
92+
93+ It("Fails with non default aud behavior", func() {
94+ result, err := verify(ctx, &IDTokenVerificationOptions{
95+ AudienceClaims: []string{"client_id"},
96+ ClientID: "7817818",
97+ ExtraAudiences: []string{},
98+ }, payload{
99+ Iss: "https://foo",
100+ ClientID: "1226737",
101+ })
102+ Expect(err).To(MatchError("audience from claim client_id with value [1226737] does not match with " +
103+ "any of allowed audiences map[7817818:{}]"))
104+ Expect(result).To(BeNil())
105+ })
106+
107+ It("Succeeds with non default aud behavior and extra audiences", func() {
108+ result, err := verify(ctx, &IDTokenVerificationOptions{
109+ AudienceClaims: []string{"client_id"},
110+ ClientID: "7817818",
111+ ExtraAudiences: []string{"xyz", "1226737"},
112+ }, payload{
113+ Iss: "https://foo",
114+ ClientID: "1226737",
115+ })
116+
117+ Expect(err).ToNot(HaveOccurred())
118+ Expect(result.Issuer).To(Equal("https://foo"))
119+ Expect(result.Audience).To(Equal([]string{"1226737"}))
120+ })
121+
122+ It("Fails with non default aud behavior and extra audiences", func() {
123+ result, err := verify(ctx, &IDTokenVerificationOptions{
124+ AudienceClaims: []string{"client_id"},
125+ ClientID: "7817818",
126+ ExtraAudiences: []string{"xyz", "abc"},
127+ }, payload{
128+ Iss: "https://foo",
129+ ClientID: "1226737",
130+ })
131+
132+ Expect(err).To(MatchError("audience from claim client_id with value [1226737] does not match with any " +
133+ "of allowed audiences map[7817818:{} abc:{} xyz:{}]"))
134+ Expect(result).To(BeNil())
135+ })
136+
137+ It("Fails if audience claim does not exist", func() {
138+ result, err := verify(ctx, &IDTokenVerificationOptions{
139+ AudienceClaims: []string{"not_exists"},
140+ ClientID: "7817818",
141+ ExtraAudiences: []string{"xyz", "abc"},
142+ }, payload{
143+ Iss: "https://foo",
144+ ClientID: "1226737",
145+ Aud: "1226737",
146+ })
147+
148+ Expect(err).To(MatchError("audience claims [not_exists] do not exist in claims: " +
149+ "map[aud:1226737 client_id:1226737 iss:https://foo]"))
150+ Expect(result).To(BeNil())
151+ })
152+
153+ It("Succeeds with multiple audiences", func() {
154+ var result, err = verify(ctx, &IDTokenVerificationOptions{
155+ AudienceClaims: []string{"client_id", "aud"},
156+ ClientID: "123456789",
157+ ExtraAudiences: []string{"1226737"},
158+ }, payload{
159+ Iss: "https://foo",
160+ ClientID: "123456789",
161+ Aud: []string{"1226737", "123456789"},
162+ })
163+
164+ Expect(err).ToNot(HaveOccurred())
165+ Expect(result.Issuer).To(Equal("https://foo"))
166+ Expect(result.Audience).To(Equal([]string{"123456789"}))
167+ })
168+
169+ It("Succeeds if aud claim match", func() {
170+ result, err := verify(ctx, &IDTokenVerificationOptions{
171+ AudienceClaims: []string{"client_id", "aud"},
172+ ClientID: "1226737",
173+ ExtraAudiences: []string{"xyz", "abc"},
174+ }, payload{
175+ Iss: "https://foo",
176+ ClientID: "1226737",
177+ Aud: "1226737",
178+ })
179+
180+ Expect(err).ToNot(HaveOccurred())
181+ Expect(result.Issuer).To(Equal("https://foo"))
182+ Expect(result.Audience).To(Equal([]string{"1226737"}))
183+ })
184+})
185+
186+type payload struct {
187+ Iss string `json:"iss,omitempty"`
188+ Aud interface{} `json:"aud,omitempty"`
189+ ClientID string `json:"client_id,omitempty"`
190+}
191+
192+type jwtToken struct {
193+ PrivateKey jose.JSONWebKey
194+ PublicKey jose.JSONWebKey
195+ Token string
196+}
197+
198+type testVerifier struct {
199+ jwk jose.JSONWebKey
200+}
201+
202+func (t *testVerifier) VerifySignature(ctx context.Context, jwt string) ([]byte, error) {
203+ jws, err := jose.ParseSigned(jwt)
204+ if err != nil {
205+ return nil, fmt.Errorf("oidc: malformed jwt: %v", err)
206+ }
207+ return jws.Verify(&t.jwk)
208+}
209+
210+func verify(ctx context.Context, verificationOptions *IDTokenVerificationOptions, payload payload) (*oidc.IDToken, error) {
211+ config := &oidc.Config{
212+ ClientID: "1226737",
213+ SkipClientIDCheck: true,
214+ SkipExpiryCheck: true, // required to not run in expired Token error during testing
215+ }
216+ rawToken, err := json.Marshal(payload)
217+ if err != nil {
218+ return nil, err
219+ }
220+ token, _ := createToken(rawToken)
221+ verifier := NewVerifier(oidc.NewVerifier("https://foo", &testVerifier{jwk: token.PublicKey}, config), verificationOptions)
222+ return verifier.Verify(ctx, token.Token)
223+}
224+
225+func createToken(payload []byte) (*jwtToken, error) {
226+ privateKey, err := rsa.GenerateKey(rand.Reader, 1028)
227+ if err != nil {
228+ return nil, err
229+ }
230+ privateWebKey := jose.JSONWebKey{Key: privateKey, Algorithm: string(jose.RS256), KeyID: ""}
231+ publicWebKey := jose.JSONWebKey{Key: privateKey.Public(), Use: "sig", Algorithm: string(jose.RS256), KeyID: ""}
232+ signer, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.RS256, Key: privateWebKey}, nil)
233+ if err != nil {
234+ return nil, err
235+ }
236+ jws, err := signer.Sign(payload)
237+ if err != nil {
238+ return nil, err
239+ }
240+ data, err := jws.CompactSerialize()
241+ if err != nil {
242+ return nil, err
243+ }
244+ return &jwtToken{
245+ PrivateKey: privateWebKey,
246+ PublicKey: publicWebKey,
247+ Token: data,
248+ }, nil
249+}
pkg/validation/options.go+38−14
@@ -16,6 +16,7 @@ import (
1616 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/options"
1717 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/ip"
1818 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
19+ internaloidc "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/oidc"
1920 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/requests"
2021 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/util"
2122 "github.com/oauth2-proxy/oauth2-proxy/v7/providers"
@@ -102,6 +103,18 @@ func Validate(o *options.Options) error {
102103 }
103104 }
104105
106+ config := &oidc.Config{
107+ ClientID: o.Providers[0].ClientID,
108+ SkipIssuerCheck: o.Providers[0].OIDCConfig.InsecureSkipIssuerVerification,
109+ SkipClientIDCheck: true, // client id check is done within oauth2-proxy: IDTokenVerifier.Verify
110+ }
111+
112+ verificationOptions := &internaloidc.IDTokenVerificationOptions{
113+ AudienceClaims: o.Providers[0].OIDCConfig.AudienceClaims,
114+ ClientID: o.Providers[0].ClientID,
115+ ExtraAudiences: o.Providers[0].OIDCConfig.ExtraAudiences,
116+ }
117+
105118 // Construct a manual IDTokenVerifier from issuer URL & JWKS URI
106119 // instead of metadata discovery if we enable -skip-oidc-discovery.
107120 // In this case we need to make sure the required endpoints for
@@ -117,21 +130,16 @@ func Validate(o *options.Options) error {
117130 msgs = append(msgs, "missing setting: oidc-jwks-url")
118131 }
119132 keySet := oidc.NewRemoteKeySet(ctx, o.Providers[0].OIDCConfig.JwksURL)
120− o.SetOIDCVerifier(oidc.NewVerifier(o.Providers[0].OIDCConfig.IssuerURL, keySet, &oidc.Config{
121− ClientID: o.Providers[0].ClientID,
122− SkipIssuerCheck: o.Providers[0].OIDCConfig.InsecureSkipIssuerVerification,
123− }))
133+ o.SetOIDCVerifier(internaloidc.NewVerifier(
134+ oidc.NewVerifier(o.Providers[0].OIDCConfig.IssuerURL, keySet, config), verificationOptions))
124135 } else {
125136 // Configure discoverable provider data.
126137 provider, err := oidc.NewProvider(ctx, o.Providers[0].OIDCConfig.IssuerURL)
127138 if err != nil {
128139 return err
129140 }
130− o.SetOIDCVerifier(provider.Verifier(&oidc.Config{
131− ClientID: o.Providers[0].ClientID,
132− SkipIssuerCheck: o.Providers[0].OIDCConfig.InsecureSkipIssuerVerification,
133− }))
134141
142+ o.SetOIDCVerifier(internaloidc.NewVerifier(provider.Verifier(config), verificationOptions))
135143 o.Providers[0].LoginURL = provider.Endpoint().AuthURL
136144 o.Providers[0].RedeemURL = provider.Endpoint().TokenURL
137145 }
@@ -153,7 +161,11 @@ func Validate(o *options.Options) error {
153161 var jwtIssuers []jwtIssuer
154162 jwtIssuers, msgs = parseJwtIssuers(o.ExtraJwtIssuers, msgs)
155163 for _, jwtIssuer := range jwtIssuers {
156− verifier, err := newVerifierFromJwtIssuer(jwtIssuer)
164+ verifier, err := newVerifierFromJwtIssuer(
165+ o.Providers[0].OIDCConfig.AudienceClaims,
166+ o.Providers[0].OIDCConfig.ExtraAudiences,
167+ jwtIssuer,
168+ )
157169 if err != nil {
158170 msgs = append(msgs, fmt.Sprintf("error building verifiers: %s", err))
159171 }
@@ -290,9 +302,14 @@ func parseProviderInfo(o *options.Options, msgs []string) []string {
290302 if err != nil {
291303 msgs = append(msgs, "failed to initialize oidc provider for gitlab.com")
292304 } else {
293− p.Verifier = provider.Verifier(&oidc.Config{
305+ verificationOptions := &internaloidc.IDTokenVerificationOptions{
306+ AudienceClaims: o.Providers[0].OIDCConfig.AudienceClaims,
307+ ClientID: o.Providers[0].ClientID,
308+ ExtraAudiences: o.Providers[0].OIDCConfig.ExtraAudiences,
309+ }
310+ p.Verifier = internaloidc.NewVerifier(provider.Verifier(&oidc.Config{
294311 ClientID: o.Providers[0].ClientID,
295− })
312+ }), verificationOptions)
296313
297314 p.LoginURL, msgs = parseURL(provider.Endpoint().AuthURL, "login", msgs)
298315 p.RedeemURL, msgs = parseURL(provider.Endpoint().TokenURL, "redeem", msgs)
@@ -372,9 +389,10 @@ func parseJwtIssuers(issuers []string, msgs []string) ([]jwtIssuer, []string) {
372389
373390// newVerifierFromJwtIssuer takes in issuer information in jwtIssuer info and returns
374391// a verifier for that issuer.
375−func newVerifierFromJwtIssuer(jwtIssuer jwtIssuer) (*oidc.IDTokenVerifier, error) {
392+func newVerifierFromJwtIssuer(audienceClaims []string, extraAudiences []string, jwtIssuer jwtIssuer) (*internaloidc.IDTokenVerifier, error) {
376393 config := &oidc.Config{
377− ClientID: jwtIssuer.audience,
394+ ClientID: jwtIssuer.audience,
395+ SkipClientIDCheck: true, // client id check is done within oauth2-proxy: IDTokenVerifier.Verify
378396 }
379397 // Try as an OpenID Connect Provider first
380398 var verifier *oidc.IDTokenVerifier
@@ -390,7 +408,13 @@ func newVerifierFromJwtIssuer(jwtIssuer jwtIssuer) (*oidc.IDTokenVerifier, error
390408 } else {
391409 verifier = provider.Verifier(config)
392410 }
393− return verifier, nil
411+ verificationOptions := &internaloidc.IDTokenVerificationOptions{
412+ AudienceClaims: audienceClaims,
413+ ClientID: jwtIssuer.audience,
414+ ExtraAudiences: extraAudiences,
415+ // ExtraAudiences: o.Providers[0].OIDCConfig.ExtraAudiences,
416+ }
417+ return internaloidc.NewVerifier(verifier, verificationOptions), nil
394418}
395419
396420// jwtIssuer hold parsed JWT issuer info that's used to construct a verifier.
providers/adfs_test.gomode 100644 → 100755+8−2
@@ -14,6 +14,7 @@ import (
1414 "github.com/coreos/go-oidc/v3/oidc"
1515 "github.com/golang-jwt/jwt"
1616 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
17+ internaloidc "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/oidc"
1718 . "github.com/onsi/ginkgo"
1819 . "github.com/onsi/ginkgo/extensions/table"
1920 . "github.com/onsi/gomega"
@@ -41,11 +42,16 @@ func newSignedTestADFSToken(tokenClaims adfsClaims) (string, error) {
4142}
4243
4344func testADFSProvider(hostname string) *ADFSProvider {
44− o := oidc.NewVerifier(
45+ verificationOptions := &internaloidc.IDTokenVerificationOptions{
46+ AudienceClaims: []string{"aud"},
47+ ClientID: "https://test.myapp.com",
48+ }
49+
50+ o := internaloidc.NewVerifier(oidc.NewVerifier(
4551 "https://issuer.example.com",
4652 fakeADFSJwks{},
4753 &oidc.Config{ClientID: "https://test.myapp.com"},
48− )
54+ ), verificationOptions)
4955
5056 p := NewADFSProvider(&ProviderData{
5157 ProviderName: "",
providers/azure_test.go+19−6
@@ -13,8 +13,11 @@ import (
1313 "testing"
1414 "time"
1515
16− "github.com/coreos/go-oidc/v3/oidc"
16+ "github.com/golang-jwt/jwt"
17+
18+ oidc "github.com/coreos/go-oidc/v3/oidc"
1719 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
20+ internaloidc "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/oidc"
1821
1922 . "github.com/onsi/gomega"
2023 "github.com/stretchr/testify/assert"
@@ -38,6 +41,10 @@ type azureOAuthPayload struct {
3841}
3942
4043func testAzureProvider(hostname string) *AzureProvider {
44+ verificationOptions := &internaloidc.IDTokenVerificationOptions{
45+ AudienceClaims: []string{"aud"},
46+ ClientID: "cd6d4fae-f6a6-4a34-8454-2c6b598e9532",
47+ }
4148 p := NewAzureProvider(
4249 &ProviderData{
4350 ProviderName: "",
@@ -48,7 +55,7 @@ func testAzureProvider(hostname string) *AzureProvider {
4855 ProtectedResource: &url.URL{},
4956 Scope: "",
5057 EmailClaim: "email",
51− Verifier: oidc.NewVerifier(
58+ Verifier: internaloidc.NewVerifier(oidc.NewVerifier(
5259 "https://issuer.example.com",
5360 fakeAzureKeySetStub{},
5461 &oidc.Config{
@@ -57,7 +64,7 @@ func testAzureProvider(hostname string) *AzureProvider {
5764 SkipIssuerCheck: true,
5865 SkipExpiryCheck: true,
5966 },
60− ),
67+ ), verificationOptions),
6168 })
6269
6370 if hostname != "" {
@@ -285,13 +292,17 @@ func TestAzureProviderRedeem(t *testing.T) {
285292 accessTokenString := ""
286293 if testCase.EmailFromIDToken != "" {
287294 var err error
288− token := idTokenClaims{Email: testCase.EmailFromIDToken}
295+ token := idTokenClaims{
296+ StandardClaims: jwt.StandardClaims{Audience: "cd6d4fae-f6a6-4a34-8454-2c6b598e9532"},
297+ Email: testCase.EmailFromIDToken}
289298 idTokenString, err = newSignedTestIDToken(token)
290299 assert.NoError(t, err)
291300 }
292301 if testCase.EmailFromAccessToken != "" {
293302 var err error
294− token := idTokenClaims{Email: testCase.EmailFromAccessToken}
303+ token := idTokenClaims{
304+ StandardClaims: jwt.StandardClaims{Audience: "cd6d4fae-f6a6-4a34-8454-2c6b598e9532"},
305+ Email: testCase.EmailFromAccessToken}
295306 accessTokenString, err = newSignedTestIDToken(token)
296307 assert.NoError(t, err)
297308 }
@@ -342,7 +353,9 @@ func TestAzureProviderProtectedResourceConfigured(t *testing.T) {
342353
343354func TestAzureProviderRefresh(t *testing.T) {
344355 email := "foo@example.com"
345− idToken := idTokenClaims{Email: email}
356+ idToken := idTokenClaims{
357+ StandardClaims: jwt.StandardClaims{Audience: "cd6d4fae-f6a6-4a34-8454-2c6b598e9532"},
358+ Email: email}
346359 idTokenString, err := newSignedTestIDToken(idToken)
347360 assert.NoError(t, err)
348361 timestamp, err := time.Parse(time.RFC3339, "3006-01-02T22:04:05Z")
providers/keycloak_oidc_test.go+13−3
@@ -12,14 +12,20 @@ import (
1212 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
1313 . "github.com/onsi/ginkgo"
1414 . "github.com/onsi/gomega"
15+
16+ internaloidc "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/oidc"
1517)
1618
1719const (
1820 accessTokenHeader = "ewogICJhbGciOiAiUlMyNTYiLAogICJ0eXAiOiAiSldUIgp9"
19− accessTokenPayload = "eyJyZWFsbV9hY2Nlc3MiOiB7InJvbGVzIjogWyJ3cml0ZSJdfSwgInJlc291cmNlX2FjY2VzcyI6IHsiZGVmYXVsdCI6IHsicm9sZXMiOiBbInJlYWQiXX19fQ"
2021 accessTokenSignature = "dyt0CoTl4WoVjAHI9Q_CwSKhl6d_9rhM3NrXuJttkao"
22+ defaultAudienceClaim = "aud"
23+ mockClientID = "cd6d4fae-f6a6-4a34-8454-2c6b598e9532"
2124)
2225
26+var accessTokenPayload = base64.StdEncoding.EncodeToString([]byte(
27+ fmt.Sprintf(`{"%s": "%s", "realm_access": {"roles": ["write"]}, "resource_access": {"default": {"roles": ["read"]}}}`, defaultAudienceClaim, mockClientID)))
28+
2329type DummyKeySet struct{}
2430
2531func (DummyKeySet) VerifySignature(_ context.Context, _ string) (payload []byte, err error) {
@@ -38,6 +44,10 @@ func newTestKeycloakOIDCSetup() (*httptest.Server, *KeycloakOIDCProvider) {
3844}
3945
4046func newKeycloakOIDCProvider(serverURL *url.URL) *KeycloakOIDCProvider {
47+ verificationOptions := &internaloidc.IDTokenVerificationOptions{
48+ AudienceClaims: []string{defaultAudienceClaim},
49+ ClientID: mockClientID,
50+ }
4151 p := NewKeycloakOIDCProvider(
4252 &ProviderData{
4353 LoginURL: &url.URL{
@@ -64,12 +74,12 @@ func newKeycloakOIDCProvider(serverURL *url.URL) *KeycloakOIDCProvider {
6474 }
6575
6676 keyset := DummyKeySet{}
67− p.Verifier = oidc.NewVerifier("", keyset, &oidc.Config{
77+ p.Verifier = internaloidc.NewVerifier(oidc.NewVerifier("", keyset, &oidc.Config{
6878 ClientID: "client",
6979 SkipIssuerCheck: true,
7080 SkipClientIDCheck: true,
7181 SkipExpiryCheck: true,
72− })
82+ }), verificationOptions)
7383 p.EmailClaim = "email"
7484 p.GroupsClaim = "groups"
7585 return p
providers/oidc_test.go+7−2
@@ -14,6 +14,7 @@ import (
1414 "github.com/coreos/go-oidc/v3/oidc"
1515 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
1616 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/encryption"
17+ internaloidc "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/oidc"
1718 "github.com/stretchr/testify/assert"
1819)
1920
@@ -26,6 +27,10 @@ type redeemTokenResponse struct {
2627}
2728
2829func newOIDCProvider(serverURL *url.URL) *OIDCProvider {
30+ verificationOptions := &internaloidc.IDTokenVerificationOptions{
31+ AudienceClaims: []string{"aud"},
32+ ClientID: "https://test.myapp.com",
33+ }
2934 providerData := &ProviderData{
3035 ProviderName: "oidc",
3136 ClientID: oidcClientID,
@@ -49,11 +54,11 @@ func newOIDCProvider(serverURL *url.URL) *OIDCProvider {
4954 Scope: "openid profile offline_access",
5055 EmailClaim: "email",
5156 GroupsClaim: "groups",
52− Verifier: oidc.NewVerifier(
57+ Verifier: internaloidc.NewVerifier(oidc.NewVerifier(
5358 oidcIssuer,
5459 mockJWKS{},
5560 &oidc.Config{ClientID: oidcClientID},
56− ),
61+ ), verificationOptions),
5762 }
5863
5964 p := NewOIDCProvider(providerData)
providers/provider_data.go+4−1
@@ -12,6 +12,7 @@ import (
1212 "github.com/coreos/go-oidc/v3/oidc"
1313 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
1414 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/logger"
15+ internaloidc "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/oidc"
1516 "golang.org/x/oauth2"
1617)
1718
@@ -20,6 +21,8 @@ const (
2021 OIDCGroupsClaim = "groups"
2122)
2223
24+var OIDCAudienceClaims = []string{"aud"}
25+
2326// ProviderData contains information required to configure all implementations
2427// of OAuth2 providers
2528type ProviderData struct {
@@ -44,7 +47,7 @@ type ProviderData struct {
4447 UserClaim string
4548 EmailClaim string
4649 GroupsClaim string
47− Verifier *oidc.IDTokenVerifier
50+ Verifier *internaloidc.IDTokenVerifier
4851
4952 // Universal Group authorization data structure
5053 // any provider can set to consume
providers/provider_data_test.go+27−9
@@ -16,6 +16,7 @@ import (
1616 "github.com/golang-jwt/jwt"
1717 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/apis/sessions"
1818 "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/encryption"
19+ internaloidc "github.com/oauth2-proxy/oauth2-proxy/v7/pkg/oidc"
1920 . "github.com/onsi/gomega"
2021 "golang.org/x/oauth2"
2122)
@@ -155,7 +156,8 @@ func TestProviderData_verifyIDToken(t *testing.T) {
155156 IDToken: &failureIDToken,
156157 Verifier: true,
157158 ExpectIDToken: false,
158− ExpectedError: errors.New("failed to verify signature: the validation failed for subject [123456789]"),
159+ ExpectedError: errors.New("failed to verify token: failed to verify signature: " +
160+ "the validation failed for subject [123456789]"),
159161 },
160162 "Missing ID Token": {
161163 IDToken: nil,
@@ -186,11 +188,15 @@ func TestProviderData_verifyIDToken(t *testing.T) {
186188
187189 provider := &ProviderData{}
188190 if tc.Verifier {
189− provider.Verifier = oidc.NewVerifier(
191+ verificationOptions := &internaloidc.IDTokenVerificationOptions{
192+ AudienceClaims: []string{"aud"},
193+ ClientID: oidcClientID,
194+ }
195+ provider.Verifier = internaloidc.NewVerifier(oidc.NewVerifier(
190196 oidcIssuer,
191197 mockJWKS{},
192198 &oidc.Config{ClientID: oidcClientID},
193− )
199+ ), verificationOptions)
194200 }
195201 verified, err := provider.verifyIDToken(context.Background(), token)
196202 if err != nil {
@@ -346,12 +352,16 @@ func TestProviderData_buildSessionFromClaims(t *testing.T) {
346352 t.Run(testName, func(t *testing.T) {
347353 g := NewWithT(t)
348354
355+ verificationOptions := &internaloidc.IDTokenVerificationOptions{
356+ AudienceClaims: []string{"aud"},
357+ ClientID: oidcClientID,
358+ }
349359 provider := &ProviderData{
350− Verifier: oidc.NewVerifier(
360+ Verifier: internaloidc.NewVerifier(oidc.NewVerifier(
351361 oidcIssuer,
352362 mockJWKS{},
353363 &oidc.Config{ClientID: oidcClientID},
354− ),
364+ ), verificationOptions),
355365 }
356366 provider.AllowUnverifiedEmail = tc.AllowUnverified
357367 provider.UserClaim = tc.UserClaim
@@ -408,12 +418,16 @@ func TestProviderData_checkNonce(t *testing.T) {
408418 t.Run(testName, func(t *testing.T) {
409419 g := NewWithT(t)
410420
421+ verificationOptions := &internaloidc.IDTokenVerificationOptions{
422+ AudienceClaims: []string{"aud"},
423+ ClientID: oidcClientID,
424+ }
411425 provider := &ProviderData{
412− Verifier: oidc.NewVerifier(
426+ Verifier: internaloidc.NewVerifier(oidc.NewVerifier(
413427 oidcIssuer,
414428 mockJWKS{},
415429 &oidc.Config{ClientID: oidcClientID},
416− ),
430+ ), verificationOptions),
417431 }
418432
419433 rawIDToken, err := newSignedTestIDToken(tc.IDToken)
@@ -501,12 +515,16 @@ func TestProviderData_extractGroups(t *testing.T) {
501515 t.Run(testName, func(t *testing.T) {
502516 g := NewWithT(t)
503517
518+ verificationOptions := &internaloidc.IDTokenVerificationOptions{
519+ AudienceClaims: []string{"aud"},
520+ ClientID: oidcClientID,
521+ }
504522 provider := &ProviderData{
505− Verifier: oidc.NewVerifier(
523+ Verifier: internaloidc.NewVerifier(oidc.NewVerifier(
506524 oidcIssuer,
507525 mockJWKS{},
508526 &oidc.Config{ClientID: oidcClientID},
509− ),
527+ ), verificationOptions),
510528 }
511529 provider.GroupsClaim = tc.GroupsClaim
512530