Git Product home page Git Product logo

jwt's Introduction

API Documentation Build Status

About

… a JSON Web Token (JWT) library for the Go programming language.

  • Feature complete
  • Full test coverage
  • Dependency free
  • Key management

The API enforces secure use by design. Unsigned tokens are rejected. No support for encrypted tokens either—use wire encryption instead.

This is free and unencumbered software released into the public domain.

Introduction

Tokens encapsulate signed statements called claims. A claim is a named JSON value. Applications using JWTs should define which specific claims they use and when they are required or optional.

var claims jwt.Claims
claims.Subject = "alice"
claims.Issued  = jwt.NewNumericTime(time.Now().Round(time.Second))
claims.Set     = map[string]interface{}{"email_verified": false}
// issue a JWT
token, err := claims.EdDSASign(JWTPrivateKey)

Tokens consists of printable ASCII characters, e.g., eyJhbGciOiJFUzI1NiJ9.eyJzdWIiOiJha3JpZWdlciIsInByZWZpeCI6IkRyLiJ9.RTOboYsLW7zXFJyXtIypOmXfuRGVT_FpDUTs2TOuK73qZKm56JcESfsl_etnBsl7W80TXE5l5qecrMizh3XYmw. Secured resources can use such tokens to determine the respective permissions. Note how the verification process is self-contained with just a public key.

// verify a JWT
claims, err := jwt.EdDSACheck(token, JWTPublicKey)
if err != nil {
	log.Print("credentials rejected: ", err)
	return
}
err = claims.AcceptTemporal(time.Now(), time.Second)
if err != nil {
	log.Print("credential constraints violated: ", err)
	return
}

// ready for use
log.Print("hello ", claims.Subject)
if verified, _ := claims.Set["email_verified"].(bool); !verified {
	log.Print("e-mail confirmation pending")
}

Commonly, agents receive a JWT uppon authentication/login. Then, that token is included with requests to the secured resources, as a proof of authority. Token access is “eyes only” in such scenario. Include and enforce more context detail with claims to further reduce risk. E.g., a session identifier or a fingerprint of the client's TLS key can prevent usage of any hijacked tokens.

High-Level API

Server-side security can be applied with a standard http.Handler setup. The following example denies requests to MyAPI when the JWT is not valid, or when the JWT is missing either the subject, formatted name or roles claim.

// define trusted credentials
var keys jwt.KeyRegister
n, err := keys.LoadPEM(text, nil)
if err != nil {
	log.Fatal(err)
}
log.Print("setup with ", n, " JWT keys")

http.Handle("/api/v1", &jwt.Handler{
	Target: MyAPI, // protected HTTP handler
	Keys:   &keys,

	// map two claims to HTTP headers
	HeaderPrefix: "X-Verified-",
	HeaderBinding: map[string]string{
		"sub": "X-Verified-User", // registered [standard] claim
		"fn":  "X-Verified-Name", // private [custom] claim
	},

	// map another claim with custom logic
	Func: func(w http.ResponseWriter, req *http.Request, claims *jwt.Claims) (pass bool) {
		log.Printf("got a valid JWT %q for %q", claims.ID, claims.Audiences)

		// map role enumeration
		s, ok := claims.String("roles")
		if !ok {
			http.Error(w, "jwt: want roles claim as a string", http.StatusForbidden)
			return false
		}
		req.Header["X-Verified-Roles"] = strings.Fields(s)

		return true
	},
})

When all applicable JWT claims are mapped to HTTP request headers, then the service logic can stay free of verification code, plus easier unit testing.

// Greeting is a standard HTTP handler fuction.
func Greeting(w http.ResponseWriter, req *http.Request) {
	fmt.Fprintf(w, "Hello %s!\n", req.Header.Get("X-Verified-Name"))
	fmt.Fprintf(w, "You are authorized as %s.\n", req.Header.Get("X-Verified-User"))
}

