Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adds go module support /v4 #41

Merged
merged 14 commits into from
Aug 3, 2021
17 changes: 12 additions & 5 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -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:
Expand All @@ -28,6 +38,3 @@ jobs:
go vet ./...
go test -v ./...
go build ./...
env:
GO111MODULE: auto
GOPATH: ${{ github.workspace }}
22 changes: 11 additions & 11 deletions MIGRATION_GUIDE.md
Original file line number Diff line number Diff line change
@@ -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.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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

Expand Down
4 changes: 4 additions & 0 deletions VERSION_HISTORY.md
Original file line number Diff line number Diff line change
@@ -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)).
Expand Down
17 changes: 8 additions & 9 deletions claims.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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 {
Expand Down Expand Up @@ -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)
Expand Down
3 changes: 1 addition & 2 deletions cmd/jwt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
23 changes: 0 additions & 23 deletions cmd/jwt/args.go

This file was deleted.

54 changes: 35 additions & 19 deletions cmd/jwt/app.go → cmd/jwt/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
"regexp"
"strings"

"github.com/golang-jwt/jwt"
"github.com/golang-jwt/jwt/v4"
)

var (
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -172,15 +172,15 @@ 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))
}

// 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
Expand All @@ -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
Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
}
Loading