// Copyright 2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
///////////////////////////////////////////////////////////////////////////////

package services_test

import (
	"context"
	"errors"
	"fmt"
	"testing"

	dpb "google.golang.org/protobuf/types/known/durationpb"
	spb "google.golang.org/protobuf/types/known/structpb"
	tpb "google.golang.org/protobuf/types/known/timestamppb"
	wpb "google.golang.org/protobuf/types/known/wrapperspb"
	"github.com/google/go-cmp/cmp"
	"google.golang.org/protobuf/proto"
	"google.golang.org/protobuf/testing/protocmp"
	"github.com/google/tink/go/aead"
	"github.com/google/tink/go/jwt"
	"github.com/google/tink/go/signature"
	"github.com/google/tink/testing/go/services"
	pb "github.com/google/tink/testing/go/protos/testing_api_go_grpc"
)

func verifiedJWTFromResponse(response *pb.JwtVerifyResponse) (*pb.JwtToken, error) {
	switch r := response.Result.(type) {
	case *pb.JwtVerifyResponse_VerifiedJwt:
		return r.VerifiedJwt, nil
	case *pb.JwtVerifyResponse_Err:
		return nil, errors.New(r.Err)
	default:
		return nil, fmt.Errorf("response.Result has unexpected type %T", r)
	}
}

func signedCompactJWTFromResponse(response *pb.JwtSignResponse) (string, error) {
	switch r := response.Result.(type) {
	case *pb.JwtSignResponse_SignedCompactJwt:
		return r.SignedCompactJwt, nil
	case *pb.JwtSignResponse_Err:
		return "", errors.New(r.Err)
	default:
		return "", fmt.Errorf("response.Result has unexpected type %T", r)
	}
}

func jwkSetFromResponse(response *pb.JwtToJwkSetResponse) (string, error) {
	switch r := response.Result.(type) {
	case *pb.JwtToJwkSetResponse_JwkSet:
		return r.JwkSet, nil
	case *pb.JwtToJwkSetResponse_Err:
		return "", errors.New(r.Err)
	default:
		return "", fmt.Errorf("response.Result has unexpected type %T", r)
	}
}

func keysetFromResponse(response *pb.JwtFromJwkSetResponse) ([]byte, error) {
	switch r := response.Result.(type) {
	case *pb.JwtFromJwkSetResponse_Keyset:
		return r.Keyset, nil
	case *pb.JwtFromJwkSetResponse_Err:
		return nil, errors.New(r.Err)
	default:
		return nil, fmt.Errorf("response.Result has unexpected type %T", r)
	}
}

type jwtTestCase struct {
	tag       string
	rawJWT    *pb.JwtToken
	validator *pb.JwtValidator
}

func TestJWTComputeInvalidJWT(t *testing.T) {
	for _, tc := range []jwtTestCase{
		{
			tag:    "nil rawJWT",
			rawJWT: nil,
		},
		{
			tag: "invalid json array string",
			rawJWT: &pb.JwtToken{
				CustomClaims: map[string]*pb.JwtClaimValue{
					"cc-array": &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_JsonArrayValue{JsonArrayValue: "{35}"}},
				},
			},
		},
		{
			tag: "invalid json object string",
			rawJWT: &pb.JwtToken{
				CustomClaims: map[string]*pb.JwtClaimValue{
					"cc-object": &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_JsonObjectValue{JsonObjectValue: `["o":"a"]`}},
				},
			},
		},
	} {
		t.Run(tc.tag, func(t *testing.T) {
			keysetService := &services.KeysetService{}
			jwtService := &services.JWTService{}
			ctx := context.Background()
			template, err := proto.Marshal(jwt.HS256Template())
			if err != nil {
				t.Fatalf("proto.Marshal(jwt.HS256Template()) failed: %v", err)
			}
			keyset, err := genKeyset(ctx, keysetService, template)
			if err != nil {
				t.Fatalf("genKeyset failed: %v", err)
			}
			signResponse, err := jwtService.ComputeMacAndEncode(ctx, &pb.JwtSignRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: keyset}, RawJwt: tc.rawJWT})
			if err != nil {
				t.Fatalf("jwtService.ComputeMacAndEncode() err = %v, want nil", err)
			}
			if _, err := signedCompactJWTFromResponse(signResponse); err == nil {
				t.Fatalf("JwtSignResponse: error = nil, want error")
			}
		})
	}
}

