diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index ec7bd9ac..4ada1176 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -8,6 +8,18 @@ on:
     types: [opened, synchronize, reopened]
 
 jobs:
+  check:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v2
+      - uses: reviewdog/action-staticcheck@v1
+        with:
+          github_token: ${{ secrets.github_token }}
+          reporter: github-pr-review
+          filter_mode: nofilter
+          fail_on_error: true
+
   build:
     runs-on: ubuntu-latest
     strategy:
@@ -17,8 +29,6 @@ jobs:
     steps:
       - name: Checkout
         uses: actions/checkout@v2
-        with:
-          path: src/github.com/golang-jwt/jwt
       - name: Setup Go
         uses: actions/setup-go@v2
         with:
@@ -28,6 +38,3 @@ jobs:
           go vet ./...
           go test -v ./...
           go build ./...
-        env:
-          GO111MODULE: auto
-          GOPATH: ${{ github.workspace }}
diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md
index c4efbd2a..0b621493 100644
--- a/MIGRATION_GUIDE.md
+++ b/MIGRATION_GUIDE.md
@@ -1,22 +1,22 @@
-## Migration Guide (v3.2.1)
+## Migration Guide (v4.0.0)
 
-Starting from [v3.2.1](https://github.com/golang-jwt/jwt/releases/tag/v3.2.1]), the import path has changed from `github.com/dgrijalva/jwt-go` to `github.com/golang-jwt/jwt`. Future releases will be using the `github.com/golang-jwt/jwt` import path and continue the existing versioning scheme of `v3.x.x+incompatible`. Backwards-compatible patches and fixes will be done on the `v3` release branch, where as new build-breaking features will be developed in a `v4` release, possibly including a SIV-style import path.
+Starting from [v4.0.0](https://github.com/golang-jwt/jwt/releases/tag/v4.0.0]), the import path will be:
 
-### go.mod replacement
+    "github.com/golang-jwt/jwt/v4"
 
-In a first step, the easiest way is to use `go mod edit` to issue a replacement.
+The `/v4` version will be backwards compatible with existing `v3.x.y` tags in this repo, as well as 
+`github.com/dgrijalva/jwt-go`. For most users this should be a drop-in replacement, if you're having 
+troubles migrating, please open an issue.
+
+You can replace all occurrences of `github.com/dgrijalva/jwt-go` or `github.com/golang-jwt/jwt` with `github.com/golang-jwt/jwt/v4`, either manually or by using tools such as `sed` or `gofmt`.
+
+And then you'd typically run:
 
 ```
-go mod edit -replace github.com/dgrijalva/jwt-go=github.com/golang-jwt/jwt@v3.2.1+incompatible
+go get github.com/golang-jwt/jwt/v4
 go mod tidy
 ```
 
-This will still keep the old import path in your code but replace it with the new package and also introduce a new indirect dependency to `github.com/golang-jwt/jwt`. Try to compile your project; it should still work.
-
-### Cleanup
-
-If your code still consistently builds, you can replace all occurences of `github.com/dgrijalva/jwt-go` with `github.com/golang-jwt/jwt`, either manually or by using tools such as `sed`. Finally, the `replace` directive in the `go.mod` file can be removed.
-
 ## Older releases (before v3.2.0)
 
 The original migration guide for older releases can be found at https://github.com/dgrijalva/jwt-go/blob/master/MIGRATION_GUIDE.md.
\ No newline at end of file
diff --git a/README.md b/README.md
index 9b653e46..96fe3b97 100644
--- a/README.md
+++ b/README.md
@@ -5,9 +5,11 @@
 
 A [go](http://www.golang.org) (or 'golang' for search engine friendliness) implementation of [JSON Web Tokens](https://datatracker.ietf.org/doc/html/rfc7519).
 
-**IMPORT PATH CHANGE:** Starting from [v3.2.1](https://github.com/golang-jwt/jwt/releases/tag/v3.2.1), the import path has changed from `github.com/dgrijalva/jwt-go` to `github.com/golang-jwt/jwt`. After the original author of the library suggested migrating the maintenance of `jwt-go`, a dedicated team of open source maintainers decided to clone the existing library into this repository. See [dgrijalva/jwt-go#462](https://github.com/dgrijalva/jwt-go/issues/462) for a detailed discussion on this topic.
+Starting with [v4.0.0](https://github.com/golang-jwt/jwt/releases/tag/v4.0.0) this project adds Go module support, but maintains backwards compataibility with older `v3.x.y` tags and upstream `github.com/dgrijalva/jwt-go`.
+See the `MIGRATION_GUIDE.md` for more information.
+
+> After the original author of the library suggested migrating the maintenance of `jwt-go`, a dedicated team of open source maintainers decided to clone the existing library into this repository. See [dgrijalva/jwt-go#462](https://github.com/dgrijalva/jwt-go/issues/462) for a detailed discussion on this topic.
 
-Future releases will be using the `github.com/golang-jwt/jwt` import path and continue the existing versioning scheme of `v3.x.x+incompatible`. Backwards-compatible patches and fixes will be done on the `v3` release branch, where as new build-breaking features will be developed in a `v4` release, possibly including a SIV-style import path.
 
 **SECURITY NOTICE:** Some older versions of Go have a security issue in the crypto/elliptic. Recommendation is to upgrade to at least 1.15 See issue [dgrijalva/jwt-go#216](https://github.com/dgrijalva/jwt-go/issues/216) for more detail.
 
@@ -60,10 +62,8 @@ This library is considered production ready.  Feedback and feature requests are
 
 This project uses [Semantic Versioning 2.0.0](http://semver.org).  Accepted pull requests will land on `main`.  Periodically, versions will be tagged from `main`.  You can find all the releases on [the project releases page](https://github.com/golang-jwt/jwt/releases).
 
-While we try to make it obvious when we make breaking changes, there isn't a great mechanism for pushing announcements out to users.  You may want to use this alternative package include: `gopkg.in/golang-jwt/jwt.v3`.  It will do the right thing WRT semantic versioning.
-
 **BREAKING CHANGES:*** 
-* Version 3.0.0 includes _a lot_ of changes from the 2.x line, including a few that break the API.  We've tried to break as few things as possible, so there should just be a few type signature changes.  A full list of breaking changes is available in `VERSION_HISTORY.md`.  See `MIGRATION_GUIDE.md` for more information on updating your code.
+A full list of breaking changes is available in `VERSION_HISTORY.md`.  See `MIGRATION_GUIDE.md` for more information on updating your code.
 
 ## Usage Tips
 
diff --git a/VERSION_HISTORY.md b/VERSION_HISTORY.md
index 637f2ba6..afbfc4e4 100644
--- a/VERSION_HISTORY.md
+++ b/VERSION_HISTORY.md
@@ -1,5 +1,9 @@
 ## `jwt-go` Version History
 
+#### 4.0.0
+
+* Introduces support for Go modules. The `v4` version will be backwards compatible with `v3.x.y`.
+
 #### 3.2.2
 
 * Starting from this release, we are adopting the policy to support the most 2 recent versions of Go currently available. By the time of this release, this is Go 1.15 and 1.16 ([#28](https://github.com/golang-jwt/jwt/pull/28)).
diff --git a/claims.go b/claims.go
index f1dba3cb..7c2f33bc 100644
--- a/claims.go
+++ b/claims.go
@@ -6,13 +6,13 @@ import (
 	"time"
 )
 
-// For a type to be a Claims object, it must just have a Valid method that determines
+// Claims must just have a Valid method that determines
 // if the token is invalid for any supported reason
 type Claims interface {
 	Valid() error
 }
 
-// Structured version of Claims Section, as referenced at
+// StandardClaims are a structured version of the Claims Section, as referenced at
 // https://tools.ietf.org/html/rfc7519#section-4.1
 // See examples for how to use this with your own claim types
 type StandardClaims struct {
@@ -25,8 +25,7 @@ type StandardClaims struct {
 	Subject   string `json:"sub,omitempty"`
 }
 
-// Validates time based claims "exp, iat, nbf".
-// There is no accounting for clock skew.
+// Valid validates time based claims "exp, iat, nbf". There is no accounting for clock skew.
 // As well, if any of the above claims are not in the token, it will still
 // be considered a valid claim.
 func (c StandardClaims) Valid() error {
@@ -58,31 +57,31 @@ func (c StandardClaims) Valid() error {
 	return vErr
 }
 
-// Compares the aud claim against cmp.
+// VerifyAudience compares the aud claim against cmp.
 // If required is false, this method will return true if the value matches or is unset
 func (c *StandardClaims) VerifyAudience(cmp string, req bool) bool {
 	return verifyAud([]string{c.Audience}, cmp, req)
 }
 
-// Compares the exp claim against cmp.
+// VerifyExpiresAt compares the exp claim against cmp.
 // If required is false, this method will return true if the value matches or is unset
 func (c *StandardClaims) VerifyExpiresAt(cmp int64, req bool) bool {
 	return verifyExp(c.ExpiresAt, cmp, req)
 }
 
-// Compares the iat claim against cmp.
+// VerifyIssuedAt compares the iat claim against cmp.
 // If required is false, this method will return true if the value matches or is unset
 func (c *StandardClaims) VerifyIssuedAt(cmp int64, req bool) bool {
 	return verifyIat(c.IssuedAt, cmp, req)
 }
 
-// Compares the iss claim against cmp.
+// VerifyIssuer compares the iss claim against cmp.
 // If required is false, this method will return true if the value matches or is unset
 func (c *StandardClaims) VerifyIssuer(cmp string, req bool) bool {
 	return verifyIss(c.Issuer, cmp, req)
 }
 
-// Compares the nbf claim against cmp.
+// VerifyNotBefore compares the nbf claim against cmp.
 // If required is false, this method will return true if the value matches or is unset
 func (c *StandardClaims) VerifyNotBefore(cmp int64, req bool) bool {
 	return verifyNbf(c.NotBefore, cmp, req)
diff --git a/cmd/jwt/README.md b/cmd/jwt/README.md
index 8c659e9c..4388e5f9 100644
--- a/cmd/jwt/README.md
+++ b/cmd/jwt/README.md
@@ -16,5 +16,4 @@ To simply display a token, use:
 
 You can install this tool with the following command:
 
-     go install github.com/golang-jwt/jwt/cmd/jwt
-
+     go install github.com/golang-jwt/jwt/v4/cmd/jwt
\ No newline at end of file
diff --git a/cmd/jwt/args.go b/cmd/jwt/args.go
deleted file mode 100644
index a5bba5b1..00000000
--- a/cmd/jwt/args.go
+++ /dev/null
@@ -1,23 +0,0 @@
-package main
-
-import (
-	"encoding/json"
-	"fmt"
-	"strings"
-)
-
-type ArgList map[string]string
-
-func (l ArgList) String() string {
-	data, _ := json.Marshal(l)
-	return string(data)
-}
-
-func (l ArgList) Set(arg string) error {
-	parts := strings.SplitN(arg, "=", 2)
-	if len(parts) != 2 {
-		return fmt.Errorf("Invalid argument '%v'.  Must use format 'key=value'. %v", arg, parts)
-	}
-	l[parts[0]] = parts[1]
-	return nil
-}
diff --git a/cmd/jwt/app.go b/cmd/jwt/main.go
similarity index 82%
rename from cmd/jwt/app.go
rename to cmd/jwt/main.go
index c8fd9361..8b16b22a 100644
--- a/cmd/jwt/app.go
+++ b/cmd/jwt/main.go
@@ -16,7 +16,7 @@ import (
 	"regexp"
 	"strings"
 
-	"github.com/golang-jwt/jwt"
+	"github.com/golang-jwt/jwt/v4"
 )
 
 var (
@@ -67,14 +67,14 @@ func start() error {
 		return showToken()
 	} else {
 		flag.Usage()
-		return fmt.Errorf("None of the required flags are present.  What do you want me to do?")
+		return fmt.Errorf("none of the required flags are present.  What do you want me to do?")
 	}
 }
 
 // Helper func:  Read input from specified file or stdin
 func loadData(p string) ([]byte, error) {
 	if p == "" {
-		return nil, fmt.Errorf("No path specified")
+		return nil, fmt.Errorf("no path specified")
 	}
 
 	var rdr io.Reader
@@ -117,7 +117,7 @@ func verifyToken() error {
 	// get the token
 	tokData, err := loadData(*flagVerify)
 	if err != nil {
-		return fmt.Errorf("Couldn't read token: %v", err)
+		return fmt.Errorf("couldn't read token: %w", err)
 	}
 
 	// trim possible whitespace from token
@@ -150,17 +150,17 @@ func verifyToken() error {
 
 	// Print an error if we can't parse for some reason
 	if err != nil {
-		return fmt.Errorf("Couldn't parse token: %v", err)
+		return fmt.Errorf("couldn't parse token: %w", err)
 	}
 
 	// Is token invalid?
 	if !token.Valid {
-		return fmt.Errorf("Token is invalid")
+		return fmt.Errorf("token is invalid")
 	}
 
 	// Print the token details
 	if err := printJSON(token.Claims); err != nil {
-		return fmt.Errorf("Failed to output claims: %v", err)
+		return fmt.Errorf("failed to output claims: %w", err)
 	}
 
 	return nil
@@ -172,7 +172,7 @@ func signToken() error {
 	// get the token data from command line arguments
 	tokData, err := loadData(*flagSign)
 	if err != nil {
-		return fmt.Errorf("Couldn't read token: %v", err)
+		return fmt.Errorf("couldn't read token: %w", err)
 	} else if *flagDebug {
 		fmt.Fprintf(os.Stderr, "Token: %v bytes", len(tokData))
 	}
@@ -180,7 +180,7 @@ func signToken() error {
 	// parse the JSON of the claims
 	var claims jwt.MapClaims
 	if err := json.Unmarshal(tokData, &claims); err != nil {
-		return fmt.Errorf("Couldn't parse claims JSON: %v", err)
+		return fmt.Errorf("couldn't parse claims JSON: %w", err)
 	}
 
 	// add command line claims
@@ -194,13 +194,13 @@ func signToken() error {
 	var key interface{}
 	key, err = loadData(*flagKey)
 	if err != nil {
-		return fmt.Errorf("Couldn't read key: %v", err)
+		return fmt.Errorf("couldn't read key: %w", err)
 	}
 
 	// get the signing alg
 	alg := jwt.GetSigningMethod(*flagAlg)
 	if alg == nil {
-		return fmt.Errorf("Couldn't find signing method: %v", *flagAlg)
+		return fmt.Errorf("couldn't find signing method: %v", *flagAlg)
 	}
 
 	// create a new token
@@ -215,7 +215,7 @@ func signToken() error {
 
 	if isEs() {
 		if k, ok := key.([]byte); !ok {
-			return fmt.Errorf("Couldn't convert key data to key")
+			return fmt.Errorf("couldn't convert key data to key")
 		} else {
 			key, err = jwt.ParseECPrivateKeyFromPEM(k)
 			if err != nil {
@@ -224,7 +224,7 @@ func signToken() error {
 		}
 	} else if isRs() {
 		if k, ok := key.([]byte); !ok {
-			return fmt.Errorf("Couldn't convert key data to key")
+			return fmt.Errorf("couldn't convert key data to key")
 		} else {
 			key, err = jwt.ParseRSAPrivateKeyFromPEM(k)
 			if err != nil {
@@ -233,7 +233,7 @@ func signToken() error {
 		}
 	} else if isEd() {
 		if k, ok := key.([]byte); !ok {
-			return fmt.Errorf("Couldn't convert key data to key")
+			return fmt.Errorf("couldn't convert key data to key")
 		} else {
 			key, err = jwt.ParseEdPrivateKeyFromPEM(k)
 			if err != nil {
@@ -245,7 +245,7 @@ func signToken() error {
 	if out, err := token.SignedString(key); err == nil {
 		fmt.Println(out)
 	} else {
-		return fmt.Errorf("Error signing token: %v", err)
+		return fmt.Errorf("error signing token: %w", err)
 	}
 
 	return nil
@@ -256,7 +256,7 @@ func showToken() error {
 	// get the token
 	tokData, err := loadData(*flagShow)
 	if err != nil {
-		return fmt.Errorf("Couldn't read token: %v", err)
+		return fmt.Errorf("couldn't read token: %w", err)
 	}
 
 	// trim possible whitespace from token
@@ -267,18 +267,18 @@ func showToken() error {
 
 	token, err := jwt.Parse(string(tokData), nil)
 	if token == nil {
-		return fmt.Errorf("malformed token: %v", err)
+		return fmt.Errorf("malformed token: %w", err)
 	}
 
 	// Print the token details
 	fmt.Println("Header:")
 	if err := printJSON(token.Header); err != nil {
-		return fmt.Errorf("Failed to output header: %v", err)
+		return fmt.Errorf("failed to output header: %w", err)
 	}
 
 	fmt.Println("Claims:")
 	if err := printJSON(token.Claims); err != nil {
-		return fmt.Errorf("Failed to output claims: %v", err)
+		return fmt.Errorf("failed to output claims: %w", err)
 	}
 
 	return nil
@@ -295,3 +295,19 @@ func isRs() bool {
 func isEd() bool {
 	return strings.HasPrefix(strings.ToUpper(*flagAlg), "Ed")
 }
+
+type ArgList map[string]string
+
+func (l ArgList) String() string {
+	data, _ := json.Marshal(l)
+	return string(data)
+}
+
+func (l ArgList) Set(arg string) error {
+	parts := strings.SplitN(arg, "=", 2)
+	if len(parts) != 2 {
+		return fmt.Errorf("invalid argument '%v'.  Must use format 'key=value'. %v", arg, parts)
+	}
+	l[parts[0]] = parts[1]
+	return nil
+}
diff --git a/ecdsa.go b/ecdsa.go
index 15e23435..eac023fc 100644
--- a/ecdsa.go
+++ b/ecdsa.go
@@ -13,7 +13,7 @@ var (
 	ErrECDSAVerification = errors.New("crypto/ecdsa: verification error")
 )
 
-// Implements the ECDSA family of signing methods signing methods
+// SigningMethodECDSA implements the ECDSA family of signing methods.
 // Expects *ecdsa.PrivateKey for signing and *ecdsa.PublicKey for verification
 type SigningMethodECDSA struct {
 	Name      string
@@ -53,7 +53,7 @@ func (m *SigningMethodECDSA) Alg() string {
 	return m.Name
 }
 
-// Implements the Verify method from SigningMethod
+// Verify implements token verification for the SigningMethod.
 // For this verify method, key must be an ecdsa.PublicKey struct
 func (m *SigningMethodECDSA) Verify(signingString, signature string, key interface{}) error {
 	var err error
@@ -95,7 +95,7 @@ func (m *SigningMethodECDSA) Verify(signingString, signature string, key interfa
 	return ErrECDSAVerification
 }
 
-// Implements the Sign method from SigningMethod
+// Sign implements token signing for the SigningMethod.
 // For this signing method, key must be an ecdsa.PrivateKey struct
 func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string, error) {
 	// Get the key
diff --git a/ecdsa_test.go b/ecdsa_test.go
index c384608e..5b503eba 100644
--- a/ecdsa_test.go
+++ b/ecdsa_test.go
@@ -6,7 +6,7 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/golang-jwt/jwt"
+	"github.com/golang-jwt/jwt/v4"
 )
 
 var ecdsaTestData = []struct {
diff --git a/ecdsa_utils.go b/ecdsa_utils.go
index db9f4be7..5700636d 100644
--- a/ecdsa_utils.go
+++ b/ecdsa_utils.go
@@ -8,11 +8,11 @@ import (
 )
 
 var (
-	ErrNotECPublicKey  = errors.New("Key is not a valid ECDSA public key")
-	ErrNotECPrivateKey = errors.New("Key is not a valid ECDSA private key")
+	ErrNotECPublicKey  = errors.New("key is not a valid ECDSA public key")
+	ErrNotECPrivateKey = errors.New("key is not a valid ECDSA private key")
 )
 
-// Parse PEM encoded Elliptic Curve Private Key Structure
+// ParseECPrivateKeyFromPEM parses a PEM encoded Elliptic Curve Private Key Structure
 func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) {
 	var err error
 
@@ -39,7 +39,7 @@ func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) {
 	return pkey, nil
 }
 
-// Parse PEM encoded PKCS1 or PKCS8 public key
+// ParseECPublicKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 public key
 func ParseECPublicKeyFromPEM(key []byte) (*ecdsa.PublicKey, error) {
 	var err error
 
diff --git a/ed25519.go b/ed25519.go
index a2f8ddbe..9f40dc0c 100644
--- a/ed25519.go
+++ b/ed25519.go
@@ -10,7 +10,7 @@ var (
 	ErrEd25519Verification = errors.New("ed25519: verification error")
 )
 
-// Implements the EdDSA family
+// SigningMethodEd25519 implements the EdDSA family.
 // Expects ed25519.PrivateKey for signing and ed25519.PublicKey for verification
 type SigningMethodEd25519 struct{}
 
@@ -30,7 +30,7 @@ func (m *SigningMethodEd25519) Alg() string {
 	return "EdDSA"
 }
 
-// Implements the Verify method from SigningMethod
+// Verify implements token verification for the SigningMethod.
 // For this verify method, key must be an ed25519.PublicKey
 func (m *SigningMethodEd25519) Verify(signingString, signature string, key interface{}) error {
 	var err error
@@ -59,7 +59,7 @@ func (m *SigningMethodEd25519) Verify(signingString, signature string, key inter
 	return nil
 }
 
-// Implements the Sign method from SigningMethod
+// Sign implements token signing for the SigningMethod.
 // For this signing method, key must be an ed25519.PrivateKey
 func (m *SigningMethodEd25519) Sign(signingString string, key interface{}) (string, error) {
 	var ed25519Key ed25519.PrivateKey
diff --git a/ed25519_test.go b/ed25519_test.go
index 26177e28..c7109c76 100644
--- a/ed25519_test.go
+++ b/ed25519_test.go
@@ -5,7 +5,7 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/golang-jwt/jwt"
+	"github.com/golang-jwt/jwt/v4"
 )
 
 var ed25519TestData = []struct {
diff --git a/ed25519_utils.go b/ed25519_utils.go
index c6357275..cdb5e68e 100644
--- a/ed25519_utils.go
+++ b/ed25519_utils.go
@@ -9,11 +9,11 @@ import (
 )
 
 var (
-	ErrNotEdPrivateKey = errors.New("Key is not a valid Ed25519 private key")
-	ErrNotEdPublicKey  = errors.New("Key is not a valid Ed25519 public key")
+	ErrNotEdPrivateKey = errors.New("key is not a valid Ed25519 private key")
+	ErrNotEdPublicKey  = errors.New("key is not a valid Ed25519 public key")
 )
 
-// Parse PEM-encoded Edwards curve private key
+// ParseEdPrivateKeyFromPEM parses a PEM-encoded Edwards curve private key
 func ParseEdPrivateKeyFromPEM(key []byte) (crypto.PrivateKey, error) {
 	var err error
 
@@ -38,7 +38,7 @@ func ParseEdPrivateKeyFromPEM(key []byte) (crypto.PrivateKey, error) {
 	return pkey, nil
 }
 
-// Parse PEM-encoded Edwards curve public key
+// ParseEdPublicKeyFromPEM parses a PEM-encoded Edwards curve public key
 func ParseEdPublicKeyFromPEM(key []byte) (crypto.PublicKey, error) {
 	var err error
 
diff --git a/errors.go b/errors.go
index 1c93024a..f309878b 100644
--- a/errors.go
+++ b/errors.go
@@ -27,7 +27,7 @@ const (
 	ValidationErrorClaimsInvalid // Generic claims validation error
 )
 
-// Helper for constructing a ValidationError with a string error message
+// NewValidationError is a helper for constructing a ValidationError with a string error message
 func NewValidationError(errorText string, errorFlags uint32) *ValidationError {
 	return &ValidationError{
 		text:   errorText,
@@ -35,14 +35,14 @@ func NewValidationError(errorText string, errorFlags uint32) *ValidationError {
 	}
 }
 
-// The error from Parse if token is not valid
+// ValidationError represents an error from Parse if token is not valid
 type ValidationError struct {
 	Inner  error  // stores the error returned by external dependencies, i.e.: KeyFunc
 	Errors uint32 // bitfield.  see ValidationError... constants
 	text   string // errors that do not have a valid error just have text
 }
 
-// Validation error is an error type
+// Error is the implementation of the err interface.
 func (e ValidationError) Error() string {
 	if e.Inner != nil {
 		return e.Inner.Error()
diff --git a/example_test.go b/example_test.go
index 5be4a296..aae1c558 100644
--- a/example_test.go
+++ b/example_test.go
@@ -4,7 +4,7 @@ import (
 	"fmt"
 	"time"
 
-	"github.com/golang-jwt/jwt"
+	"github.com/golang-jwt/jwt/v4"
 )
 
 // Example (atypical) using the StandardClaims type by itself to parse a token.
diff --git a/go.mod b/go.mod
new file mode 100644
index 00000000..6bc53fdc
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module github.com/golang-jwt/jwt/v4
+
+go 1.15
diff --git a/go.sum b/go.sum
new file mode 100644
index 00000000..e69de29b
diff --git a/hmac.go b/hmac.go
index addbe5d4..011f68a2 100644
--- a/hmac.go
+++ b/hmac.go
@@ -6,7 +6,7 @@ import (
 	"errors"
 )
 
-// Implements the HMAC-SHA family of signing methods signing methods
+// SigningMethodHMAC implements the HMAC-SHA family of signing methods.
 // Expects key type of []byte for both signing and validation
 type SigningMethodHMAC struct {
 	Name string
@@ -45,7 +45,7 @@ func (m *SigningMethodHMAC) Alg() string {
 	return m.Name
 }
 
-// Verify the signature of HSXXX tokens.  Returns nil if the signature is valid.
+// Verify implements token verification for the SigningMethod. Returns nil if the signature is valid.
 func (m *SigningMethodHMAC) Verify(signingString, signature string, key interface{}) error {
 	// Verify the key is the right type
 	keyBytes, ok := key.([]byte)
@@ -77,7 +77,7 @@ func (m *SigningMethodHMAC) Verify(signingString, signature string, key interfac
 	return nil
 }
 
-// Implements the Sign method from SigningMethod for this signing method.
+// Sign implements token signing for the SigningMethod.
 // Key must be []byte
 func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) (string, error) {
 	if keyBytes, ok := key.([]byte); ok {
diff --git a/hmac_example_test.go b/hmac_example_test.go
index 76576771..8972f1fb 100644
--- a/hmac_example_test.go
+++ b/hmac_example_test.go
@@ -5,7 +5,7 @@ import (
 	"io/ioutil"
 	"time"
 
-	"github.com/golang-jwt/jwt"
+	"github.com/golang-jwt/jwt/v4"
 )
 
 // For HMAC signing method, the key can be any []byte. It is recommended to generate
diff --git a/hmac_test.go b/hmac_test.go
index f45d5dbe..9ccf799c 100644
--- a/hmac_test.go
+++ b/hmac_test.go
@@ -5,7 +5,7 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/golang-jwt/jwt"
+	"github.com/golang-jwt/jwt/v4"
 )
 
 var hmacTestData = []struct {
diff --git a/http_example_test.go b/http_example_test.go
index 3b6330b5..71a4cc8b 100644
--- a/http_example_test.go
+++ b/http_example_test.go
@@ -16,8 +16,8 @@ import (
 	"strings"
 	"time"
 
-	"github.com/golang-jwt/jwt"
-	"github.com/golang-jwt/jwt/request"
+	"github.com/golang-jwt/jwt/v4"
+	"github.com/golang-jwt/jwt/v4/request"
 )
 
 // location of the files used for signing and verification
@@ -30,11 +30,6 @@ var (
 	verifyKey  *rsa.PublicKey
 	signKey    *rsa.PrivateKey
 	serverPort int
-	// storing sample username/password pairs
-	// don't do this on a real server
-	users = map[string]string{
-		"test": "known",
-	}
 )
 
 // read the key files before starting http handlers
@@ -65,8 +60,6 @@ func init() {
 	}()
 }
 
-var start func()
-
 func fatal(err error) {
 	if err != nil {
 		log.Fatal(err)
@@ -199,11 +192,11 @@ func authHandler(w http.ResponseWriter, r *http.Request) {
 // only accessible with a valid token
 func restrictedHandler(w http.ResponseWriter, r *http.Request) {
 	// Get token from request
-	token, err := request.ParseFromRequestWithClaims(r, request.OAuth2Extractor, &CustomClaimsExample{}, func(token *jwt.Token) (interface{}, error) {
+	token, err := request.ParseFromRequest(r, request.OAuth2Extractor, func(token *jwt.Token) (interface{}, error) {
 		// since we only use the one private key to sign the tokens,
 		// we also only use its public counter part to verify
 		return verifyKey, nil
-	})
+	}, request.WithClaims(&CustomClaimsExample{}))
 
 	// If the token is missing or invalid, return error
 	if err != nil {
@@ -214,5 +207,4 @@ func restrictedHandler(w http.ResponseWriter, r *http.Request) {
 
 	// Token is valid
 	fmt.Fprintln(w, "Welcome,", token.Claims.(*CustomClaimsExample).Name)
-	return
 }
diff --git a/map_claims.go b/map_claims.go
index 72c79f92..7e00e753 100644
--- a/map_claims.go
+++ b/map_claims.go
@@ -6,7 +6,7 @@ import (
 	// "fmt"
 )
 
-// Claims type that uses the map[string]interface{} for JSON decoding
+// MapClaims is a claims type that uses the map[string]interface{} for JSON decoding.
 // This is the default claims type if you don't supply one
 type MapClaims map[string]interface{}
 
@@ -31,7 +31,7 @@ func (m MapClaims) VerifyAudience(cmp string, req bool) bool {
 	return verifyAud(aud, cmp, req)
 }
 
-// Compares the exp claim against cmp.
+// VerifyExpiresAt compares the exp claim against cmp.
 // If required is false, this method will return true if the value matches or is unset
 func (m MapClaims) VerifyExpiresAt(cmp int64, req bool) bool {
 	exp, ok := m["exp"]
@@ -48,7 +48,7 @@ func (m MapClaims) VerifyExpiresAt(cmp int64, req bool) bool {
 	return false
 }
 
-// Compares the iat claim against cmp.
+// VerifyIssuedAt compares the iat claim against cmp.
 // If required is false, this method will return true if the value matches or is unset
 func (m MapClaims) VerifyIssuedAt(cmp int64, req bool) bool {
 	iat, ok := m["iat"]
@@ -65,14 +65,14 @@ func (m MapClaims) VerifyIssuedAt(cmp int64, req bool) bool {
 	return false
 }
 
-// Compares the iss claim against cmp.
+// VerifyIssuer compares the iss claim against cmp.
 // If required is false, this method will return true if the value matches or is unset
 func (m MapClaims) VerifyIssuer(cmp string, req bool) bool {
 	iss, _ := m["iss"].(string)
 	return verifyIss(iss, cmp, req)
 }
 
-// Compares the nbf claim against cmp.
+// VerifyNotBefore compares the nbf claim against cmp.
 // If required is false, this method will return true if the value matches or is unset
 func (m MapClaims) VerifyNotBefore(cmp int64, req bool) bool {
 	nbf, ok := m["nbf"]
@@ -89,7 +89,7 @@ func (m MapClaims) VerifyNotBefore(cmp int64, req bool) bool {
 	return false
 }
 
-// Validates time based claims "exp, iat, nbf".
+// Valid calidates time based claims "exp, iat, nbf".
 // There is no accounting for clock skew.
 // As well, if any of the above claims are not in the token, it will still
 // be considered a valid claim.
diff --git a/none.go b/none.go
index f04d189d..f19835d2 100644
--- a/none.go
+++ b/none.go
@@ -1,6 +1,6 @@
 package jwt
 
-// Implements the none signing method.  This is required by the spec
+// SigningMethodNone implements the none signing method.  This is required by the spec
 // but you probably should never use it.
 var SigningMethodNone *signingMethodNone
 
diff --git a/none_test.go b/none_test.go
index 9e3371a7..cbf6657e 100644
--- a/none_test.go
+++ b/none_test.go
@@ -4,7 +4,7 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/golang-jwt/jwt"
+	"github.com/golang-jwt/jwt/v4"
 )
 
 var noneTestData = []struct {
diff --git a/parser.go b/parser.go
index d6901d9a..0c811f31 100644
--- a/parser.go
+++ b/parser.go
@@ -13,7 +13,7 @@ type Parser struct {
 	SkipClaimsValidation bool     // Skip claims validation during token parsing
 }
 
-// Parse, validate, and return a token.
+// Parse parses, validates, and returns a token.
 // keyFunc will receive the parsed token and should return the key for validating.
 // If everything is kosher, err will be nil
 func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
@@ -87,12 +87,12 @@ func (p *Parser) ParseWithClaims(tokenString string, claims Claims, keyFunc Keyf
 	return token, vErr
 }
 
-// WARNING: Don't use this method unless you know what you're doing
+// ParseUnverified parses the token but doesn't validate the signature.
 //
-// This method parses the token but doesn't validate the signature. It's only
-// ever useful in cases where you know the signature is valid (because it has
-// been checked previously in the stack) and you want to extract values from
-// it.
+// WARNING: Don't use this method unless you know what you're doing.
+//
+// It's only ever useful in cases where you know the signature is valid (because it has
+// been checked previously in the stack) and you want to extract values from it.
 func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) {
 	parts = strings.Split(tokenString, ".")
 	if len(parts) != 3 {
diff --git a/parser_test.go b/parser_test.go
index abd245e8..870fd1cb 100644
--- a/parser_test.go
+++ b/parser_test.go
@@ -8,17 +8,17 @@ import (
 	"testing"
 	"time"
 
-	"github.com/golang-jwt/jwt"
-	"github.com/golang-jwt/jwt/test"
+	"github.com/golang-jwt/jwt/v4"
+	"github.com/golang-jwt/jwt/v4/test"
 )
 
-var keyFuncError error = fmt.Errorf("error loading key")
+var errKeyFuncError error = fmt.Errorf("error loading key")
 
 var (
 	jwtTestDefaultKey *rsa.PublicKey
 	defaultKeyFunc    jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return jwtTestDefaultKey, nil }
 	emptyKeyFunc      jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return nil, nil }
-	errorKeyFunc      jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return nil, keyFuncError }
+	errorKeyFunc      jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return nil, errKeyFuncError }
 	nilKeyFunc        jwt.Keyfunc = nil
 )
 
@@ -236,8 +236,8 @@ func TestParser_Parse(t *testing.T) {
 					t.Errorf("[%v] Errors don't match expectation.  %v != %v", data.name, e, data.errors)
 				}
 
-				if err.Error() == keyFuncError.Error() && ve.Inner != keyFuncError {
-					t.Errorf("[%v] Inner error does not match expectation.  %v != %v", data.name, ve.Inner, keyFuncError)
+				if err.Error() == errKeyFuncError.Error() && ve.Inner != errKeyFuncError {
+					t.Errorf("[%v] Inner error does not match expectation.  %v != %v", data.name, ve.Inner, errKeyFuncError)
 				}
 			}
 		}
diff --git a/request/extractor.go b/request/extractor.go
index 14414fe2..b297b8aa 100644
--- a/request/extractor.go
+++ b/request/extractor.go
@@ -10,15 +10,15 @@ var (
 	ErrNoTokenInRequest = errors.New("no token present in request")
 )
 
-// Interface for extracting a token from an HTTP request.
+// Extractor is an interface for extracting a token from an HTTP request.
 // The ExtractToken method should return a token string or an error.
 // If no token is present, you must return ErrNoTokenInRequest.
 type Extractor interface {
 	ExtractToken(*http.Request) (string, error)
 }
 
-// Extractor for finding a token in a header.  Looks at each specified
-// header in order until there's a match
+// HeaderExtractor is an extractor for finding a token in a header.
+// Looks at each specified header in order until there's a match
 type HeaderExtractor []string
 
 func (e HeaderExtractor) ExtractToken(req *http.Request) (string, error) {
@@ -31,7 +31,7 @@ func (e HeaderExtractor) ExtractToken(req *http.Request) (string, error) {
 	return "", ErrNoTokenInRequest
 }
 
-// Extract token from request arguments.  This includes a POSTed form or
+// ArgumentExtractor extracts a token from request arguments.  This includes a POSTed form or
 // GET URL arguments.  Argument names are tried in order until there's a match.
 // This extractor calls `ParseMultipartForm` on the request
 type ArgumentExtractor []string
@@ -50,7 +50,7 @@ func (e ArgumentExtractor) ExtractToken(req *http.Request) (string, error) {
 	return "", ErrNoTokenInRequest
 }
 
-// Tries Extractors in order until one returns a token string or an error occurs
+// MultiExtractor tries Extractors in order until one returns a token string or an error occurs
 type MultiExtractor []Extractor
 
 func (e MultiExtractor) ExtractToken(req *http.Request) (string, error) {
@@ -65,7 +65,7 @@ func (e MultiExtractor) ExtractToken(req *http.Request) (string, error) {
 	return "", ErrNoTokenInRequest
 }
 
-// Wrap an Extractor in this to post-process the value before it's handed off.
+// PostExtractionFilter wraps an Extractor in this to post-process the value before it's handed off.
 // See AuthorizationHeaderExtractor for an example
 type PostExtractionFilter struct {
 	Extractor
diff --git a/request/oauth2.go b/request/oauth2.go
index 5948694a..5860a53f 100644
--- a/request/oauth2.go
+++ b/request/oauth2.go
@@ -13,14 +13,14 @@ func stripBearerPrefixFromTokenString(tok string) (string, error) {
 	return tok, nil
 }
 
-// Extract bearer token from Authorization header
+// AuthorizationHeaderExtractor extracts a bearer token from Authorization header
 // Uses PostExtractionFilter to strip "Bearer " prefix from header
 var AuthorizationHeaderExtractor = &PostExtractionFilter{
 	HeaderExtractor{"Authorization"},
 	stripBearerPrefixFromTokenString,
 }
 
-// Extractor for OAuth2 access tokens.  Looks in 'Authorization'
+// OAuth2Extractor is an Extractor for OAuth2 access tokens.  Looks in 'Authorization'
 // header then 'access_token' argument for a token.
 var OAuth2Extractor = &MultiExtractor{
 	AuthorizationHeaderExtractor,
diff --git a/request/request.go b/request/request.go
index 32b27297..79f53f4e 100644
--- a/request/request.go
+++ b/request/request.go
@@ -3,10 +3,10 @@ package request
 import (
 	"net/http"
 
-	"github.com/golang-jwt/jwt"
+	"github.com/golang-jwt/jwt/v4"
 )
 
-// Extract and parse a JWT token from an HTTP request.
+// ParseFromRequest extracts and parses a JWT token from an HTTP request.
 // This behaves the same as Parse, but accepts a request and an extractor
 // instead of a token string.  The Extractor interface allows you to define
 // the logic for extracting a token.  Several useful implementations are provided.
@@ -39,8 +39,9 @@ func ParseFromRequest(req *http.Request, extractor Extractor, keyFunc jwt.Keyfun
 	return p.parser.ParseWithClaims(tokenString, p.claims, keyFunc)
 }
 
-// ParseFromRequest but with custom Claims type
-// DEPRECATED: use ParseFromRequest and the WithClaims option
+// ParseFromRequestWithClaims is an alias for ParseFromRequest but with custom Claims type.
+//
+// Deprecated: use ParseFromRequest and the WithClaims option
 func ParseFromRequestWithClaims(req *http.Request, extractor Extractor, claims jwt.Claims, keyFunc jwt.Keyfunc) (token *jwt.Token, err error) {
 	return ParseFromRequest(req, extractor, keyFunc, WithClaims(claims))
 }
@@ -54,14 +55,14 @@ type fromRequestParser struct {
 
 type ParseFromRequestOption func(*fromRequestParser)
 
-// Parse with custom claims
+// WithClaims parses with custom claims
 func WithClaims(claims jwt.Claims) ParseFromRequestOption {
 	return func(p *fromRequestParser) {
 		p.claims = claims
 	}
 }
 
-// Parse using a custom parser
+// WithParser parses using a custom parser
 func WithParser(parser *jwt.Parser) ParseFromRequestOption {
 	return func(p *fromRequestParser) {
 		p.parser = parser
diff --git a/request/request_test.go b/request/request_test.go
index fd3a850b..687392c7 100644
--- a/request/request_test.go
+++ b/request/request_test.go
@@ -8,8 +8,8 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/golang-jwt/jwt"
-	"github.com/golang-jwt/jwt/test"
+	"github.com/golang-jwt/jwt/v4"
+	"github.com/golang-jwt/jwt/v4/test"
 )
 
 var requestTestData = []struct {
diff --git a/rsa.go b/rsa.go
index e4caf1ca..b910b19c 100644
--- a/rsa.go
+++ b/rsa.go
@@ -6,7 +6,7 @@ import (
 	"crypto/rsa"
 )
 
-// Implements the RSA family of signing methods signing methods
+// SigningMethodRSA implements the RSA family of signing methods.
 // Expects *rsa.PrivateKey for signing and *rsa.PublicKey for validation
 type SigningMethodRSA struct {
 	Name string
@@ -44,7 +44,7 @@ func (m *SigningMethodRSA) Alg() string {
 	return m.Name
 }
 
-// Implements the Verify method from SigningMethod
+// Verify implements token verification for the SigningMethod
 // For this signing method, must be an *rsa.PublicKey structure.
 func (m *SigningMethodRSA) Verify(signingString, signature string, key interface{}) error {
 	var err error
@@ -73,7 +73,7 @@ func (m *SigningMethodRSA) Verify(signingString, signature string, key interface
 	return rsa.VerifyPKCS1v15(rsaKey, m.Hash, hasher.Sum(nil), sig)
 }
 
-// Implements the Sign method from SigningMethod
+// Sign implements token signing for the SigningMethod
 // For this signing method, must be an *rsa.PrivateKey structure.
 func (m *SigningMethodRSA) Sign(signingString string, key interface{}) (string, error) {
 	var rsaKey *rsa.PrivateKey
diff --git a/rsa_pss.go b/rsa_pss.go
index c0147086..5a8502fe 100644
--- a/rsa_pss.go
+++ b/rsa_pss.go
@@ -8,7 +8,7 @@ import (
 	"crypto/rsa"
 )
 
-// Implements the RSAPSS family of signing methods signing methods
+// SigningMethodRSAPSS implements the RSAPSS family of signing methods signing methods
 type SigningMethodRSAPSS struct {
 	*SigningMethodRSA
 	Options *rsa.PSSOptions
@@ -79,7 +79,7 @@ func init() {
 	})
 }
 
-// Implements the Verify method from SigningMethod
+// Verify implements token verification for the SigningMethod.
 // For this verify method, key must be an rsa.PublicKey struct
 func (m *SigningMethodRSAPSS) Verify(signingString, signature string, key interface{}) error {
 	var err error
@@ -113,7 +113,7 @@ func (m *SigningMethodRSAPSS) Verify(signingString, signature string, key interf
 	return rsa.VerifyPSS(rsaKey, m.Hash, hasher.Sum(nil), sig, opts)
 }
 
-// Implements the Sign method from SigningMethod
+// Sign implements token signing for the SigningMethod.
 // For this signing method, key must be an rsa.PrivateKey struct
 func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) (string, error) {
 	var rsaKey *rsa.PrivateKey
diff --git a/rsa_pss_test.go b/rsa_pss_test.go
index d1cafe71..716500eb 100644
--- a/rsa_pss_test.go
+++ b/rsa_pss_test.go
@@ -9,8 +9,8 @@ import (
 	"testing"
 	"time"
 
-	"github.com/golang-jwt/jwt"
-	"github.com/golang-jwt/jwt/test"
+	"github.com/golang-jwt/jwt/v4"
+	"github.com/golang-jwt/jwt/v4/test"
 )
 
 var rsaPSSTestData = []struct {
diff --git a/rsa_test.go b/rsa_test.go
index fba45e07..e0c66630 100644
--- a/rsa_test.go
+++ b/rsa_test.go
@@ -5,7 +5,7 @@ import (
 	"strings"
 	"testing"
 
-	"github.com/golang-jwt/jwt"
+	"github.com/golang-jwt/jwt/v4"
 )
 
 var rsaTestData = []struct {
diff --git a/rsa_utils.go b/rsa_utils.go
index 14c78c29..1966c450 100644
--- a/rsa_utils.go
+++ b/rsa_utils.go
@@ -8,12 +8,12 @@ import (
 )
 
 var (
-	ErrKeyMustBePEMEncoded = errors.New("Invalid Key: Key must be a PEM encoded PKCS1 or PKCS8 key")
-	ErrNotRSAPrivateKey    = errors.New("Key is not a valid RSA private key")
-	ErrNotRSAPublicKey     = errors.New("Key is not a valid RSA public key")
+	ErrKeyMustBePEMEncoded = errors.New("invalid key: Key must be a PEM encoded PKCS1 or PKCS8 key")
+	ErrNotRSAPrivateKey    = errors.New("key is not a valid RSA private key")
+	ErrNotRSAPublicKey     = errors.New("key is not a valid RSA public key")
 )
 
-// Parse PEM encoded PKCS1 or PKCS8 private key
+// ParseRSAPrivateKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 private key
 func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) {
 	var err error
 
@@ -39,7 +39,11 @@ func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) {
 	return pkey, nil
 }
 
-// Parse PEM encoded PKCS1 or PKCS8 private key protected with password
+// ParseRSAPrivateKeyFromPEMWithPassword parses a PEM encoded PKCS1 or PKCS8 private key protected with password
+//
+// Deprecated: This function is deprecated and should not be used anymore. It uses the deprecated x509.DecryptPEMBlock
+// function, which was deprecated since RFC 1423 is regarded insecure by design. Unfortunately, there is no alternative
+// in the Go standard library for now. See https://github.com/golang/go/issues/8860.
 func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) (*rsa.PrivateKey, error) {
 	var err error
 
@@ -71,7 +75,7 @@ func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) (*rsa.Pr
 	return pkey, nil
 }
 
-// Parse PEM encoded PKCS1 or PKCS8 public key
+// ParseRSAPublicKeyFromPEM parses a PEM encoded PKCS1 or PKCS8 public key
 func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) {
 	var err error
 
diff --git a/signing_method.go b/signing_method.go
index ed1f212b..3269170f 100644
--- a/signing_method.go
+++ b/signing_method.go
@@ -7,14 +7,14 @@ import (
 var signingMethods = map[string]func() SigningMethod{}
 var signingMethodLock = new(sync.RWMutex)
 
-// Implement SigningMethod to add new methods for signing or verifying tokens.
+// SigningMethod can be used add new methods for signing or verifying tokens.
 type SigningMethod interface {
 	Verify(signingString, signature string, key interface{}) error // Returns nil if signature is valid
 	Sign(signingString string, key interface{}) (string, error)    // Returns encoded signature or error
 	Alg() string                                                   // returns the alg identifier for this method (example: 'HS256')
 }
 
-// Register the "alg" name and a factory function for signing method.
+// RegisterSigningMethod registers the "alg" name and a factory function for signing method.
 // This is typically done during init() in the method's implementation
 func RegisterSigningMethod(alg string, f func() SigningMethod) {
 	signingMethodLock.Lock()
@@ -23,7 +23,7 @@ func RegisterSigningMethod(alg string, f func() SigningMethod) {
 	signingMethods[alg] = f
 }
 
-// Get a signing method from an "alg" string
+// GetSigningMethod retrieves a signing method from an "alg" string
 func GetSigningMethod(alg string) (method SigningMethod) {
 	signingMethodLock.RLock()
 	defer signingMethodLock.RUnlock()
diff --git a/staticcheck.conf b/staticcheck.conf
new file mode 100644
index 00000000..53745d51
--- /dev/null
+++ b/staticcheck.conf
@@ -0,0 +1 @@
+checks = ["all", "-ST1000", "-ST1003", "-ST1016", "-ST1023"]
diff --git a/test/helpers.go b/test/helpers.go
index ef54aeab..c541edb1 100644
--- a/test/helpers.go
+++ b/test/helpers.go
@@ -4,7 +4,7 @@ import (
 	"crypto/rsa"
 	"io/ioutil"
 
-	"github.com/golang-jwt/jwt"
+	"github.com/golang-jwt/jwt/v4"
 )
 
 func LoadRSAPrivateKeyFromDisk(location string) *rsa.PrivateKey {
diff --git a/token.go b/token.go
index 6b30ced1..b896acb0 100644
--- a/token.go
+++ b/token.go
@@ -12,13 +12,13 @@ import (
 // server uses a different time zone than your tokens.
 var TimeFunc = time.Now
 
-// Parse methods use this callback function to supply
+// Keyfunc will be used by the Parse methods as a callback function to supply
 // the key for verification.  The function receives the parsed,
 // but unverified Token.  This allows you to use properties in the
 // Header of the token (such as `kid`) to identify which key to use.
 type Keyfunc func(*Token) (interface{}, error)
 
-// A JWT Token.  Different fields will be used depending on whether you're
+// Token represents a JWT Token.  Different fields will be used depending on whether you're
 // creating or parsing/verifying a token.
 type Token struct {
 	Raw       string                 // The raw token.  Populated when you Parse a token
@@ -29,7 +29,7 @@ type Token struct {
 	Valid     bool                   // Is the token valid?  Populated when you Parse/Verify a token
 }
 
-// Create a new Token.  Takes a signing method
+// New creates a new Token.  Takes a signing method
 func New(method SigningMethod) *Token {
 	return NewWithClaims(method, MapClaims{})
 }
@@ -45,7 +45,7 @@ func NewWithClaims(method SigningMethod, claims Claims) *Token {
 	}
 }
 
-// Get the complete, signed token
+// SignedString retrieves the complete, signed token
 func (t *Token) SignedString(key interface{}) (string, error) {
 	var sig, sstr string
 	var err error
@@ -58,7 +58,7 @@ func (t *Token) SignedString(key interface{}) (string, error) {
 	return strings.Join([]string{sstr, sig}, "."), nil
 }
 
-// Generate the signing string.  This is the
+// SigningString generates the signing string.  This is the
 // most expensive part of the whole deal.  Unless you
 // need this for something special, just go straight for
 // the SignedString.
@@ -82,7 +82,7 @@ func (t *Token) SigningString() (string, error) {
 	return strings.Join(parts, "."), nil
 }
 
-// Parse, validate, and return a token.
+// Parse parses, validates, and returns a token.
 // keyFunc will receive the parsed token and should return the key for validating.
 // If everything is kosher, err will be nil
 func Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
@@ -93,12 +93,18 @@ func ParseWithClaims(tokenString string, claims Claims, keyFunc Keyfunc) (*Token
 	return new(Parser).ParseWithClaims(tokenString, claims, keyFunc)
 }
 
-// Encode JWT specific base64url encoding with padding stripped
+// EncodeSegment encodes a JWT specific base64url encoding with padding stripped
+//
+// Deprecated: In a future release, we will demote this function to a non-exported function, since it
+// should only be used internally
 func EncodeSegment(seg []byte) string {
 	return base64.RawURLEncoding.EncodeToString(seg)
 }
 
-// Decode JWT specific base64url encoding with padding stripped
+// DecodeSegment decodes a JWT specific base64url encoding with padding stripped
+//
+// Deprecated: In a future release, we will demote this function to a non-exported function, since it
+// should only be used internally
 func DecodeSegment(seg string) ([]byte, error) {
 	return base64.RawURLEncoding.DecodeString(seg)
 }