The validated Claims object may also be exposed through the request context.

Performance

The following results were measured with Go 1.20.3 on an Apple M1.

ECDSA/sign-ES256-8         19.88µ ± 0%
ECDSA/sign-ES384-8         182.2µ ± 0%
ECDSA/check-ES256-8        58.65µ ± 0%
ECDSA/check-ES384-8        535.2µ ± 0%
EdDSA/sign-EdDSA-8         21.30µ ± 1%
EdDSA/check-EdDSA-8        47.12µ ± 1%
HMAC/sign-HS256-8          660.1n ± 0%
HMAC/sign-HS256-reuse-8    458.3n ± 1%
HMAC/sign-HS384-8          1.028µ ± 0%
HMAC/sign-HS384-reuse-8    600.4n ± 0%
HMAC/sign-HS512-8          1.053µ ± 0%
HMAC/sign-HS512-reuse-8    616.6n ± 0%
HMAC/check-HS256-8         1.826µ ± 0%
HMAC/check-HS256-reuse-8   1.611µ ± 1%
HMAC/check-HS384-8         2.271µ ± 1%
HMAC/check-HS384-reuse-8   1.786µ ± 1%
HMAC/check-HS512-8         2.287µ ± 1%
HMAC/check-HS512-reuse-8   1.803µ ± 0%
RSA/sign-1024-bit-8        292.8µ ± 1%
RSA/sign-2048-bit-8        1.273m ± 0%
RSA/sign-4096-bit-8        8.685m ± 1%
RSA/check-1024-bit-8       49.51µ ± 3%
RSA/check-2048-bit-8       168.6µ ± 0%
RSA/check-4096-bit-8       662.6µ ± 0%

EdDSA [Ed25519] produces small signatures and it performs well.

Standard Compliance

  • RFC 2617: “HTTP Authentication”
  • RFC 6750: “The OAuth 2.0 Authorization Framework: Bearer Token Usage”
  • RFC 7468: “Textual Encodings of PKIX, PKCS, and CMS Structures”
  • RFC 7515: “JSON Web Signature (JWS)”
  • RFC 7517: “JSON Web Key (JWK)”
  • RFC 7518: “JSON Web Algorithms (JWA)”
  • RFC 7519: “JSON Web Token (JWT)”
  • RFC 8037: “CFRG Elliptic Curve Diffie-Hellman (ECDH) and Signatures in JSON Object Signing and Encryption (JOSE)”

JWT.io

jwt's People

Contributors

krylphi avatar pascaldekloe avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jwt's Issues

Feature/example request

This library looks very promising, however, to make it really useful, I have two questions:

  1. can you provide a convenient method to convert a JSON string into the jwt.Claims structure?
  2. how can I verify a jwt token if I have a private string typed password?

For 1, you can argue that it's not this project's responsibility to do it, that's fine. But for 2, I cannot believe it's not documented in the readme.md. This is the most fundamental use of jwt. I think if your project is better documented, this project will gain 50x more popularity. I have been here several times and was turned off by lacking of useful examples every time. This time I finally decided to open this ticket. Thanks.

claims.Set int entries are treated as float64

So I'm setting some integer values in Set, and when I receive back the JWT and decode it they are treated as float64 so when I do c.Set["something"].(int) the compiler complains about Panic caught: interface conversion: interface {} is float64, not int

Use semver to support go module

If you try to use this lib with go 1.11's module system the latest release it will download is v1.2.1. Go modules require tags to be formatted as vx.y.z where x is MAJOR, y is MINOR and z is the PATCH number. Could you migrate tags and releases to semver-formatted strings?

How to encode/decode ed25519 keys

Must these be stored in binary in a file? I want to persist them to a file, but so far have not been able to encode/decode as PEM, or even base64. They are always corrupt when I read them back in.

If I try to generate the keys from openssl or ssh-keygen, I'm also not able to read those in as valid ed25519 keys.