func TestSuccessfulJwtMacCreation(t *testing.T) {
	keysetService := &services.KeysetService{}
	jwtService := &services.JWTService{}
	ctx := context.Background()

	template, err := proto.Marshal(jwt.HS256Template())
	if err != nil {
		t.Fatalf("proto.Marshal(jwt.HS256Template()) failed: %v, want nil", err)
	}

	keyset, err := genKeyset(ctx, keysetService, template)
	if err != nil {
		t.Fatalf("genKeyset failed: %v", err)
	}

	result, err := jwtService.CreateJwtMac(ctx, &pb.CreationRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: keyset}})
	if err != nil {
		t.Fatalf("CreateJwtMac with good keyset failed with gRPC error: %v, want nil", err)
	}
	if result.GetErr() != "" {
		t.Fatalf("CreateJwtMac with good keyset failed with result.GetErr() = %q, want empty string", result.GetErr())
	}
}

func TestFailingJwtMacCreation(t *testing.T) {
	keysetService := &services.KeysetService{}
	jwtService := &services.JWTService{}
	ctx := context.Background()

	// We use signature keys -- then we cannot create a JwtMac
	template, err := proto.Marshal(aead.AES128GCMKeyTemplate())
	if err != nil {
		t.Fatalf("proto.Marshal(signature.ECDSAP256KeyTemplate()) failed: %v", err)
	}

	badKeyset, err := genKeyset(ctx, keysetService, template)
	if err != nil {
		t.Fatalf("genKeyset failed: %v", err)
	}

	result, err := jwtService.CreateJwtMac(ctx, &pb.CreationRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: badKeyset}})
	if err != nil {
		t.Fatalf("CreateJwtMac with bad keyset failed with gRPC error: %v", err)
	}
	if result.GetErr() == "" {
		t.Fatalf("result.GetErr() of bad keyset after CreateJwtMac is empty, want not empty")
	}
}

func TestJWTComputeMACWithInvalidKeysetFails(t *testing.T) {
	keysetService := &services.KeysetService{}
	jwtService := &services.JWTService{}
	ctx := context.Background()
	template, err := proto.Marshal(aead.AES256GCMKeyTemplate())
	if err != nil {
		t.Fatalf("proto.Marshal(jwt.AES256GCMKeyTemplate()) failed: %v", err)
	}
	keyset, err := genKeyset(ctx, keysetService, template)
	if err != nil {
		t.Fatalf("genKeyset failed: %v", err)
	}
	rawJWT := &pb.JwtToken{
		TypeHeader: &wpb.StringValue{Value: "JWT"},
		Issuer:     &wpb.StringValue{Value: "issuer"},
	}
	signResponse, err := jwtService.ComputeMacAndEncode(ctx, &pb.JwtSignRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: keyset}, RawJwt: rawJWT})
	if err != nil {
		t.Fatalf("jwtService.ComputeMacAndEncode() err = %v, want nil", err)
	}
	if _, err := signedCompactJWTFromResponse(signResponse); err == nil {
		t.Fatalf("JwtSignResponse: error = nil, want error")
	}
}

