Repository: golang-jwt/jwt

Issue:
Token.New example is for the wrong func
The example for Token.New() actually demonstrates Token.NewWithClaims(). It should be demonstrating Token.New().

It additionally demonstrates signing, which I guess is ok but it seems out of scope, given that the signing example can just be part of the documentation for that method ...

Discussion:
@oxisto: > The example for Token.New() actually demonstrates Token.NewWithClaims(). It should be demonstrating Token.New().
> 
> It additionally demonstrates signing, which I guess is ok but it seems out of scope, given that the signing example can just be part of the documentation for that method ...

Which example are you exactly referring to? The ones in `example_test.go` use NewWithClaims, but are also named in this way.@notrobpike: https://github.com/golang-jwt/jwt/blob/v5.0.0/hmac_example_test.go#L26

which generates https://pkg.go.dev/github.com/golang-jwt/jwt/v5#New

Solution patch:
diff --git a/.github/spell-check.toml b/.github/spell-check.toml
new file mode 100644
index 0000000..163ef50
--- /dev/null
+++ b/.github/spell-check.toml
@@ -0,0 +1,21 @@
+[default]
+extend-ignore-re = [
+    # Ignore JWT/JWE tokens
+    "\\beyJ[\\dA-Za-z=_-]+(?:\\.[\\dA-Za-z=_-]{3,}){1,4}",
+]
+
+[default.extend-identifiers]
+# Common registered claim abbreviations
+alg = "alg"
+typ = "typ"
+iss = "iss"
+sub = "sub"
+aud = "aud"
+exp = "exp"
+nbf = "nbf"
+iat = "iat"
+jti = "jti"
+cty = "cty"
+
+# Custom exceptions (i.e. Github Usernames, proper nouns etc)
+thaJeztah = "thaJeztah"
\ No newline at end of file
diff --git a/.github/workflows/spell-check.yml b/.github/workflows/spell-check.yml
new file mode 100644
index 0000000..2ae75fd
--- /dev/null
+++ b/.github/workflows/spell-check.yml
@@ -0,0 +1,25 @@
+name: spelling
+
+permissions:
+  contents: read
+
+on:
+  push:
+    branches:
+      - main
+  pull_request:
+
+env:
+  CLICOLOR: 1
+
+jobs:
+  spelling:
+    name: Spell Check with Typos
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout Actions Repository
+        uses: actions/checkout@v4
+      - name: Spell Check Repo
+        uses: crate-ci/typos@v1.34.0
+        with:
+          config: ./.github/spell-check.toml
diff --git a/VERSION_HISTORY.md b/VERSION_HISTORY.md
index b5039e4..e39ca8e 100644
--- a/VERSION_HISTORY.md
+++ b/VERSION_HISTORY.md
@@ -97,7 +97,7 @@ Backwards compatible API change that was missed in 2.0.0.
 
 There were two major reasons for breaking backwards compatibility with this update.  The first was a refactor required to expand the width of the RSA and HMAC-SHA signing implementations.  There will likely be no required code changes to support this change.
 
-The second update, while unfortunately requiring a small change in integration, is required to open up this library to other signing methods.  Not all keys used for all signing methods have a single standard on-disk representation.  Requiring `[]byte` as the type for all keys proved too limiting.  Additionally, this implementation allows for pre-parsed tokens to be reused, which might matter in an application that parses a high volume of tokens with a small set of keys.  Backwards compatibilty has been maintained for passing `[]byte` to the RSA signing methods, but they will also accept `*rsa.PublicKey` and `*rsa.PrivateKey`.
+The second update, while unfortunately requiring a small change in integration, is required to open up this library to other signing methods.  Not all keys used for all signing methods have a single standard on-disk representation.  Requiring `[]byte` as the type for all keys proved too limiting.  Additionally, this implementation allows for pre-parsed tokens to be reused, which might matter in an application that parses a high volume of tokens with a small set of keys.  Backwards compatibility has been maintained for passing `[]byte` to the RSA signing methods, but they will also accept `*rsa.PublicKey` and `*rsa.PrivateKey`.
 
 It is likely the only integration change required here will be to change `func(t *jwt.Token) ([]byte, error)` to `func(t *jwt.Token) (interface{}, error)` when calling `Parse`.
 