The test I use is to generate them in Go, then try to encode them, decode them, and re-run a sign/verify.

Microsecond Normalization

Hi.
Have configured all timestamps in microseconds.
But in library i have seen only Unix Timestamp in seconds is used, have found an option for TimeFunc(), but with that only Timezone can be changed.

Can anyone help me on this? or any workaround for the same?

While debugging,

Time configured as Microseconds in token:
image

var TimeFunc = time.Now
now := TimeFunc().Unix()

Current time in Seconds:
image

P.s, Apologies if i didnt follow standard way of raising concern

Unexported errors

I'm curious as to why some of potential return errors from HMACCheckHeader aren't exported. This includes errAuthHeader, and errAuthSchema. Since they aren't exported I can't compare against them in my middleware.

I need to handle differently the situations where an invalid token is submitted and no token is submitted. I could just duplicate the code, but those errors are already being returned. To take advantage of them, I'd need to do string comparison, which is frowned upon.

Any interest in exporting these errors?

Remove goe dependency

Thanks for your work on this package.

In the README it says the package uses no third-party dependencies, but the go.mod file lists the dependency github.com/pascaldekloe/goe.

From a quick check it looks like the only place goe is being used is the following line:

jwt/x/x_test.go

Line 134 in fcba0b3

verify.Values(t, gold.Serial, keys, gold.Keys)

I was wondering if the test could be refactored to inline any necessary code, instead of pulling through the whole dependency?

unknown import path "crypto/ed25519"

go: downloading github.com/pascaldekloe/jwt v1.8.0
go: extracting github.com/pascaldekloe/jwt v1.8.0
.cache/pkg/mod/github.com/pascaldekloe/[email protected]/check.go:6:2: unknown import path "crypto/ed25519": cannot find module providing package crypto/ed25519

docker image golang:1.13

Crypto Go :we are a research group to help developers build secure applications.

Hi, we are a research group to help developers build secure applications. We designed a cryptographic misuse detector (i.e., CryptoGo) on Go language. We found your great public repository from Github, and several security issues detected by CryptoGo are shown in the following.
Note that the cryptographic algorithms are categorized with two aspects: security strength and security vulnerability based on NIST Special Publication 800-57 and other public publications. Moreover, CryptoGo defined certain rules derived from the APIs of Go cryptographic library and other popular cryptographic misuse detectors. The specific security issues we found are as follows:
Location: sign.go:174;
Broken rule: RSASSA-PKCS1-v1_5 is deprecated;
We wish the above security issues could truly help you to build a secure application. If you have any concern or suggestion, please feel free to contact us, we are looking forward to your reply. Thanks.

Abstract signing

Feature Request.
I can make a call to Azure keyvault to sign and what I get back are the following ;

  1. kid
  2. base64 url encoded signature
  3. alg, i.e. "RSA256" passed in

Could you think about putting the signing stuff into an interface and letting me implement that on my end. I would still expect your code to construct the JWT ({0}.{1}.{signature})

That way we could also reduce what looks like redundant code in all the *Sign() functions.

my POC function looks like this, and would change based upon the interface requirements of your engine;

// HARD CODED to SHA256 at the moment

func RSA256AzureSign(ctx context.Context, data []byte) (kid *string, signature *string, err error) {
	keyClient := getKeysClient()
	digest := crypto.SHA256.New()
	digest.Write(data)
	h := digest.Sum(nil)
	sEnc := b64.StdEncoding.EncodeToString(h)

	keyOperationResult, err := keyClient.Sign(ctx, "https://P7KeyValut.vault.azure.net/", "P7IdentityServer4SelfSigned", "", keyvault.KeySignParameters{
		Algorithm: keyvault.RS256,
		Value:     &sEnc,
	})
	if err != nil {
		return
	}
	return keyOperationResult.Kid, keyOperationResult.Result, nil
}