func TestJWTComputeAndVerifyMac(t *testing.T) {
	for _, tc := range []jwtTestCase{
		{
			tag: "all claims and custom claims",
			rawJWT: &pb.JwtToken{
				TypeHeader: &wpb.StringValue{Value: "JWT"},
				Issuer:     &wpb.StringValue{Value: "issuer"},
				Subject:    &wpb.StringValue{Value: "subject"},
				JwtId:      &wpb.StringValue{Value: "tink"},
				Audiences:  []string{"audience"},
				Expiration: &tpb.Timestamp{Seconds: 123456},
				NotBefore:  &tpb.Timestamp{Seconds: 12345},
				IssuedAt:   &tpb.Timestamp{Seconds: 1234},
				CustomClaims: map[string]*pb.JwtClaimValue{
					"cc-null":   &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_NullValue{}},
					"cc-num":    &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_NumberValue{NumberValue: 5.67}},
					"cc-bool":   &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_BoolValue{BoolValue: true}},
					"cc-string": &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_StringValue{StringValue: "foo bar"}},
					"cc-array":  &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_JsonArrayValue{JsonArrayValue: "[35]"}},
					"cc-object": &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_JsonObjectValue{JsonObjectValue: `{"key":"val"}`}},
				},
			},
			validator: &pb.JwtValidator{
				ExpectedTypeHeader: &wpb.StringValue{Value: "JWT"},
				ExpectedIssuer:     &wpb.StringValue{Value: "issuer"},
				ExpectedAudience:   &wpb.StringValue{Value: "audience"},
				Now:                &tpb.Timestamp{Seconds: 12345},
				ClockSkew:          &dpb.Duration{Seconds: 0},
			},
		},
		{
			tag: "without custom claims",
			rawJWT: &pb.JwtToken{
				TypeHeader: &wpb.StringValue{Value: "JWT"},
				Issuer:     &wpb.StringValue{Value: "issuer"},
				Subject:    &wpb.StringValue{Value: "subject"},
				Audiences:  []string{"audience"},
			},
			validator: &pb.JwtValidator{
				ExpectedTypeHeader:     &wpb.StringValue{Value: "JWT"},
				ExpectedIssuer:         &wpb.StringValue{Value: "issuer"},
				ExpectedAudience:       &wpb.StringValue{Value: "audience"},
				AllowMissingExpiration: true,
			},
		},
		{
			tag: "without expiration",
			rawJWT: &pb.JwtToken{
				Subject: &wpb.StringValue{Value: "subject"},
			},
			validator: &pb.JwtValidator{
				AllowMissingExpiration: true,
			},
		},
		{
			tag: "clock skew",
			rawJWT: &pb.JwtToken{
				Expiration: &tpb.Timestamp{Seconds: 1234},
			},
			validator: &pb.JwtValidator{
				Now:       &tpb.Timestamp{Seconds: 1235},
				ClockSkew: &dpb.Duration{Seconds: 2},
			},
		},
	} {
		t.Run(tc.tag, func(t *testing.T) {
			keysetService := &services.KeysetService{}
			jwtService := &services.JWTService{}
			ctx := context.Background()
			template, err := proto.Marshal(jwt.HS256Template())
			if err != nil {
				t.Fatalf("proto.Marshal(jwt.HS256Template()) failed: %v", err)
			}
			keyset, err := genKeyset(ctx, keysetService, template)
			if err != nil {
				t.Fatalf("genKeyset failed: %v", err)
			}

			signResponse, err := jwtService.ComputeMacAndEncode(ctx, &pb.JwtSignRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: keyset}, RawJwt: tc.rawJWT})
			if err != nil {
				t.Fatalf("jwtService.ComputeMacAndEncode() err = %v, want nil", err)
			}
			compact, err := signedCompactJWTFromResponse(signResponse)
			if err != nil {
				t.Fatalf("JwtSignResponse_Err: %v", err)
			}
			verifyResponse, err := jwtService.VerifyMacAndDecode(ctx, &pb.JwtVerifyRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: keyset}, SignedCompactJwt: compact, Validator: tc.validator})
			if err != nil {
				t.Fatalf("jwtService.VerifyMacAndDecode() err = %v, want nil", err)
			}
			verifiedJWT, err := verifiedJWTFromResponse(verifyResponse)
			if err != nil {
				t.Fatalf("JwtVerifyResponse_Err: %v", err)
			}
			if !cmp.Equal(verifiedJWT, tc.rawJWT, protocmp.Transform()) {
				t.Errorf("verifiedJWT doesn't match expected value: (+ got, - want) %v", cmp.Diff(verifiedJWT, tc.rawJWT, protocmp.Transform()))
			}
		})
	}
}

