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] types: [opened, synchronize, reopened]
jobs: 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: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
@ -17,8 +29,6 @@ jobs:
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2
with:
path: src/github.com/golang-jwt/jwt
- name: Setup Go - name: Setup Go
uses: actions/setup-go@v2 uses: actions/setup-go@v2
with: with:
@ -28,6 +38,3 @@ jobs:
go vet ./... go vet ./...
go test -v ./... go test -v ./...
go build ./... 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 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) ## 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. 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). 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. **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). 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:*** **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 ## Usage Tips

View File

@ -1,5 +1,9 @@
## `jwt-go` Version History ## `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 #### 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)). * 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" "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 // if the token is invalid for any supported reason
type Claims interface { type Claims interface {
Valid() error 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 // https://tools.ietf.org/html/rfc7519#section-4.1
// See examples for how to use this with your own claim types // See examples for how to use this with your own claim types
type StandardClaims struct { type StandardClaims struct {
@ -25,8 +25,7 @@ type StandardClaims struct {
Subject string `json:"sub,omitempty"` Subject string `json:"sub,omitempty"`
} }
// Validates time based claims "exp, iat, nbf". // Valid validates time based claims "exp, iat, nbf". There is no accounting for clock skew.
// There is no accounting for clock skew.
// As well, if any of the above claims are not in the token, it will still // As well, if any of the above claims are not in the token, it will still
// be considered a valid claim. // be considered a valid claim.
func (c StandardClaims) Valid() error { func (c StandardClaims) Valid() error {
@ -58,31 +57,31 @@ func (c StandardClaims) Valid() error {
return vErr 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 // 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 { func (c *StandardClaims) VerifyAudience(cmp string, req bool) bool {
return verifyAud([]string{c.Audience}, cmp, req) 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 // 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 { func (c *StandardClaims) VerifyExpiresAt(cmp int64, req bool) bool {
return verifyExp(c.ExpiresAt, cmp, req) 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 // 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 { func (c *StandardClaims) VerifyIssuedAt(cmp int64, req bool) bool {
return verifyIat(c.IssuedAt, cmp, req) 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 // 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 { func (c *StandardClaims) VerifyIssuer(cmp string, req bool) bool {
return verifyIss(c.Issuer, cmp, req) 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 // 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 { func (c *StandardClaims) VerifyNotBefore(cmp int64, req bool) bool {
return verifyNbf(c.NotBefore, cmp, req) 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: 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" "regexp"
"strings" "strings"
"github.com/golang-jwt/jwt" "github.com/golang-jwt/jwt/v4"
) )
var ( var (
@ -67,14 +67,14 @@ func start() error {
return showToken() return showToken()
} else { } else {
flag.Usage() 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 // Helper func: Read input from specified file or stdin
func loadData(p string) ([]byte, error) { func loadData(p string) ([]byte, error) {
if p == "" { if p == "" {
return nil, fmt.Errorf("No path specified") return nil, fmt.Errorf("no path specified")
} }
var rdr io.Reader var rdr io.Reader
@ -117,7 +117,7 @@ func verifyToken() error {
// get the token // get the token
tokData, err := loadData(*flagVerify) tokData, err := loadData(*flagVerify)
if err != nil { 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 // trim possible whitespace from token
@ -150,17 +150,17 @@ func verifyToken() error {
// Print an error if we can't parse for some reason // Print an error if we can't parse for some reason
if err != nil { if err != nil {
return fmt.Errorf("Couldn't parse token: %v", err) return fmt.Errorf("couldn't parse token: %w", err)
} }
// Is token invalid? // Is token invalid?
if !token.Valid { if !token.Valid {
return fmt.Errorf("Token is invalid") return fmt.Errorf("token is invalid")
} }
// Print the token details // Print the token details
if err := printJSON(token.Claims); err != nil { 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 return nil
@ -172,7 +172,7 @@ func signToken() error {
// get the token data from command line arguments // get the token data from command line arguments
tokData, err := loadData(*flagSign) tokData, err := loadData(*flagSign)
if err != nil { if err != nil {
return fmt.Errorf("Couldn't read token: %v", err) return fmt.Errorf("couldn't read token: %w", err)
} else if *flagDebug { } else if *flagDebug {
fmt.Fprintf(os.Stderr, "Token: %v bytes", len(tokData)) fmt.Fprintf(os.Stderr, "Token: %v bytes", len(tokData))
} }
@ -180,7 +180,7 @@ func signToken() error {
// parse the JSON of the claims // parse the JSON of the claims
var claims jwt.MapClaims var claims jwt.MapClaims
if err := json.Unmarshal(tokData, &claims); err != nil { 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 // add command line claims
@ -194,13 +194,13 @@ func signToken() error {
var key interface{} var key interface{}
key, err = loadData(*flagKey) key, err = loadData(*flagKey)
if err != nil { 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 // get the signing alg
alg := jwt.GetSigningMethod(*flagAlg) alg := jwt.GetSigningMethod(*flagAlg)
if alg == nil { 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 // create a new token
@ -215,7 +215,7 @@ func signToken() error {
if isEs() { if isEs() {
if k, ok := key.([]byte); !ok { 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 { } else {
key, err = jwt.ParseECPrivateKeyFromPEM(k) key, err = jwt.ParseECPrivateKeyFromPEM(k)
if err != nil { if err != nil {
@ -224,7 +224,7 @@ func signToken() error {
} }
} else if isRs() { } else if isRs() {
if k, ok := key.([]byte); !ok { 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 { } else {
key, err = jwt.ParseRSAPrivateKeyFromPEM(k) key, err = jwt.ParseRSAPrivateKeyFromPEM(k)
if err != nil { if err != nil {
@ -233,7 +233,7 @@ func signToken() error {
} }
} else if isEd() { } else if isEd() {
if k, ok := key.([]byte); !ok { 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 { } else {
key, err = jwt.ParseEdPrivateKeyFromPEM(k) key, err = jwt.ParseEdPrivateKeyFromPEM(k)
if err != nil { if err != nil {
@ -245,7 +245,7 @@ func signToken() error {
if out, err := token.SignedString(key); err == nil { if out, err := token.SignedString(key); err == nil {
fmt.Println(out) fmt.Println(out)
} else { } else {
return fmt.Errorf("Error signing token: %v", err) return fmt.Errorf("error signing token: %w", err)
} }
return nil return nil
@ -256,7 +256,7 @@ func showToken() error {
// get the token // get the token
tokData, err := loadData(*flagShow) tokData, err := loadData(*flagShow)
if err != nil { 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 // trim possible whitespace from token
@ -267,18 +267,18 @@ func showToken() error {
token, err := jwt.Parse(string(tokData), nil) token, err := jwt.Parse(string(tokData), nil)
if token == nil { if token == nil {
return fmt.Errorf("malformed token: %v", err) return fmt.Errorf("malformed token: %w", err)
} }
// Print the token details // Print the token details
fmt.Println("Header:") fmt.Println("Header:")
if err := printJSON(token.Header); err != nil { 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:") fmt.Println("Claims:")
if err := printJSON(token.Claims); err != nil { 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 return nil
@ -295,3 +295,19 @@ func isRs() bool {
func isEd() bool { func isEd() bool {
return strings.HasPrefix(strings.ToUpper(*flagAlg), "Ed") 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") 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 // Expects *ecdsa.PrivateKey for signing and *ecdsa.PublicKey for verification
type SigningMethodECDSA struct { type SigningMethodECDSA struct {
Name string Name string
@ -53,7 +53,7 @@ func (m *SigningMethodECDSA) Alg() string {
return m.Name 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 // For this verify method, key must be an ecdsa.PublicKey struct
func (m *SigningMethodECDSA) Verify(signingString, signature string, key interface{}) error { func (m *SigningMethodECDSA) Verify(signingString, signature string, key interface{}) error {
var err error var err error
@ -95,7 +95,7 @@ func (m *SigningMethodECDSA) Verify(signingString, signature string, key interfa
return ErrECDSAVerification 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 // For this signing method, key must be an ecdsa.PrivateKey struct
func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string, error) { func (m *SigningMethodECDSA) Sign(signingString string, key interface{}) (string, error) {
// Get the key // Get the key

View File

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

View File

@ -8,11 +8,11 @@ import (
) )
var ( var (
ErrNotECPublicKey = errors.New("Key is not a valid ECDSA public key") ErrNotECPublicKey = errors.New("key is not a valid ECDSA public key")
ErrNotECPrivateKey = errors.New("Key is not a valid ECDSA private 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) { func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) {
var err error var err error
@ -39,7 +39,7 @@ func ParseECPrivateKeyFromPEM(key []byte) (*ecdsa.PrivateKey, error) {
return pkey, nil 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) { func ParseECPublicKeyFromPEM(key []byte) (*ecdsa.PublicKey, error) {
var err error var err error

View File

@ -10,7 +10,7 @@ var (
ErrEd25519Verification = errors.New("ed25519: verification error") 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 // Expects ed25519.PrivateKey for signing and ed25519.PublicKey for verification
type SigningMethodEd25519 struct{} type SigningMethodEd25519 struct{}
@ -30,7 +30,7 @@ func (m *SigningMethodEd25519) Alg() string {
return "EdDSA" 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 // For this verify method, key must be an ed25519.PublicKey
func (m *SigningMethodEd25519) Verify(signingString, signature string, key interface{}) error { func (m *SigningMethodEd25519) Verify(signingString, signature string, key interface{}) error {
var err error var err error
@ -59,7 +59,7 @@ func (m *SigningMethodEd25519) Verify(signingString, signature string, key inter
return nil 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 // For this signing method, key must be an ed25519.PrivateKey
func (m *SigningMethodEd25519) Sign(signingString string, key interface{}) (string, error) { func (m *SigningMethodEd25519) Sign(signingString string, key interface{}) (string, error) {
var ed25519Key ed25519.PrivateKey var ed25519Key ed25519.PrivateKey

View File

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

View File

@ -9,11 +9,11 @@ import (
) )
var ( var (
ErrNotEdPrivateKey = errors.New("Key is not a valid Ed25519 private key") ErrNotEdPrivateKey = errors.New("key is not a valid Ed25519 private key")
ErrNotEdPublicKey = errors.New("Key is not a valid Ed25519 public 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) { func ParseEdPrivateKeyFromPEM(key []byte) (crypto.PrivateKey, error) {
var err error var err error
@ -38,7 +38,7 @@ func ParseEdPrivateKeyFromPEM(key []byte) (crypto.PrivateKey, error) {
return pkey, nil 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) { func ParseEdPublicKeyFromPEM(key []byte) (crypto.PublicKey, error) {
var err error var err error

View File

@ -27,7 +27,7 @@ const (
ValidationErrorClaimsInvalid // Generic claims validation error 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 { func NewValidationError(errorText string, errorFlags uint32) *ValidationError {
return &ValidationError{ return &ValidationError{
text: errorText, 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 { type ValidationError struct {
Inner error // stores the error returned by external dependencies, i.e.: KeyFunc Inner error // stores the error returned by external dependencies, i.e.: KeyFunc
Errors uint32 // bitfield. see ValidationError... constants Errors uint32 // bitfield. see ValidationError... constants
text string // errors that do not have a valid error just have text 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 { func (e ValidationError) Error() string {
if e.Inner != nil { if e.Inner != nil {
return e.Inner.Error() return e.Inner.Error()

View File

@ -4,7 +4,7 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/golang-jwt/jwt" "github.com/golang-jwt/jwt/v4"
) )
// Example (atypical) using the StandardClaims type by itself to parse a token. // 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" "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 // Expects key type of []byte for both signing and validation
type SigningMethodHMAC struct { type SigningMethodHMAC struct {
Name string Name string
@ -45,7 +45,7 @@ func (m *SigningMethodHMAC) Alg() string {
return m.Name 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 { func (m *SigningMethodHMAC) Verify(signingString, signature string, key interface{}) error {
// Verify the key is the right type // Verify the key is the right type
keyBytes, ok := key.([]byte) keyBytes, ok := key.([]byte)
@ -77,7 +77,7 @@ func (m *SigningMethodHMAC) Verify(signingString, signature string, key interfac
return nil return nil
} }
// Implements the Sign method from SigningMethod for this signing method. // Sign implements token signing for the SigningMethod.
// Key must be []byte // Key must be []byte
func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) (string, error) { func (m *SigningMethodHMAC) Sign(signingString string, key interface{}) (string, error) {
if keyBytes, ok := key.([]byte); ok { if keyBytes, ok := key.([]byte); ok {

View File

@ -5,7 +5,7 @@ import (
"io/ioutil" "io/ioutil"
"time" "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 // For HMAC signing method, the key can be any []byte. It is recommended to generate

View File

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

View File

@ -16,8 +16,8 @@ import (
"strings" "strings"
"time" "time"
"github.com/golang-jwt/jwt" "github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/request" "github.com/golang-jwt/jwt/v4/request"
) )
// location of the files used for signing and verification // location of the files used for signing and verification
@ -30,11 +30,6 @@ var (
verifyKey *rsa.PublicKey verifyKey *rsa.PublicKey
signKey *rsa.PrivateKey signKey *rsa.PrivateKey
serverPort int 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 // read the key files before starting http handlers
@ -65,8 +60,6 @@ func init() {
}() }()
} }
var start func()
func fatal(err error) { func fatal(err error) {
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)
@ -199,11 +192,11 @@ func authHandler(w http.ResponseWriter, r *http.Request) {
// only accessible with a valid token // only accessible with a valid token
func restrictedHandler(w http.ResponseWriter, r *http.Request) { func restrictedHandler(w http.ResponseWriter, r *http.Request) {
// Get token from 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, // since we only use the one private key to sign the tokens,
// we also only use its public counter part to verify // we also only use its public counter part to verify
return verifyKey, nil return verifyKey, nil
}) }, request.WithClaims(&CustomClaimsExample{}))
// If the token is missing or invalid, return error // If the token is missing or invalid, return error
if err != nil { if err != nil {
@ -214,5 +207,4 @@ func restrictedHandler(w http.ResponseWriter, r *http.Request) {
// Token is valid // Token is valid
fmt.Fprintln(w, "Welcome,", token.Claims.(*CustomClaimsExample).Name) fmt.Fprintln(w, "Welcome,", token.Claims.(*CustomClaimsExample).Name)
return
} }

View File

@ -6,7 +6,7 @@ import (
// "fmt" // "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 // This is the default claims type if you don't supply one
type MapClaims map[string]interface{} type MapClaims map[string]interface{}
@ -31,7 +31,7 @@ func (m MapClaims) VerifyAudience(cmp string, req bool) bool {
return verifyAud(aud, cmp, req) 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 // 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 { func (m MapClaims) VerifyExpiresAt(cmp int64, req bool) bool {
exp, ok := m["exp"] exp, ok := m["exp"]
@ -48,7 +48,7 @@ func (m MapClaims) VerifyExpiresAt(cmp int64, req bool) bool {
return false 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 // 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 { func (m MapClaims) VerifyIssuedAt(cmp int64, req bool) bool {
iat, ok := m["iat"] iat, ok := m["iat"]
@ -65,14 +65,14 @@ func (m MapClaims) VerifyIssuedAt(cmp int64, req bool) bool {
return false 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 // 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 { func (m MapClaims) VerifyIssuer(cmp string, req bool) bool {
iss, _ := m["iss"].(string) iss, _ := m["iss"].(string)
return verifyIss(iss, cmp, req) 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 // 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 { func (m MapClaims) VerifyNotBefore(cmp int64, req bool) bool {
nbf, ok := m["nbf"] nbf, ok := m["nbf"]
@ -89,7 +89,7 @@ func (m MapClaims) VerifyNotBefore(cmp int64, req bool) bool {
return false return false
} }
// Validates time based claims "exp, iat, nbf". // Valid calidates time based claims "exp, iat, nbf".
// There is no accounting for clock skew. // There is no accounting for clock skew.
// As well, if any of the above claims are not in the token, it will still // As well, if any of the above claims are not in the token, it will still
// be considered a valid claim. // be considered a valid claim.

View File

@ -1,6 +1,6 @@
package jwt 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. // but you probably should never use it.
var SigningMethodNone *signingMethodNone var SigningMethodNone *signingMethodNone

View File

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

View File

@ -13,7 +13,7 @@ type Parser struct {
SkipClaimsValidation bool // Skip claims validation during token parsing 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. // keyFunc will receive the parsed token and should return the key for validating.
// If everything is kosher, err will be nil // If everything is kosher, err will be nil
func (p *Parser) Parse(tokenString string, keyFunc Keyfunc) (*Token, error) { 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 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 // WARNING: Don't use this method unless you know what you're doing.
// 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's only ever useful in cases where you know the signature is valid (because it has
// it. // 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) { func (p *Parser) ParseUnverified(tokenString string, claims Claims) (token *Token, parts []string, err error) {
parts = strings.Split(tokenString, ".") parts = strings.Split(tokenString, ".")
if len(parts) != 3 { if len(parts) != 3 {

View File

@ -8,17 +8,17 @@ import (
"testing" "testing"
"time" "time"
"github.com/golang-jwt/jwt" "github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/test" "github.com/golang-jwt/jwt/v4/test"
) )
var keyFuncError error = fmt.Errorf("error loading key") var errKeyFuncError error = fmt.Errorf("error loading key")
var ( var (
jwtTestDefaultKey *rsa.PublicKey jwtTestDefaultKey *rsa.PublicKey
defaultKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return jwtTestDefaultKey, nil } defaultKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return jwtTestDefaultKey, nil }
emptyKeyFunc jwt.Keyfunc = func(t *jwt.Token) (interface{}, error) { return nil, 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 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) t.Errorf("[%v] Errors don't match expectation. %v != %v", data.name, e, data.errors)
} }
if err.Error() == keyFuncError.Error() && 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, keyFuncError) 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") 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. // The ExtractToken method should return a token string or an error.
// If no token is present, you must return ErrNoTokenInRequest. // If no token is present, you must return ErrNoTokenInRequest.
type Extractor interface { type Extractor interface {
ExtractToken(*http.Request) (string, error) ExtractToken(*http.Request) (string, error)
} }
// Extractor for finding a token in a header. Looks at each specified // HeaderExtractor is an extractor for finding a token in a header.
// header in order until there's a match // Looks at each specified header in order until there's a match
type HeaderExtractor []string type HeaderExtractor []string
func (e HeaderExtractor) ExtractToken(req *http.Request) (string, error) { func (e HeaderExtractor) ExtractToken(req *http.Request) (string, error) {
@ -31,7 +31,7 @@ func (e HeaderExtractor) ExtractToken(req *http.Request) (string, error) {
return "", ErrNoTokenInRequest 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. // GET URL arguments. Argument names are tried in order until there's a match.
// This extractor calls `ParseMultipartForm` on the request // This extractor calls `ParseMultipartForm` on the request
type ArgumentExtractor []string type ArgumentExtractor []string
@ -50,7 +50,7 @@ func (e ArgumentExtractor) ExtractToken(req *http.Request) (string, error) {
return "", ErrNoTokenInRequest 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 type MultiExtractor []Extractor
func (e MultiExtractor) ExtractToken(req *http.Request) (string, error) { func (e MultiExtractor) ExtractToken(req *http.Request) (string, error) {
@ -65,7 +65,7 @@ func (e MultiExtractor) ExtractToken(req *http.Request) (string, error) {
return "", ErrNoTokenInRequest 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 // See AuthorizationHeaderExtractor for an example
type PostExtractionFilter struct { type PostExtractionFilter struct {
Extractor Extractor

View File

@ -13,14 +13,14 @@ func stripBearerPrefixFromTokenString(tok string) (string, error) {
return tok, nil 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 // Uses PostExtractionFilter to strip "Bearer " prefix from header
var AuthorizationHeaderExtractor = &PostExtractionFilter{ var AuthorizationHeaderExtractor = &PostExtractionFilter{
HeaderExtractor{"Authorization"}, HeaderExtractor{"Authorization"},
stripBearerPrefixFromTokenString, 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. // header then 'access_token' argument for a token.
var OAuth2Extractor = &MultiExtractor{ var OAuth2Extractor = &MultiExtractor{
AuthorizationHeaderExtractor, AuthorizationHeaderExtractor,

View File

@ -3,10 +3,10 @@ package request
import ( import (
"net/http" "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 // 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 // instead of a token string. The Extractor interface allows you to define
// the logic for extracting a token. Several useful implementations are provided. // 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) return p.parser.ParseWithClaims(tokenString, p.claims, keyFunc)
} }
// ParseFromRequest but with custom Claims type // ParseFromRequestWithClaims is an alias for ParseFromRequest but with custom Claims type.
// DEPRECATED: use ParseFromRequest and the WithClaims option //
// 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) { 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)) return ParseFromRequest(req, extractor, keyFunc, WithClaims(claims))
} }
@ -54,14 +55,14 @@ type fromRequestParser struct {
type ParseFromRequestOption func(*fromRequestParser) type ParseFromRequestOption func(*fromRequestParser)
// Parse with custom claims // WithClaims parses with custom claims
func WithClaims(claims jwt.Claims) ParseFromRequestOption { func WithClaims(claims jwt.Claims) ParseFromRequestOption {
return func(p *fromRequestParser) { return func(p *fromRequestParser) {
p.claims = claims p.claims = claims
} }
} }
// Parse using a custom parser // WithParser parses using a custom parser
func WithParser(parser *jwt.Parser) ParseFromRequestOption { func WithParser(parser *jwt.Parser) ParseFromRequestOption {
return func(p *fromRequestParser) { return func(p *fromRequestParser) {
p.parser = parser p.parser = parser

View File

@ -8,8 +8,8 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/golang-jwt/jwt" "github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/test" "github.com/golang-jwt/jwt/v4/test"
) )
var requestTestData = []struct { var requestTestData = []struct {

6
rsa.go
View File

@ -6,7 +6,7 @@ import (
"crypto/rsa" "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 // Expects *rsa.PrivateKey for signing and *rsa.PublicKey for validation
type SigningMethodRSA struct { type SigningMethodRSA struct {
Name string Name string
@ -44,7 +44,7 @@ func (m *SigningMethodRSA) Alg() string {
return m.Name 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. // For this signing method, must be an *rsa.PublicKey structure.
func (m *SigningMethodRSA) Verify(signingString, signature string, key interface{}) error { func (m *SigningMethodRSA) Verify(signingString, signature string, key interface{}) error {
var err 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) 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. // For this signing method, must be an *rsa.PrivateKey structure.
func (m *SigningMethodRSA) Sign(signingString string, key interface{}) (string, error) { func (m *SigningMethodRSA) Sign(signingString string, key interface{}) (string, error) {
var rsaKey *rsa.PrivateKey var rsaKey *rsa.PrivateKey

View File

@ -8,7 +8,7 @@ import (
"crypto/rsa" "crypto/rsa"
) )
// Implements the RSAPSS family of signing methods signing methods // SigningMethodRSAPSS implements the RSAPSS family of signing methods signing methods
type SigningMethodRSAPSS struct { type SigningMethodRSAPSS struct {
*SigningMethodRSA *SigningMethodRSA
Options *rsa.PSSOptions 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 // For this verify method, key must be an rsa.PublicKey struct
func (m *SigningMethodRSAPSS) Verify(signingString, signature string, key interface{}) error { func (m *SigningMethodRSAPSS) Verify(signingString, signature string, key interface{}) error {
var err 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) 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 // For this signing method, key must be an rsa.PrivateKey struct
func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) (string, error) { func (m *SigningMethodRSAPSS) Sign(signingString string, key interface{}) (string, error) {
var rsaKey *rsa.PrivateKey var rsaKey *rsa.PrivateKey

View File

@ -9,8 +9,8 @@ import (
"testing" "testing"
"time" "time"
"github.com/golang-jwt/jwt" "github.com/golang-jwt/jwt/v4"
"github.com/golang-jwt/jwt/test" "github.com/golang-jwt/jwt/v4/test"
) )
var rsaPSSTestData = []struct { var rsaPSSTestData = []struct {

View File

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

View File

@ -8,12 +8,12 @@ import (
) )
var ( var (
ErrKeyMustBePEMEncoded = errors.New("Invalid Key: Key must be a PEM encoded PKCS1 or PKCS8 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") ErrNotRSAPrivateKey = errors.New("key is not a valid RSA private key")
ErrNotRSAPublicKey = errors.New("Key is not a valid RSA public 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) { func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) {
var err error var err error
@ -39,7 +39,11 @@ func ParseRSAPrivateKeyFromPEM(key []byte) (*rsa.PrivateKey, error) {
return pkey, nil 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) { func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) (*rsa.PrivateKey, error) {
var err error var err error
@ -71,7 +75,7 @@ func ParseRSAPrivateKeyFromPEMWithPassword(key []byte, password string) (*rsa.Pr
return pkey, nil 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) { func ParseRSAPublicKeyFromPEM(key []byte) (*rsa.PublicKey, error) {
var err error var err error

View File

@ -7,14 +7,14 @@ import (
var signingMethods = map[string]func() SigningMethod{} var signingMethods = map[string]func() SigningMethod{}
var signingMethodLock = new(sync.RWMutex) 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 { type SigningMethod interface {
Verify(signingString, signature string, key interface{}) error // Returns nil if signature is valid 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 Sign(signingString string, key interface{}) (string, error) // Returns encoded signature or error
Alg() string // returns the alg identifier for this method (example: 'HS256') 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 // This is typically done during init() in the method's implementation
func RegisterSigningMethod(alg string, f func() SigningMethod) { func RegisterSigningMethod(alg string, f func() SigningMethod) {
signingMethodLock.Lock() signingMethodLock.Lock()
@ -23,7 +23,7 @@ func RegisterSigningMethod(alg string, f func() SigningMethod) {
signingMethods[alg] = f 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) { func GetSigningMethod(alg string) (method SigningMethod) {
signingMethodLock.RLock() signingMethodLock.RLock()
defer signingMethodLock.RUnlock() 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" "crypto/rsa"
"io/ioutil" "io/ioutil"
"github.com/golang-jwt/jwt" "github.com/golang-jwt/jwt/v4"
) )
func LoadRSAPrivateKeyFromDisk(location string) *rsa.PrivateKey { func LoadRSAPrivateKeyFromDisk(location string) *rsa.PrivateKey {

View File

@ -12,13 +12,13 @@ import (
// server uses a different time zone than your tokens. // server uses a different time zone than your tokens.
var TimeFunc = time.Now 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, // the key for verification. The function receives the parsed,
// but unverified Token. This allows you to use properties in the // but unverified Token. This allows you to use properties in the
// Header of the token (such as `kid`) to identify which key to use. // Header of the token (such as `kid`) to identify which key to use.
type Keyfunc func(*Token) (interface{}, error) 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. // creating or parsing/verifying a token.
type Token struct { type Token struct {
Raw string // The raw token. Populated when you Parse a token 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 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 { func New(method SigningMethod) *Token {
return NewWithClaims(method, MapClaims{}) 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) { func (t *Token) SignedString(key interface{}) (string, error) {
var sig, sstr string var sig, sstr string
var err error var err error
@ -58,7 +58,7 @@ func (t *Token) SignedString(key interface{}) (string, error) {
return strings.Join([]string{sstr, sig}, "."), nil 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 // most expensive part of the whole deal. Unless you
// need this for something special, just go straight for // need this for something special, just go straight for
// the SignedString. // the SignedString.
@ -82,7 +82,7 @@ func (t *Token) SigningString() (string, error) {
return strings.Join(parts, "."), nil 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. // keyFunc will receive the parsed token and should return the key for validating.
// If everything is kosher, err will be nil // If everything is kosher, err will be nil
func Parse(tokenString string, keyFunc Keyfunc) (*Token, error) { 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) 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 { func EncodeSegment(seg []byte) string {
return base64.RawURLEncoding.EncodeToString(seg) 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) { func DecodeSegment(seg string) ([]byte, error) {
return base64.RawURLEncoding.DecodeString(seg) return base64.RawURLEncoding.DecodeString(seg)
} }