The call to azure picks the latest version of the cert and signs for me, returning the kid and the base64 signature.

Audiences are represented as string if claims.Set is used

Hi,
at first, thank you for this awesome library!
But whenever I use claims.Set = map[string]interface{}{"role": "userrole",} audiences are stated as a string instead of an array.

E.g.:

{
  "aud": "audience.org",
  "exp": 1897992150.1938002,
  "iat": 1582275750,
  "iss": "issuer.org",
  "role": "userrole",
  "sub": "0ff88b48-231c-4862-8fcf-56c7fce32400"
}

vs.

{
  "aud": [
           "audience.org"
         ],
  "exp": 1897992150.1938002,
  "iat": 1582275750,
  "iss": "issuer.org",
  "sub": "0ff88b48-231c-4862-8fcf-56c7fce32400"
}

Missing Ed25519 package

Hey there! Love your package. It's very simple and straight-forward. I prefer it to other JWT packages thanks to its API. Great job!

I only have one problem. I have jwt in my project and it's in my go.mod and in go.sum. Every time I try to run go test -v -count=1 ./... in my root directory, it complains about jwt's imported library and fails:

myproject:master* λ go test -v -count=1 ./...
../../pascaldekloe/jwt/check.go:6:2: cannot find package "crypto/ed25519" in any of:
	/usr/lib/go/src/crypto/ed25519 (from $GOROOT)
	/home/myusername/go/src/crypto/ed25519 (from $GOPATH)

crypto/ed25519 exists on my system:

ed25519:master λ pwd
/home/myusername/go/src/golang.org/x/crypto/ed25519

Is there something wrong with my system variables or import paths?

This problem doesn't occur with any other packages.

Thanks!

👋🏽 Updated benchmark results

I ran benchmarks on my M1 with Go 1.20.3 and the results seem to be a bit faster than what's in the README:

> uname -a
Darwin Jonathans-MacBook-Air.local 22.4.0 Darwin Kernel Version 22.4.0: Mon Mar  6 21:00:41 PST 2023; root:xnu-8796.101.5~3/RELEASE_ARM64_T8103 arm64 arm Darwin

> go version
go version go1.20.3 darwin/arm64

> go test -o testbench
> ./testbench -test.bench . -test.count 6 > result
> ~/go/bin/benchstat - < result

ECDSA/sign-ES256-8         19.88µ ± 0%
ECDSA/sign-ES384-8         182.2µ ± 0%
ECDSA/check-ES256-8        58.65µ ± 0%
ECDSA/check-ES384-8        535.2µ ± 0%
EdDSA/sign-EdDSA-8         21.30µ ± 1%
EdDSA/check-EdDSA-8        47.12µ ± 1%
HMAC/sign-HS256-8          660.1n ± 0%
HMAC/sign-HS256-reuse-8    458.3n ± 1%
HMAC/sign-HS384-8          1.028µ ± 0%
HMAC/sign-HS384-reuse-8    600.4n ± 0%
HMAC/sign-HS512-8          1.053µ ± 0%
HMAC/sign-HS512-reuse-8    616.6n ± 0%
HMAC/check-HS256-8         1.826µ ± 0%
HMAC/check-HS256-reuse-8   1.611µ ± 1%
HMAC/check-HS384-8         2.271µ ± 1%
HMAC/check-HS384-reuse-8   1.786µ ± 1%
HMAC/check-HS512-8         2.287µ ± 1%
HMAC/check-HS512-reuse-8   1.803µ ± 0%
RSA/sign-1024-bit-8        292.8µ ± 1%
RSA/sign-2048-bit-8        1.273m ± 0%
RSA/sign-4096-bit-8        8.685m ± 1%
RSA/check-1024-bit-8       49.51µ ± 3%
RSA/check-2048-bit-8       168.6µ ± 0%
RSA/check-4096-bit-8       662.6µ ± 0%

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.