func TestJWTVerifyMACFailures(t *testing.T) {
	keysetService := &services.KeysetService{}
	jwtService := &services.JWTService{}
	ctx := context.Background()
	template, err := proto.Marshal(jwt.HS256Template())
	if err != nil {
		t.Fatalf("proto.Marshal(jwt.HS256Template()) failed: %v", err)
	}
	keyset, err := genKeyset(ctx, keysetService, template)
	if err != nil {
		t.Fatalf("genKeyset failed: %v", err)
	}
	rawJWT := &pb.JwtToken{
		TypeHeader: &wpb.StringValue{Value: "JWT"},
		Expiration: &tpb.Timestamp{Seconds: 123456},
		NotBefore:  &tpb.Timestamp{Seconds: 12345},
		IssuedAt:   &tpb.Timestamp{Seconds: 1234},
	}
	signResponse, err := jwtService.ComputeMacAndEncode(ctx, &pb.JwtSignRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: keyset}, RawJwt: rawJWT})
	if err != nil {
		t.Fatalf("jwtService.ComputeMacAndEncode() err = %v, want nil", err)
	}
	compact, err := signedCompactJWTFromResponse(signResponse)
	if err != nil {
		t.Fatalf("JwtSignResponse_Err: %v", err)
	}
	validator := &pb.JwtValidator{
		ExpectedTypeHeader: &wpb.StringValue{Value: "JWT"},
		Now:                &tpb.Timestamp{Seconds: 12345},
	}
	verifyResponse, err := jwtService.VerifyMacAndDecode(ctx, &pb.JwtVerifyRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: keyset}, SignedCompactJwt: compact, Validator: validator})
	if err != nil {
		t.Fatalf("jwtService.VerifyMacAndDecode() err = %v, want nil", err)
	}
	if _, err := verifiedJWTFromResponse(verifyResponse); err != nil {
		t.Fatalf("JwtVerifyResponse_Err: %v", err)
	}
	for _, tc := range []jwtTestCase{
		{
			tag: "unexpected type header",
			validator: &pb.JwtValidator{
				ExpectedTypeHeader: &wpb.StringValue{Value: "unexpected"},
				Now:                &tpb.Timestamp{Seconds: 12345},
			},
		},
		{
			tag: "expired token",
			validator: &pb.JwtValidator{
				ExpectedTypeHeader: &wpb.StringValue{Value: "JWT"},
				Now:                &tpb.Timestamp{Seconds: 999999999999},
			},
		},
		{
			tag: "expect issued in the past",
			validator: &pb.JwtValidator{
				ExpectedTypeHeader:    &wpb.StringValue{Value: "JWT"},
				Now:                   &tpb.Timestamp{Seconds: 1233},
				ExpectIssuedInThePast: true,
			},
		},
	} {
		t.Run(tc.tag, func(t *testing.T) {
			verifyResponse, err := jwtService.VerifyMacAndDecode(ctx, &pb.JwtVerifyRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: keyset}, SignedCompactJwt: compact, Validator: tc.validator})
			if err != nil {
				t.Fatalf("jwtService.VerifyMacAndDecode() err = %v, want nil", err)
			}
			if _, err := verifiedJWTFromResponse(verifyResponse); err == nil {
				t.Fatalf("JwtVerifyResponse_Err: nil, want error")
			}
		})
	}
}