diff --git a/parser.go b/parser.go
index 054c7eb..e47679e 100644
--- a/parser.go
+++ b/parser.go
@@ -216,7 +216,7 @@ func splitToken(token string) ([]string, bool) {
 	parts[1] = claims
 	// One more cut to ensure the signature is the last part of the token and there are no more
 	// delimiters. This avoids an issue where malicious input could contain additional delimiters
-	// causing unecessary overhead parsing tokens.
+	// causing unnecessary overhead parsing tokens.
 	signature, _, unexpected := strings.Cut(remain, tokenDelimiter)
 	if unexpected {
 		return nil, false
diff --git a/parser_option.go b/parser_option.go
index 4315735..d845865 100644
--- a/parser_option.go
+++ b/parser_option.go
@@ -66,6 +66,14 @@ func WithExpirationRequired() ParserOption {
 	}
 }
 
+// WithNotBeforeRequired returns the ParserOption to make nbf claim required.
+// By default nbf claim is optional.
+func WithNotBeforeRequired() ParserOption {
+	return func(p *Parser) {
+		p.validator.requireNbf = true
+	}
+}
+
 // WithAudience configures the validator to require any of the specified
 // audiences in the `aud` claim. Validation will fail if the audience is not
 // listed in the token or the `aud` claim is missing.
diff --git a/validator.go b/validator.go
index 92b5c05..c82dfca 100644
--- a/validator.go
+++ b/validator.go
@@ -44,6 +44,9 @@ type Validator struct {
 	// requireExp specifies whether the exp claim is required
 	requireExp bool
 
+	// requireNbf specifies whether the nbf claim is required
+	requireNbf bool
+
 	// verifyIat specifies whether the iat (Issued At) claim will be verified.
 	// According to https://www.rfc-editor.org/rfc/rfc7519#section-4.1.6 this
 	// only specifies the age of the token, but no validation check is
@@ -111,8 +114,9 @@ func (v *Validator) Validate(claims Claims) error {
 	}
 
 	// We always need to check not-before, but usage of the claim itself is
-	// OPTIONAL.
-	if err = v.verifyNotBefore(claims, now, false); err != nil {
+	// OPTIONAL by default. requireNbf overrides this behavior and makes
+	// the nbf claim mandatory.
+	if err = v.verifyNotBefore(claims, now, v.requireNbf); err != nil {
 		errs = append(errs, err)
 	}
 



Test patch:
diff --git a/hmac_example_test.go b/hmac_example_test.go
index dafdd67..179d9c1 100644
--- a/hmac_example_test.go
+++ b/hmac_example_test.go
@@ -24,14 +24,13 @@ func init() {
 }
 
 // Example creating, signing, and encoding a JWT token using the HMAC signing method
-func ExampleNew_hmac() {
+func ExampleNewWithClaims_hmac() {
 	// Create a new token object, specifying signing method and the claims
 	// you would like it to contain.
 	token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
 		"foo": "bar",
 		"nbf": time.Date(2015, 10, 10, 12, 0, 0, 0, time.UTC).Unix(),
 	})
-
 	// Sign and get the complete encoded token as a string using the secret
 	tokenString, err := token.SignedString(hmacSampleSecret)
 
diff --git a/validator_test.go b/validator_test.go
index 9fdaafa..1790be1 100644
--- a/validator_test.go
+++ b/validator_test.go
@@ -262,6 +262,73 @@ func Test_Validator_verifyIssuedAt(t *testing.T) {
 	}
 }
 
+func Test_Validator_requireNotBefore(t *testing.T) {
+	type fields struct {
+		leeway     time.Duration
+		timeFunc   func() time.Time
+		requireNbf bool
+	}
+	type args struct {
+		claims   Claims
+		cmp      time.Time
+		required bool
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr error
+	}{
+		{
+			name:    "good claim without nbf",
+			fields:  fields{requireNbf: false},
+			args:    args{claims: MapClaims{}, required: false},
+			wantErr: nil,
+		},
+		{
+			name:   "good claim with nbf",
+			fields: fields{requireNbf: true},
+			args: args{
+				claims:   RegisteredClaims{NotBefore: NewNumericDate(time.Now().Add(time.Minute * -10))},
+				cmp:      time.Now().Add(10 * time.Minute),
+				required: true,
+			},
+			wantErr: nil,
+		},
+		{
+			name:   "token nbf time is in future",
+			fields: fields{requireNbf: true, timeFunc: time.Now},
+			args: args{
+				claims:   RegisteredClaims{NotBefore: NewNumericDate(time.Now().Add(time.Minute * +10))},
+				cmp:      time.Now().Add(10 * time.Minute),
+				required: true,
+			},
+			wantErr: ErrTokenNotValidYet,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			opts := []ParserOption{
+				WithLeeway(tt.fields.leeway),
+			}
+
+			if tt.fields.requireNbf {
+				opts = append(opts, WithNotBeforeRequired())
+			}
+
+			if tt.fields.timeFunc != nil {
+				opts = append(opts, WithTimeFunc(tt.fields.timeFunc))
+			}
+
+			v := NewValidator(opts...)
+
+			if err := v.verifyNotBefore(tt.args.claims, tt.args.cmp, tt.args.required); (err != nil) && !errors.Is(err, tt.wantErr) {
+				t.Errorf("validator.requireNotBefore() error = %v, wantErr %v", err, tt.wantErr)
+			}
+		})
+	}
+}
+
 func Test_Validator_verifyAudience(t *testing.T) {
 	type fields struct {
 		expectedAud []string