git.sr.ht/~pingoo/stdx@v0.0.0-20240218134121-094174641f6e/jwt/jwt_test.go (about)

     1  package jwt_test
     2  
     3  import (
     4  	"errors"
     5  	"strconv"
     6  	"testing"
     7  	"time"
     8  
     9  	"git.sr.ht/~pingoo/stdx/jwt"
    10  )
    11  
    12  var (
    13  	INSECURE_SECRET = []byte("9MfG7mC+dqxXgXZGdiFsxyET1mQRBekiw7K+bIvZEGc=")
    14  )
    15  
    16  func TestVerifyInvalidTokens(t *testing.T) {
    17  	jwtProvider, _ := jwt.NewProvider(INSECURE_SECRET, jwt.AlgorithmHS256, nil)
    18  	invalidTokens := []string{
    19  		".",
    20  		"..",
    21  		"...",
    22  		"....",
    23  		"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..",
    24  		".eyJtZXNzYWdlIjoiOSJ9.",
    25  		"..pRVbZ4OC40z7qZsRj0cPpLodPmMAF7-skUqztxeK9iQ=",
    26  		"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXNzYWdlIjoiOSJ9.",
    27  		".eyJtZXNzYWdlIjoiOSJ9.pRVbZ4OC40z7qZsRj0cPpLodPmMAF7-skUqztxeK9iQ=",
    28  		"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..pRVbZ4OC40z7qZsRj0cPpLodPmMAF7-skUqztxeK9iQ=",
    29  	}
    30  
    31  	for _, invalidToken := range invalidTokens {
    32  		var decodedPayload struct{}
    33  		err := jwtProvider.VerifyToken(invalidToken, &decodedPayload)
    34  		if err == nil {
    35  			t.Errorf("The invalid token: %s is verifed as valid", invalidToken)
    36  		}
    37  	}
    38  }
    39  
    40  func TestVerifyKnownJWTs(t *testing.T) {
    41  	jwts := []struct {
    42  		Token     string
    43  		Algorithm jwt.Algorithm
    44  		Secret    []byte
    45  	}{
    46  		{
    47  			Token:     "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJtZXNzYWdlIjoiSGVsbG8gV29ybGQifQ.B3yZ_TwtqZGk1ejyUI6QcD-eqrPN0awNEy4L4CiwvL8",
    48  			Algorithm: jwt.AlgorithmHS256,
    49  			Secret:    []byte("secretsecretsecretsecretsecretsecret"),
    50  		},
    51  	}
    52  
    53  	for _, knowJwt := range jwts {
    54  		var emptyStruct struct{}
    55  		jwtProvider, _ := jwt.NewProvider(knowJwt.Secret, jwt.AlgorithmHS256, nil)
    56  		err := jwtProvider.VerifyToken(knowJwt.Token, &emptyStruct)
    57  		if err != nil {
    58  			t.Error(err)
    59  		}
    60  	}
    61  }
    62  
    63  func TestIssueAndVerify(t *testing.T) {
    64  	type claims struct {
    65  		Message string `json:"message"`
    66  	}
    67  	jwtProvider, _ := jwt.NewProvider(INSECURE_SECRET, jwt.AlgorithmHS256, nil)
    68  
    69  	for i := 0; i < 10; i += 1 {
    70  		payload := claims{Message: strconv.Itoa(i)}
    71  		token, err := jwtProvider.IssueToken(payload, nil)
    72  		if err != nil {
    73  			t.Error(err)
    74  		}
    75  
    76  		var decodedPayload claims
    77  		err = jwtProvider.VerifyToken(token, &decodedPayload)
    78  		if err != nil {
    79  			t.Error(err)
    80  		}
    81  		if decodedPayload.Message != payload.Message {
    82  			t.Errorf("payload.message (%s) != decodedPayload.message(%s)", payload.Message, decodedPayload.Message)
    83  		}
    84  	}
    85  }
    86  
    87  func TestIssueAndVerifyInvalid(t *testing.T) {
    88  	type claims struct {
    89  		Message string `json:"message"`
    90  	}
    91  	jwtProvider, _ := jwt.NewProvider(INSECURE_SECRET, jwt.AlgorithmHS256, nil)
    92  
    93  	for i := 0; i < 10; i += 1 {
    94  		payload := claims{Message: strconv.Itoa(i)}
    95  		token, err := jwtProvider.IssueToken(payload, nil)
    96  		if err != nil {
    97  			t.Error(err)
    98  		}
    99  
   100  		var decodedPayload claims
   101  
   102  		invalidTokenWithPrefix := "x" + token
   103  		err = jwtProvider.VerifyToken(invalidTokenWithPrefix, &decodedPayload)
   104  		if !errors.Is(err, jwt.ErrSignatureIsNotValid) {
   105  			t.Errorf("expected error: %s. got: %v", jwt.ErrSignatureIsNotValid, err)
   106  		}
   107  
   108  		invalidTokenWithInvalidPrefix := "|" + token
   109  		err = jwtProvider.VerifyToken(invalidTokenWithInvalidPrefix, &decodedPayload)
   110  		if !errors.Is(err, jwt.ErrSignatureIsNotValid) {
   111  			t.Errorf("expected error: %s. got: %v", jwt.ErrSignatureIsNotValid, err)
   112  		}
   113  
   114  		invalidTokenWithSuffix := token + "x"
   115  		err = jwtProvider.VerifyToken(invalidTokenWithSuffix, &decodedPayload)
   116  		if !errors.Is(err, jwt.ErrSignatureIsNotValid) {
   117  			t.Errorf("expected error: %s. got: %v", jwt.ErrSignatureIsNotValid, err)
   118  		}
   119  
   120  		invalidTokenWithInvalidSuffix := token + "|"
   121  		err = jwtProvider.VerifyToken(invalidTokenWithInvalidSuffix, &decodedPayload)
   122  		if !errors.Is(err, jwt.ErrTokenIsNotValid) {
   123  			t.Errorf("expected error: %s. got: %v", jwt.ErrTokenIsNotValid, err)
   124  		}
   125  	}
   126  }
   127  
   128  func TestIssueAndVerifyExpireIntTheFuture(t *testing.T) {
   129  	type claims struct {
   130  		Message string `json:"message"`
   131  	}
   132  	jwtProvider, _ := jwt.NewProvider(INSECURE_SECRET, jwt.AlgorithmHS256, nil)
   133  
   134  	for i := 0; i < 10; i += 1 {
   135  		payload := claims{Message: strconv.Itoa(i)}
   136  		expiresAt := time.Now().Add(1 * time.Hour)
   137  		token, err := jwtProvider.IssueToken(payload, &jwt.TokenOptions{ExpirationTime: &expiresAt})
   138  		if err != nil {
   139  			t.Error(err)
   140  		}
   141  
   142  		var decodedPayload claims
   143  		err = jwtProvider.VerifyToken(token, &decodedPayload)
   144  		if err != nil {
   145  			t.Error(err)
   146  		}
   147  		if decodedPayload.Message != payload.Message {
   148  			t.Errorf("pyaload.message (%s) != decodedPayload.message(%s)", payload.Message, decodedPayload.Message)
   149  		}
   150  	}
   151  }
   152  
   153  func TestIssueAndVerifyExpired(t *testing.T) {
   154  	type emptyClaims struct {
   155  	}
   156  	type claims struct {
   157  		Message string `json:"message"`
   158  	}
   159  	jwtProvider, _ := jwt.NewProvider(INSECURE_SECRET, jwt.AlgorithmHS256, nil)
   160  
   161  	for i := 0; i < 10; i += 1 {
   162  		expiresAt := time.Now().Add(-1 * time.Hour)
   163  		token, err := jwtProvider.IssueToken(emptyClaims{}, &jwt.TokenOptions{ExpirationTime: &expiresAt})
   164  		if err != nil {
   165  			t.Error(err)
   166  		}
   167  
   168  		var decodedPayload emptyClaims
   169  		err = jwtProvider.VerifyToken(token, &decodedPayload)
   170  		if !errors.Is(err, jwt.ErrTokenHasExpired) {
   171  			t.Errorf("expected error: %s. got: %v", jwt.ErrTokenHasExpired, err)
   172  		}
   173  	}
   174  
   175  	for i := 0; i < 10; i += 1 {
   176  		payload := claims{Message: strconv.Itoa(i)}
   177  		expiresAt := time.Now().Add(-1 * time.Hour)
   178  		token, err := jwtProvider.IssueToken(payload, &jwt.TokenOptions{ExpirationTime: &expiresAt})
   179  		if err != nil {
   180  			t.Error(err)
   181  		}
   182  
   183  		var decodedPayload claims
   184  		err = jwtProvider.VerifyToken(token, &decodedPayload)
   185  		if !errors.Is(err, jwt.ErrTokenHasExpired) {
   186  			t.Errorf("expected error: %s. got: %v", jwt.ErrTokenHasExpired, err)
   187  		}
   188  	}
   189  }