func TestSuccessfulJwtSignVerifyCreation(t *testing.T) {
	keysetService := &services.KeysetService{}
	jwtService := &services.JWTService{}
	ctx := context.Background()

	template, err := proto.Marshal(jwt.ES256Template())
	if err != nil {
		t.Fatalf("proto.Marshal(hybrid.ES256Template()) failed: %v", err)
	}

	privateKeyset, err := genKeyset(ctx, keysetService, template)
	if err != nil {
		t.Fatalf("genKeyset failed: %v", err)
	}

	result, err := jwtService.CreateJwtPublicKeySign(ctx, &pb.CreationRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: privateKeyset}})
	if err != nil {
		t.Fatalf("CreateJwtPublicKeySign with good keyset failed with gRPC error: %v, want nil", err)
	}
	if result.GetErr() != "" {
		t.Fatalf("CreateJwtPublicKeySign with good keyset failed with result.GetErr() = %q, want empty string", result.GetErr())
	}
}

func TestSuccessfulJwtVerifyCreation(t *testing.T) {
	keysetService := &services.KeysetService{}
	jwtService := &services.JWTService{}
	ctx := context.Background()

	template, err := proto.Marshal(jwt.ES256Template())
	if err != nil {
		t.Fatalf("proto.Marshal(hybrid.ES256Template()) failed: %v", err)
	}

	privateKeyset, err := genKeyset(ctx, keysetService, template)
	if err != nil {
		t.Fatalf("genKeyset failed: %v", err)
	}
	publicKeyset, err := pubKeyset(ctx, keysetService, privateKeyset)
	if err != nil {
		t.Fatalf("pubKeyset failed: %v", err)
	}

	result, err := jwtService.CreateJwtPublicKeyVerify(ctx, &pb.CreationRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: publicKeyset}})
	if err != nil {
		t.Fatalf("CreateJwtPublicKeyVerify with good keyset failed with gRPC error: %v", err)
	}
	if result.GetErr() != "" {
		t.Fatalf("CreateJwtPublicKeyVerify with good keyset failed with result.GetErr() = %q, want empty string", result.GetErr())
	}
}

func TestFailingJwtSignCreation(t *testing.T) {
	keysetService := &services.KeysetService{}
	jwtService := &services.JWTService{}
	ctx := context.Background()

	// We use signature keys -- then we cannot create a hybrid encrypt
	template, err := proto.Marshal(signature.ECDSAP256KeyTemplate())
	if err != nil {
		t.Fatalf("proto.Marshal(signature.ECDSAP256KeyTemplate()) failed: %v", err)
	}

	privateKeyset, err := genKeyset(ctx, keysetService, template)
	if err != nil {
		t.Fatalf("genKeyset failed: %v", err)
	}

	result, err := jwtService.CreateJwtPublicKeySign(ctx, &pb.CreationRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: privateKeyset}})
	if err != nil {
		t.Fatalf("CreateJwtPublicKeySign with bad keyset failed with gRPC error: %v", err)
	}
	if result.GetErr() == "" {
		t.Fatalf("CreateJwtPublicKeySign with bad keyset succeeded")
	}
}

func TestFailingJwtVerifyCreation(t *testing.T) {
	keysetService := &services.KeysetService{}
	jwtService := &services.JWTService{}
	ctx := context.Background()

	// We use signature keys -- then we cannot create a hybrid encrypt
	template, err := proto.Marshal(signature.ECDSAP256KeyTemplate())
	if err != nil {
		t.Fatalf("proto.Marshal(signature.ECDSAP256KeyTemplate()) failed: %v", err)
	}

	privateKeyset, err := genKeyset(ctx, keysetService, template)
	if err != nil {
		t.Fatalf("genKeyset failed: %v", err)
	}
	publicKeyset, err := pubKeyset(ctx, keysetService, privateKeyset)
	if err != nil {
		t.Fatalf("pubKeyset failed: %v", err)
	}

	result, err := jwtService.CreateJwtPublicKeyVerify(ctx, &pb.CreationRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: publicKeyset}})
	if err != nil {
		t.Fatalf("CreateJwtPublicKeyVerify with good keyset failed with gRPC error: %v", err)
	}
	if result.GetErr() == "" {
		t.Fatalf("CreateJwtPublicKeyVerify with bad keyset succeeded")
	}
}

