Rename "ExpectedAudiences" to ExpectedAudience" in ValidatorOpts.

There is a typo in ValidatorOpts, ExpectedAudiences should not have an "s" at the end. To fix this, we add an additional field "ExpectedAudience", and deprecate "ExpectedAudiences". Both are accepted, but must not be set at the same time.

PiperOrigin-RevId: 463761926
diff --git a/go/jwt/jwt_validator.go b/go/jwt/jwt_validator.go
index 3659431..9462b1b 100644
--- a/go/jwt/jwt_validator.go
+++ b/go/jwt/jwt_validator.go
@@ -29,7 +29,8 @@
 type ValidatorOpts struct {
 	ExpectedTypeHeader *string
 	ExpectedIssuer     *string
-	ExpectedAudiences  *string
+	ExpectedAudiences  *string // deprecated. Use ExpectedAudience instead.
+	ExpectedAudience   *string
 
 	IgnoreTypeHeader bool
 	IgnoreAudiences  bool
@@ -52,13 +53,20 @@
 	if opts == nil {
 		return nil, fmt.Errorf("ValidatorOpts can't be nil")
 	}
+	if opts.ExpectedAudiences != nil {
+		if opts.ExpectedAudience != nil {
+			return nil, fmt.Errorf("ExpectedAudiences and ExpectedAudience can't be set at the same time")
+		}
+		opts.ExpectedAudience = opts.ExpectedAudiences
+		opts.ExpectedAudiences = nil
+	}
 	if opts.ExpectedTypeHeader != nil && opts.IgnoreTypeHeader {
 		return nil, fmt.Errorf("ExpectedTypeHeader and IgnoreTypeHeader cannot be used together")
 	}
 	if opts.ExpectedIssuer != nil && opts.IgnoreIssuer {
 		return nil, fmt.Errorf("ExpectedIssuer and IgnoreIssuer cannot be used together")
 	}
-	if opts.ExpectedAudiences != nil && opts.IgnoreAudiences {
+	if opts.ExpectedAudience != nil && opts.IgnoreAudiences {
 		return nil, fmt.Errorf("ExpectedAudience and IgnoreAudience cannot be used together")
 	}
 	if opts.ClockSkew.Minutes() > jwtMaxClockSkewMinutes {
@@ -165,7 +173,7 @@
 }
 
 func (v *Validator) validateAudiences(rawJWT *RawJWT) error {
-	skip, err := validateFieldPresence(v.opts.IgnoreAudiences, rawJWT.HasAudiences(), v.opts.ExpectedAudiences != nil)
+	skip, err := validateFieldPresence(v.opts.IgnoreAudiences, rawJWT.HasAudiences(), v.opts.ExpectedAudience != nil)
 	if err != nil {
 		return err
 	}
@@ -177,7 +185,7 @@
 		return err
 	}
 	for i, aud := range audiences {
-		if aud == *v.opts.ExpectedAudiences {
+		if aud == *v.opts.ExpectedAudience {
 			break
 		}
 		if i == len(audiences)-1 {
diff --git a/go/jwt/jwt_validator_test.go b/go/jwt/jwt_validator_test.go
index f82e48f..bb1787e 100644
--- a/go/jwt/jwt_validator_test.go
+++ b/go/jwt/jwt_validator_test.go
@@ -46,6 +46,13 @@
 			},
 		},
 		{
+			tag: "combining ExpectedAudience and IgnoreAudiences",
+			validatorOpts: &jwt.ValidatorOpts{
+				ExpectedAudience: refString("should fail"),
+				IgnoreAudiences:  true,
+			},
+		},
+		{
 			tag: "combining ExpectedAudiences and IgnoreAudiences",
 			validatorOpts: &jwt.ValidatorOpts{
 				ExpectedAudiences: refString("should fail"),
@@ -53,6 +60,13 @@
 			},
 		},
 		{
+			tag: "both ExpectedAudience and ExpectedAudiences are set",
+			validatorOpts: &jwt.ValidatorOpts{
+				ExpectedAudience:  refString("aud"),
+				ExpectedAudiences: refString("aud"),
+			},
+		},
+		{
 			tag: "invalid clock skew",
 			validatorOpts: &jwt.ValidatorOpts{
 				ClockSkew: time.Minute * 11,
@@ -199,6 +213,16 @@
 			},
 			validatorOpts: &jwt.ValidatorOpts{
 				AllowMissingExpiration: true,
+				ExpectedAudience:       refString("tink-audience"),
+			},
+		},
+		{
+			tag: "audience required but no specified, deprecated",
+			tokenOpts: &jwt.RawJWTOptions{
+				WithoutExpiration: true,
+			},
+			validatorOpts: &jwt.ValidatorOpts{
+				AllowMissingExpiration: true,
 				ExpectedAudiences:      refString("tink-audience"),
 			},
 		},
@@ -210,6 +234,17 @@
 			},
 			validatorOpts: &jwt.ValidatorOpts{
 				AllowMissingExpiration: true,
+				ExpectedAudience:       refString("audience"),
+			},
+		},
+		{
+			tag: "invalid audience, deprecated",
+			tokenOpts: &jwt.RawJWTOptions{
+				WithoutExpiration: true,
+				Audience:          refString("tink-audience"),
+			},
+			validatorOpts: &jwt.ValidatorOpts{
+				AllowMissingExpiration: true,
 				ExpectedAudiences:      refString("audience"),
 			},
 		},
@@ -405,6 +440,17 @@
 			},
 			validatorOpts: &jwt.ValidatorOpts{
 				AllowMissingExpiration: true,
+				ExpectedAudience:       refString("audience"),
+			},
+		},
+		{
+			tag: "deprecated expected audiences",
+			tokenOpts: &jwt.RawJWTOptions{
+				WithoutExpiration: true,
+				Audience:          refString("audience"),
+			},
+			validatorOpts: &jwt.ValidatorOpts{
+				AllowMissingExpiration: true,
 				ExpectedAudiences:      refString("audience"),
 			},
 		},
diff --git a/testing/go/jwt_service.go b/testing/go/jwt_service.go
index 1eebe7a..664afa9 100644
--- a/testing/go/jwt_service.go
+++ b/testing/go/jwt_service.go
@@ -274,7 +274,7 @@
 	}
 	opts := &jwt.ValidatorOpts{
 		ExpectedTypeHeader:     refString(v.GetExpectedTypeHeader()),
-		ExpectedAudiences:      refString(v.GetExpectedAudience()),
+		ExpectedAudience:       refString(v.GetExpectedAudience()),
 		ExpectedIssuer:         refString(v.GetExpectedIssuer()),
 		ExpectIssuedInThePast:  v.GetExpectIssuedInThePast(),
 		AllowMissingExpiration: v.GetAllowMissingExpiration(),