Adds go module support /v4 (#41)

Additionally, added `staticcheck` for basic static code analysis (#44)

Co-authored-by: Christian Banse <oxisto@aybaze.com>
This commit is contained in:
Michael Fridman 2021-08-03 09:51:01 -04:00 committed by GitHub
parent 4bbdd8ac62
commit 2ebb50f957
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 183 additions and 174 deletions

View File

@ -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 }}

View File

@ -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.

View File

@ -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

View File

@ -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)).

View File

@ -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)

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -6,7 +6,7 @@ import (
"strings"
"testing"
"github.com/golang-jwt/jwt"
"github.com/golang-jwt/jwt/v4"
)
var ecdsaTestData = []struct {

View File

@ -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

View File

@ -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

View File

@ -5,7 +5,7 @@ import (
"strings"
"testing"
"github.com/golang-jwt/jwt"
"github.com/golang-jwt/jwt/v4"
)
var ed25519TestData = []struct {

View File

@ -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

View File

@ -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()

View File

@ -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.

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module github.com/golang-jwt/jwt/v4
go 1.15

0
go.sum Normal file
View File

View File

@ -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 {

View File

@ -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

View File

@ -5,7 +5,7 @@ import (
"strings"
"testing"
"github.com/golang-jwt/jwt"
"github.com/golang-jwt/jwt/v4"
)
var hmacTestData = []struct {

View File

@ -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
}

View File

@ -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.

View File

@ -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

View File

@ -4,7 +4,7 @@ import (
"strings"
"testing"
"github.com/golang-jwt/jwt"
"github.com/golang-jwt/jwt/v4"
)
var noneTestData = []struct {

View File

@ -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 {

View File

@ -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)
}
}
}

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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 {

6
rsa.go
View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -5,7 +5,7 @@ import (
"strings"
"testing"
"github.com/golang-jwt/jwt"
"github.com/golang-jwt/jwt/v4"
)
var rsaTestData = []struct {

View File

@ -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

View File

@ -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()

1
staticcheck.conf Normal file
View File

@ -0,0 +1 @@
checks = ["all", "-ST1000", "-ST1003", "-ST1016", "-ST1023"]

View File

@ -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 {

View File

@ -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)
}