func TestJWTPublicKeySignWithInvalidKeysetFails(t *testing.T) {
	keysetService := &services.KeysetService{}
	jwtService := &services.JWTService{}

	ctx := context.Background()
	template, err := proto.Marshal(aead.AES256GCMKeyTemplate())
	if err != nil {
		t.Fatalf("proto.Marshal(aead.AES256GCMKeyTemplate()) failed: %v", err)
	}
	privateKeyset, err := genKeyset(ctx, keysetService, template)
	if err != nil {
		t.Fatalf("genKeyset failed: %v", err)
	}
	rawJWT := &pb.JwtToken{
		Subject: &wpb.StringValue{Value: "tink-subject"},
	}
	signResponse, err := jwtService.PublicKeySignAndEncode(ctx, &pb.JwtSignRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: privateKeyset}, RawJwt: rawJWT})
	if err != nil {
		t.Fatalf("jwtService.PublicKeySignAndEncode() err = %v", err)
	}
	if _, err := signedCompactJWTFromResponse(signResponse); err == nil {
		t.Fatalf("JwtSignResponse_Err: nil want error")
	}
}

func TestJWTPublicKeySignInvalidTokenFails(t *testing.T) {
	keysetService := &services.KeysetService{}
	jwtService := &services.JWTService{}

	ctx := context.Background()
	template, err := proto.Marshal(jwt.ES256Template())
	if err != nil {
		t.Fatalf("proto.Marshal(jwt.ES256Template()) failed: %v", err)
	}
	privateKeyset, err := genKeyset(ctx, keysetService, template)
	if err != nil {
		t.Fatalf("genKeyset failed: %v", err)
	}
	for _, tc := range []jwtTestCase{
		{
			tag:    "nil rawJWT",
			rawJWT: nil,
		},
		{
			tag: "invalid json array string",
			rawJWT: &pb.JwtToken{
				CustomClaims: map[string]*pb.JwtClaimValue{
					"cc-array": &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_JsonArrayValue{JsonArrayValue: "{35}"}},
				},
			},
		},
		{
			tag: "invalid json object string",
			rawJWT: &pb.JwtToken{
				CustomClaims: map[string]*pb.JwtClaimValue{
					"cc-object": &pb.JwtClaimValue{Kind: &pb.JwtClaimValue_JsonObjectValue{JsonObjectValue: `["o":"a"]`}},
				},
			},
		},
	} {
		t.Run(tc.tag, func(t *testing.T) {
			signResponse, err := jwtService.PublicKeySignAndEncode(ctx, &pb.JwtSignRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: privateKeyset}, RawJwt: tc.rawJWT})
			if err != nil {
				t.Fatalf("jwtService.PublicKeySignAndEncode() err = %v", err)
			}
			if _, err := signedCompactJWTFromResponse(signResponse); err == nil {
				t.Fatalf("JwtSignResponse_Err: nil want error")
			}
		})
	}
}

func TestJWTPublicKeyVerifyFails(t *testing.T) {
	keysetService := &services.KeysetService{}
	jwtService := &services.JWTService{}

	ctx := context.Background()
	template, err := proto.Marshal(jwt.ES256Template())
	if err != nil {
		t.Fatalf("proto.Marshal(jwt.ES256Template()) failed: %v", err)
	}
	privateKeyset, err := genKeyset(ctx, keysetService, template)
	if err != nil {
		t.Fatalf("genKeyset failed: %v", err)
	}
	publicKeyset, err := pubKeyset(ctx, keysetService, privateKeyset)
	if err != nil {
		t.Fatalf("pubKeyset failed: %v", err)
	}
	rawJWT := &pb.JwtToken{
		Subject: &wpb.StringValue{Value: "tink-subject"},
	}
	signResponse, err := jwtService.PublicKeySignAndEncode(ctx, &pb.JwtSignRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: privateKeyset}, RawJwt: rawJWT})
	if err != nil {
		t.Fatalf("jwtService.PublicKeySignAndEncode() err = %v", err)
	}
	compact, err := signedCompactJWTFromResponse(signResponse)
	if err != nil {
		t.Fatalf("JwtSignResponse_Err failed: %v", err)
	}
	validator := &pb.JwtValidator{
		ExpectedTypeHeader: &wpb.StringValue{Value: "JWT"},
	}
	verifyResponse, err := jwtService.PublicKeyVerifyAndDecode(ctx, &pb.JwtVerifyRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: publicKeyset}, SignedCompactJwt: compact, Validator: validator})
	if err != nil {
		t.Fatalf("jwtVerifySignature failed: %v", err)
	}
	if _, err := verifiedJWTFromResponse(verifyResponse); err == nil {
		t.Fatalf("JwtVerifyResponse_Err: nil want error")
	}
}

func TestJWTPublicKeySignAndEncodeVerifyAndDecode(t *testing.T) {
	keysetService := &services.KeysetService{}
	jwtService := &services.JWTService{}

	ctx := context.Background()
	template, err := proto.Marshal(jwt.ES256Template())
	if err != nil {
		t.Fatalf("proto.Marshal(jwt.ES256Template()) failed: %v", err)
	}
	privateKeyset, err := genKeyset(ctx, keysetService, template)
	if err != nil {
		t.Fatalf("genKeyset failed: %v", err)
	}
	publicKeyset, err := pubKeyset(ctx, keysetService, privateKeyset)
	if err != nil {
		t.Fatalf("pubKeyset failed: %v", err)
	}
	rawJWT := &pb.JwtToken{
		Subject: &wpb.StringValue{Value: "tink-subject"},
	}
	signResponse, err := jwtService.PublicKeySignAndEncode(ctx, &pb.JwtSignRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: privateKeyset}, RawJwt: rawJWT})
	if err != nil {
		t.Fatalf("jwtService.PublicKeySignAndEncode() err = %v", err)
	}
	compact, err := signedCompactJWTFromResponse(signResponse)
	if err != nil {
		t.Fatalf("JwtSignResponse_Err failed: %v", err)
	}
	validator := &pb.JwtValidator{
		AllowMissingExpiration: true,
	}
	verifyResponse, err := jwtService.PublicKeyVerifyAndDecode(ctx, &pb.JwtVerifyRequest{AnnotatedKeyset: &pb.AnnotatedKeyset{SerializedKeyset: publicKeyset}, SignedCompactJwt: compact, Validator: validator})
	if err != nil {
		t.Fatalf("jwtVerifySignature failed: %v", err)
	}
	verifiedJWT, err := verifiedJWTFromResponse(verifyResponse)
	if err != nil {
		t.Fatalf("JwtVerifyResponse_Err: %v", err)
	}
	if !cmp.Equal(verifiedJWT, rawJWT, protocmp.Transform()) {
		t.Errorf("verifiedJWT doesn't match expected value: (+ got, - want) %v", cmp.Diff(verifiedJWT, rawJWT, protocmp.Transform()))
	}
}

func TestToJwkSetWithPrivateKeyFails(t *testing.T) {
	keysetService := &services.KeysetService{}
	jwtService := &services.JWTService{}

	ctx := context.Background()
	template, err := proto.Marshal(jwt.ES256Template())
	if err != nil {
		t.Fatalf("proto.Marshal(jwt.ES256Template()) failed: %v", err)
	}
	privateKeyset, err := genKeyset(ctx, keysetService, template)
	if err != nil {
		t.Fatalf("genKeyset failed: %v", err)
	}
	toJWKResponse, err := jwtService.ToJwkSet(ctx, &pb.JwtToJwkSetRequest{Keyset: privateKeyset})
	if err != nil {
		t.Fatalf("jwtService.ToJwkSet() err = %v, want nil", err)
	}
	if _, err := jwkSetFromResponse(toJWKResponse); err == nil {
		t.Fatalf("JwtToJwkSetResponse_Err: = nil, want error")
	}
}

func TestFromJwkSetPrivateKeyFails(t *testing.T) {
	jwtService := &services.JWTService{}
	ctx := context.Background()
	jwkES256PublicKey := `{
	  "keys":[{
	  "kty":"EC",
	  "crv":"P-256",
	  "x":"wO6uIxh8SkKOO8VjZXNRTteRcwCPE4_4JElKyaa0fcQ",
	  "y":"7oRiYhnmkP6nqrdXWgtsWUWq5uFRLJkhyVFiWPRB278",
		"d":"8oRinhnmkYjkqrdXWgtsWUWq5uFRLJkhyVFiWPRB278",
	  "use":"sig","alg":"ES256","key_ops":["verify"],
	  "kid":"EhuduQ"}]
	}`
	fromJWKResponse, err := jwtService.FromJwkSet(ctx, &pb.JwtFromJwkSetRequest{JwkSet: jwkES256PublicKey})
	if err != nil {
		t.Fatalf("jwtService.FromJwkSet() err = %v, want nil", err)
	}
	if _, err := keysetFromResponse(fromJWKResponse); err == nil {
		t.Fatalf("JwtFromJwkSetResponse_Err = nil, want error")
	}
}

func TestFromJwkToJwkSet(t *testing.T) {
	jwtService := &services.JWTService{}
	ctx := context.Background()
	jwkES256PublicKey := `{
	  "keys":[{
	  "kty":"EC",
	  "crv":"P-256",
	  "x":"wO6uIxh8SkKOO8VjZXNRTteRcwCPE4_4JElKyaa0fcQ",
	  "y":"7oRiYhnmkP6nqrdXWgtsWUWq5uFRLJkhyVFiWPRB278",
	  "use":"sig","alg":"ES256","key_ops":["verify"],
	  "kid":"EhuduQ"}]
	}`
	fromJWKResponse, err := jwtService.FromJwkSet(ctx, &pb.JwtFromJwkSetRequest{JwkSet: jwkES256PublicKey})
	if err != nil {
		t.Fatalf("jwtService.FromJwkSet() err = %v, want nil", err)
	}
	ks, err := keysetFromResponse(fromJWKResponse)
	if err != nil {
		t.Fatalf("JwtFromJwkSetResponse_Err: = %v, want nil", err)
	}
	toJWKResponse, err := jwtService.ToJwkSet(ctx, &pb.JwtToJwkSetRequest{Keyset: ks})
	if err != nil {
		t.Fatalf("jwtService.ToJwkSet() err = %v, want nil", err)
	}
	jwkSet, err := jwkSetFromResponse(toJWKResponse)
	if err != nil {
		t.Fatalf("JwtToJwkSetResponse_Err: = %v, want nil", err)
	}
	got := &spb.Struct{}
	if err := got.UnmarshalJSON([]byte(jwkSet)); err != nil {
		t.Fatalf("got.UnmarshalJSON() err = %v, want nil", err)
	}
	want := &spb.Struct{}
	if err := want.UnmarshalJSON([]byte(jwkES256PublicKey)); err != nil {
		t.Fatalf("want.UnmarshalJSON() err = %v, want nil", err)
	}
	if !cmp.Equal(want, got, protocmp.Transform()) {
		t.Errorf("mismatch in jwk sets: diff (-want,+got): %v", cmp.Diff(want, got, protocmp.Transform()))
	}
}
