README

JWT

build status gocov report card godocs

Fast and simple JWT implementation written in Go. This package was designed with security, performance and simplicity in mind, it protects your tokens from critical vulnerabilities that you may find in other libraries.

Benchmarks Total Repetitions - higher is better

Please star this open source project to attract more developers so that together we can improve it even more!

Installation

The only requirement is the Go Programming Language.

$ go get github.com/kataras/jwt

Import as import "github.com/kataras/jwt" and use it as jwt.XXX.

Table of Contents

Getting Started

Sign and generate a token with the Sign method, returns the token in compact form. Optionally set an expiration, if "exp" is missing from the payload use the jwt.MaxAge helper. Verify the token with the Verify method, returns a VerifiedToken value. Decode the custom claims with the VerifiedToken.Claims method. Extremely easy!

package main

import (
	"time"

	"github.com/kataras/jwt"
)

// Keep it secret.
var sharedKey = []byte("sercrethatmaycontainch@r$32chars")

type FooClaims struct {
	Foo string `json:"foo"`
}

func main() {
	// Generate a token which expires at 15 minutes from now:
	myClaims := FooClaims{
		Foo: "bar",
	} // can be a map too.

	token, err := jwt.Sign(jwt.HS256, sharedKey, myClaims, jwt.MaxAge(15*time.Minute))
	if err != nil {
		panic(err)
	}

	// Verify and extract claims from a token:
	verifiedToken, err := jwt.Verify(jwt.HS256, sharedKey, token)
	if err != nil {
		panic(err)
	}

	var claims FooClaims
	err = verifiedToken.Claims(&claims)
	if err != nil {
		panic(err)
	}

	print(claims.Foo)
}

The package contains comments on each one of its exported functions, structures and variables, therefore, for a more detailed technical documentation please refer to godocs.

Sign a Token

Signing and Verifying a token is an extremely easy process.

Signing a Token is done through the Sign package-level function.

var sharedKey = []byte("sercrethatmaycontainch@r$32chars")
type User struct {
    Username string `json:"username"`
}
userClaims := User {
    Username:"kataras",
}

token, err := jwt.Sign(jwt.HS256, sharedkey, userClaims, jwt.MaxAge(15 *time.Minute))

[1] The first argument is the signing algorithm to create the signature part. [2] The second argument is the private key (or shared key, when symmetric algorithm was chosen) will be used to create the signature. [3] The third argument is the JWT claims. The JWT claims is the payload part and it depends on your application's requirements, there you can set custom fields (and expiration) that you can extract to another request of the same authorized client later on. Note that the claims can be any Go type, including custom struct, map and raw []byte. [4] The last variadic argument is a type of SignOption (MaxAge function and Claims struct are both valid sign options), can be used to merge custom claims with the standard ones. Returns the encoded token, ready to be sent and stored to the client.

The jwt.MaxAge is a helper which sets the jwt.Claims.Expiry and jwt.Claims.IssuedAt for you.

Example Code to manually set all claims using a standard map:

now := time.Now()
claims := map[string]interface{}{
    "iat": now.Unix(),
    "exp": now.Add(15 * time.Minute).Unix(),
    "foo": "bar",
}

token, err := jwt.Sign(jwt.HS256, sharedKey, claims)

Example Code to merge map claims with standard claims:

customClaims := jwt.Map{"foo": "bar"}

now := time.Now()
standardClaims := jwt.Claims{
    Expiry:   now.Add(15 * time.Minute).Unix(),
    IssuedAt: now.Unix(), 
    Issuer:   "my-app",
}

token, err := jwt.Sign(jwt.HS256, sharedKey, customClaims, standardClaims)

The jwt.Map is just a type alias, a shortcut, of map[string]interface{}.

At all cases, the iat(IssuedAt) and exp(Expiry/MaxAge) (and nbf(NotBefore)) values will be validated automatically on the Verify method.

Example Code to Sign & Verify a non-JSON payload:

token, err := jwt.Sign(jwt.HS256, sharedkey, []byte("raw payload - no json here"))

If the payload is not a JSON one, then merging with standard claims is not possible, therefore options like jwt.MaxAge are not available.

verifiedToken, err := jwt.Verify(jwt.HS256, sharedKey, token, jwt.Plain)
// verifiedToken.Payload == raw contents

Again, if the received payload is not a JSON one, options like jwt.Expected or jwt.NewBlocklist are not available as well.

The standard JWT Claims

The jwt.Claims we've shown above, looks like this:

type Claims struct {
    // The opposite of the exp claim. A number representing a specific
    // date and time in the format “seconds since epoch” as defined by POSIX.
    // This claim sets the exact moment from which this JWT is considered valid.
    // The current time (see `Clock` package-level variable)
    // must be equal to or later than this date and time.
    NotBefore int64 `json:"nbf,omitempty"`

    // A number representing a specific date and time (in the same
    // format as exp and nbf) at which this JWT was issued.
    IssuedAt int64 `json:"iat,omitempty"`

    // A number representing a specific date and time in the
    // format “seconds since epoch” as defined by POSIX6.
    // This claims sets the exact moment from which
    // this JWT is considered invalid. This implementation
    // allow for a certain skew between clocks
    // (by considering this JWT to be valid for a few minutes
    // after the expiration date, modify the `Clock` variable).
    Expiry int64 `json:"exp,omitempty"`

    // A string representing a unique identifier for this JWT.
    // This claim may be used to differentiate JWTs with
    // other similar content (preventing replays, for instance).
    ID string `json:"jti,omitempty"`

    // A string or URI that uniquely identifies the party
    // that issued the JWT.
    // Its interpretation is application specific
    // (there is no central authority managing issuers).
    Issuer string `json:"iss,omitempty"`

    // A string or URI that uniquely identifies the party
    // that this JWT carries information about.
    // In other words, the claims contained in this JWT
    // are statements about this party.
    // The JWT spec specifies that this claim must be unique in
    // the context of the issuer or,
    // in cases where that is not possible, globally unique. Handling of
    // this claim is application specific.
    Subject string `json:"sub,omitempty"`

    // Either a single string or URI or an array of such
    // values that uniquely identify the intended recipients of this JWT.
    // In other words, when this claim is present, the party reading
    // the data in this JWT must find itself in the aud claim or
    // disregard the data contained in the JWT.
    // As in the case of the iss and sub claims, this claim is
    // application specific.
    Audience []string `json:"aud,omitempty"`
}

Verify a Token

Verifying a Token is done through the Verify package-level function.

verifiedToken, err := jwt.Verify(jwt.HS256, sharedKey, token)

The VerifiedToken carries the token decoded information:

type VerifiedToken struct {
    Token          []byte // The original token.
    Header         []byte // The header (decoded) part.
    Payload        []byte // The payload (decoded) part.
    Signature      []byte // The signature (decoded) part.
    StandardClaims Claims // Standard claims extracted from the payload.
}
Decode custom Claims

To extract any custom claims, given on the Sign method, we use the result of the Verify method, which is a VerifiedToken pointer. This VerifiedToken has a single method, the Claims(dest interface{}) error one, which can be used to decode the claims (payload part) to a value of our choice. Again, that value can be a map or any struct.

var claims = struct {
    Foo string `json:"foo"`
}{} // or a map.

err := verifiedToken.Claims(&claims)

By default expiration set and validation is done through time.Now(). You can change that behavior through the jwt.Clock variable, e.g.

jwt.Clock = time.Now().UTC()
JSON required tag

When more than one token with different claims can be generated based on the same algorithm and key, somehow you need to invalidate a token if its payload misses one or more fields of your custom claims structure. Although it's not recommended to use the same algorithm and key for generating two different types of tokens, you can do it, and to avoid invalid claims to be retrieved by your application's route handler this package offers the JSON ,required tag field. It checks if the claims extracted from the token's payload meet the requirements of the expected struct value.

The first thing we have to do is to change the default jwt.Unmarshal variable to the jwt.UnmarshalWithRequired, once at the init of the application:

func init() {
    jwt.Unmarshal = jwt.UnmarshalWithRequired
}

The second thing, is to add the ,required json tag field to our struct, e.g.

type userClaims struct {
    Username string `json:"username,required"`
}

That's all, the VerifiedToken.Claims method will throw an ErrMissingKey if the given token's payload does not meet the requirements.

Standard Claims Validators

A more performance-wise alternative to json:"XXX,required" is to add validators to check the standard claims values through a TokenValidator or to check the custom claims manually after the VerifiedToken.Claims method.

The TokenValidator interface looks like this:

type TokenValidator interface {
	ValidateToken(token []byte, standardClaims Claims, err error) error
}

The last argument of Verify/VerifyEncrypted optionally accepts one or more TokenValidator. Available builtin validators:

  • Leeway(time.Duration)
  • Expected
  • Blocklist

The Leeway adds validation for a leeway expiration time. If the token was not expired then a comparison between this "leeway" and the token's "exp" one is expected to pass instead (now+leeway > exp). Example of use case: disallow tokens that are going to be expired in 3 seconds from now, this is useful to make sure that the token is valid when the when the user fires a database call:

verifiedToken, err := jwt.Verify(jwt.HS256, sharedKey, token, jwt.Leeway(3*time.Second))
if err != nil {
   // err == jwt.ErrExpired
}

The Expected performs simple checks between standard claims values. For example, disallow tokens that their "iss" claim does not match the "my-app" value:

verifiedToken, err := jwt.Verify(jwt.HS256, sharedKey, token, jwt.Expected{
    Issuer: "my-app",
})
if err != nil {
    // errors.Is(jwt.ErrExpected, err)
}

Block a Token

When a user logs out, the client app should delete the token from its memory. This would stop the client from being able to make authorized requests. But if the token is still valid and somebody else has access to it, the token could still be used. Therefore, a server-side invalidation is indeed useful for cases like that. When the server receives a logout request, take the token from the request and store it to the Blocklist through its InvalidateToken method. For each authorized request the jwt.Verify will check the Blocklist to see if the token has been invalidated. To keep the search space small, the expired tokens are automatically removed from the Blocklist's in-memory storage.

Enable blocklist by following the three simple steps below.

1. Initialize a blocklist instance, clean unused and expired tokens every 1 hour.

blocklist := jwt.NewBlocklist(1 * time.Hour)

2. Add the blocklist instance to the jwt.Verify's last argument, to disallow blocked entries.

verifiedToken, err := jwt.Verify(jwt.HS256, sharedKey, token, blocklist)
// [err == jwt.ErrBlocked when the token is valid but was blocked]

3. Call the blocklist.InvalidateToken whenever you want to block a specific authorized token. The method accepts the token and the expiration time should be removed from the blocklist.

blocklist.InvalidateToken(verifiedToken.Token, verifiedToken.StandardClaims)

By default the unique identifier is retrieved through the "jti" (Claims{ID}) and if that it's empty then the raw token is used as the map key instead. To change that behavior simply modify the blocklist.GetKey field before the InvalidateToken method.

Token Pair

A Token pair helps us to handle refresh tokens. It is a structure which holds both Access Token and Refresh Token. Refresh Token is long-live and access token is short-live. The server sends both of them at the first contact. The client uses the access token to access an API. The client can renew its access token by hitting a special REST endpoint to the server. The server verifies the refresh token and optionally the access token which should return ErrExpired, if it's expired or going to be expired in some time from now (Leeway), and renders a new generated token to the client. There are countless resources online and different kind of methods for using a refresh token. This jwt package offers just a helper structure which holds both the access and refresh tokens and it's ready to be sent and received to and from a client.

type ClientClaims struct {
    ClientID string `json:"client_id"`
}
accessClaims := ClientClaims{ClientID: "client-id"}
accessToken, err := jwt.Sign(alg, secret, accessClaims, jwt.MaxAge(10*time.Minute))
if err != nil {
    // [handle error...]
}

refreshClaims := jwt.Claims{Subject: "client", Issuer: "my-app"}
refreshToken, err := jwt.Sign(alg, secret, refreshClaims, jwt.MaxAge(time.Hour))
if err != nil {
    // [handle error...]
}

tokenPair := jwt.NewTokenPair(accessToken, refreshToken)

The tokenPair is JSON-compatible value, you can render it to a client and read it from a client HTTP request.

JSON Web Algorithms

There are several types of signing algorithms available according to the JWA(JSON Web Algorithms) spec. The specification requires a single algorithm to be supported by all conforming implementations:

  • HMAC using SHA-256, called HS256 in the JWA spec.

The specification also defines a series of recommended algorithms:

  • RSASSA PKCS1 v1.5 using SHA-256, called RS256 in the JWA spec.
  • ECDSA using P-256 and SHA-256, called ES256 in the JWA spec.

The implementation supports all of the above plus RSA-PSS and the new Ed25519. Navigate to the alg.go source file for details. In-short:

Algorithm jwt.Sign jwt.Verify
jwt.HS256 / HS384 / HS512 []byte The same sign key
jwt.RS256 / RS384 / RS512 *rsa.PrivateKey *rsa.PublicKey
jwt.PS256 / PS384 / PS512 *rsa.PrivateKey *rsa.PublicKey
jwt.ES256 / ES384 / ES512 *ecdsa.PrivateKey *ecdsa.PublicKey
jwt.EdDSA ed25519.PrivateKey ed25519.PublicKey
Choose the right Algorithm

Choosing the best algorithm for your application needs is up to you, however, my recommendations follows.

  • Already work with RSA public and private keys? Choose RSA(RS256/RS384/RS512/PS256/PS384/PS512) (length of produced token characters is bigger).
  • If you need the separation between public and private key, choose ECDSA(ES256/ES384/ES512) or EdDSA. ECDSA and EdDSA produce smaller tokens than RSA.
  • If you need performance and well-tested algorithm, choose HMAC(HS256/HS384/HS512) - the most common method.

The basic difference between symmetric and an asymmetric algorithm is that symmetric uses one shared key for both signing and verifying a token, and the asymmetric uses private key for signing and a public key for verifying. In general, asymmetric data is more secure because it uses different keys for the signing and verifying process but it's slower than symmetric ones.

Use your own Algorithm

If you ever need to use your own JSON Web algorithm, just implement the Alg interface. Pass it on jwt.Sign and jwt.Verify functions and you're ready to GO.

Generate keys

Keys can be generated via OpenSSL or through Go's standard library.

import (
    "crypto/rand"
    "crypto/rsa"
    "crypto/elliptic"
    "crypto/ed25519"
)
// Generate HMAC
sharedKey := make([]byte, 32)
_, _ = rand.Read(sharedKey)

// Generate RSA
bitSize := 2048
privateKey, _ := rsa.GenerateKey(rand.Reader, bitSize)
publicKey := &privateKey.PublicKey

// Generace ECDSA
c := elliptic.P256()
privateKey, _ := ecdsa.GenerateKey(c, rand.Reader)
publicKey := &privateKey.PublicKey

// Generate EdDSA
publicKey, privateKey, _ := ed25519.GenerateKey(rand.Reader)
Load and Parse keys

This package contains all the helpers you need to load and parse PEM-formatted keys.

All the available helpers:

// HMAC
MustLoadHMAC(filenameOrRaw string) []byte
// RSA
MustLoadRSA(privFile, pubFile string) (*rsa.PrivateKey, *rsa.PublicKey)
LoadPrivateKeyRSA(filename string) (*rsa.PrivateKey, error)
LoadPublicKeyRSA(filename string) (*rsa.PublicKey, error) 
ParsePrivateKeyRSA(key []byte) (*rsa.PrivateKey, error)
ParsePublicKeyRSA(key []byte) (*rsa.PublicKey, error)
// ECDSA
MustLoadECDSA(privFile, pubFile string) (*ecdsa.PrivateKey, *ecdsa.PublicKey)
LoadPrivateKeyECDSA(filename string) (*ecdsa.PrivateKey, error)
LoadPublicKeyECDSA(filename string) (*ecdsa.PublicKey, error) 
ParsePrivateKeyECDSA(key []byte) (*ecdsa.PrivateKey, error)
ParsePublicKeyECDSA(key []byte) (*ecdsa.PublicKey, error)
// EdDSA
MustLoadEdDSA(privFile, pubFile string) (ed25519.PrivateKey, ed25519.PublicKey)
LoadPrivateKeyEdDSA(filename string) (ed25519.PrivateKey, error)
LoadPublicKeyEdDSA(filename string) (ed25519.PublicKey, error)
ParsePrivateKeyEdDSA(key []byte) (ed25519.PrivateKey, error)
ParsePublicKeyEdDSA(key []byte) (ed25519.PublicKey, error)

Example Code:

import "github.com/kataras/jwt"
privateKey, publicKey := jwt.MustLoadEdDSA("./private_key.pem", "./public_key.pem")
claims := jwt.Map{"foo": "bar"}
maxAge := jwt.MaxAge(15 * time.Minute)

token, err := jwt.Sign(jwt.EdDSA, privateKey, claims, maxAge)
verifiedToken, err := Verify(EdDSA, publicKey, token)

Embedded keys? No problem, just integrate the jwt.ReadFile variable which is just a type of func(filename string) ([]byte, error).

Encryption

JWE (encrypted JWTs) is outside the scope of this package, a wire encryption of the token's payload is offered to secure the data instead. If the application requires to transmit a token which holds private data then it needs to encrypt the data on Sign and decrypt on Verify. The SignEncrypted and VerifyEncrypted package-level functions can be called to apply any type of encryption.

The package offers one of the most popular and common way to secure data; the GCM mode + AES cipher. We follow the encrypt-then-sign flow which most researchers recommend (it's safer as it prevents padding oracle attacks).

In-short, you need to call the jwt.GCM and pass its result to the jwt.SignEncrypted and jwt.VerifyEncrypted:

// Replace with your own keys and keep them secret.
// The "encKey" is used for the encryption and
// the "sigKey" is used for the selected JSON Web Algorithm
// (shared/symmetric HMAC in that case).
var (
    encKey = MustGenerateRandom(32)
    sigKey = MustGenerateRandom(32)
)

func main(){
    encrypt, decrypt, err := GCM(encKey, nil)
    if err != nil {
        // [handle error...]
    }
    // Encrypt and Sign the claims:
    token, err := SignEncrypted(jwt.HS256, sigKey, encrypt, claims, jwt.MaxAge(15 * time.Minute))
    // [...]

    // Verify and decrypt the claims:
    verifiedToken, err := VerifyEncrypted(jwt.HS256, sigKey, decrypt, token)
    // [...]
}

Read more about GCM at: https://en.wikipedia.org/wiki/Galois/Counter_Mode

References

Here is what helped me to implement JWT in Go:

License

This software is licensed under the MIT License.

Expand ▾ Collapse ▴

Documentation

Overview

Package jwt aims to provide an implementation of the JSON Web Token standard. The library supports the JSON Web Algorithm standard with HMAC, RSA, ECDSA and EdDSA. The signing operation can accept multiple claims and merge as one, not a single change to the existing structs is required. The verification process performs all the standard validations out of the box. The library supports only the compact serialization format.

Benchmarks are shown that this package is near ~3 times faster than existing packages for both Sign and Verify operations.

Project Home:

https://github.com/kataras/jwt

Examples Directory:

https://github.com/kataras/jwt/tree/main/_examples

Benchmarks:

https://github.com/kataras/jwt/tree/main/_benchmarks

Getting Started:

package main

import "github.com/kataras/jwt"

// Keep it secret.
var sharedKey = []byte("sercrethatmaycontainch@r$32chars")

func main() {
// Generate a token:
myClaims := map[string]interface{}{
	"foo": "bar",
}
token, err := jwt.Sign(jwt.HS256, sharedKey, myClaims, jwt.MaxAge(15 * time.Minute))

// Verify and extract claims from a token:
verifiedToken, err := jwt.Verify(jwt.HS256, sharedKey, token)

var claims map[string]interface{}
err = verifiedToken.Claims(&claims)
}

Index

Constants

This section is empty.

Variables

var (
	// ErrTokenSignature indicates that the verification failed.
	ErrTokenSignature = errors.New("invalid token signature")
	// ErrInvalidKey indicates that an algorithm required secret key is not a valid type.
	ErrInvalidKey = errors.New("invalid key")
)

var (
	// ErrExpired indicates that token is used after expiry time indicated in "exp" claim.
	ErrExpired = errors.New("token expired")
	// ErrNotValidYet indicates that token is used before time indicated in "nbf" claim.
	ErrNotValidYet = errors.New("token not valid yet")
	// ErrIssuedInTheFuture indicates that the "iat" claim is in the future.
	ErrIssuedInTheFuture = errors.New("token issued in the future")
)

var (
	// ErrMissing indicates that a given token to `Verify` is empty.
	ErrMissing = errors.New("token is empty")
	// ErrTokenForm indicates that the extracted token has not the expected form .
	ErrTokenForm = errors.New("invalid token form")
	// ErrTokenAlg indicates that the given algorithm does not match the extracted one.
	ErrTokenAlg = errors.New("unexpected token algorithm")
)

var Clock = time.Now

Clock is used to validate tokens expiration if the "exp" (expiration) exists in the payload. It can be overridden to use any other time value, useful for testing.

Usage: now := Clock()


var ErrBlocked = errors.New("token is blocked")

ErrBlocked indicates that the token has not yet expired but was blocked by the server's Blocklist.


var ErrDecrypt = errors.New("decrypt: payload authentication failed")

ErrDecrypt indicates a failure on payload decryption.


var ErrExpected = errors.New("field not match")

ErrExpected indicates a standard claims post-validation error. Usage:

verifiedToken, err := Verify(...)
  if errors.Is(ErrExpected, err) {

}

var ErrMissingKey = errors.New("token is missing a required field")

ErrMissingKey when token does not contain a required JSON field. Check with errors.Is.


var Marshal = func(v interface{}) ([]byte, error) {
	if b, ok := v.([]byte); ok {
		return b, nil
	}

	return json.Marshal(v)
}

Marshal same as json.Marshal. This variable can be modified to enable custom encoder behavior for a signed payload.


var Plain = TokenValidatorFunc(func(token []byte, standardClaims Claims, err error) error {
	if err == errPayloadNotJSON {
		return nil
	}

	return err
})

Plain can be provided as a Token Validator at `Verify` and `VerifyEncrypted` functions to allow tokens with plain payload (no JSON or malformed JSON) to be successfully validated.

Usage:

verifiedToken, err := jwt.Verify(jwt.HS256, []byte("secret"), token, jwt.Plain)
[handle error...]
[verifiedToken.Payload...]

var ReadFile = ioutil.ReadFile

ReadFile can be used to customize the way the Must/Load Key function helpers are loading the filenames from. Example of usage: embedded key pairs. Defaults to the `ioutil.ReadFile` which reads the file from the physical disk.


var Unmarshal = defaultUnmarshal

Unmarshal same as json.Unmarshal but with the Decoder unmarshals a number into an interface{} as a json.Number instead of as a float64. This is the function being called on `VerifiedToken.Claims` method. This variable can be modified to enable custom decoder behavior.


Functions

func Base64Decode

func Base64Decode(src []byte) ([]byte, error)

Base64Decode decodes "src" to jwt base64 url format. We could use the base64.RawURLEncoding but the below is a bit faster.

func Base64Encode

func Base64Encode(src []byte) []byte

Base64Encode encodes "src" to jwt base64 url format. We could use the base64.RawURLEncoding but the below is a bit faster.

func BytesQuote

func BytesQuote(b []byte) []byte

BytesQuote returns a double-quoted []byte slice representing "b".

func BytesToString

func BytesToString(b []byte) string

BytesToString converts a slice of bytes to string without memory allocation.

func HasRequiredJSONTag

func HasRequiredJSONTag(field reflect.StructField) bool

HasRequiredJSONTag reports whether a specific value of "i" contains one or more `json:"xxx,required"` struct fields tags.

Can be used to precalculate the unmarshaller (see `UnmarshalWithRequired`) too.

func LoadHMAC

func LoadHMAC(filenameOrRaw string) ([]byte, error)

LoadHMAC accepts a single filename which its plain text data should contain the HMAC shared key. Pass the returned value to both `Token` and `Verify` functions.

func LoadPrivateKeyECDSA

func LoadPrivateKeyECDSA(filename string) (*ecdsa.PrivateKey, error)

LoadPrivateKeyECDSA accepts a file path of a PEM-encoded ECDSA private key and returns the ECDSA private key Go value. Pass the returned value to the `Token` (signing) function.

func LoadPrivateKeyEdDSA

func LoadPrivateKeyEdDSA(filename string) (ed25519.PrivateKey, error)

LoadPrivateKeyEdDSA accepts a file path of a PEM-encoded ed25519 private key and returns the ed25519 private key Go value. Pass the returned value to the `Token` (signing) function.

func LoadPrivateKeyRSA

func LoadPrivateKeyRSA(filename string) (*rsa.PrivateKey, error)

LoadPrivateKeyRSA accepts a file path of a PEM-encoded RSA private key and returns the RSA private key Go value. Pass the returned value to the `Token` (signing) function.

func LoadPublicKeyECDSA

func LoadPublicKeyECDSA(filename string) (*ecdsa.PublicKey, error)

LoadPublicKeyECDSA accepts a file path of a PEM-encoded ECDSA public key and returns the ECDSA public key Go value. Pass the returned value to the `Verify` function.

func LoadPublicKeyEdDSA

func LoadPublicKeyEdDSA(filename string) (ed25519.PublicKey, error)

LoadPublicKeyEdDSA accepts a file path of a PEM-encoded ed25519 public key and returns the ed25519 public key Go value. Pass the returned value to the `Verify` function.

func LoadPublicKeyRSA

func LoadPublicKeyRSA(filename string) (*rsa.PublicKey, error)

LoadPublicKeyRSA accepts a file path of a PEM-encoded RSA public key and returns the RSA public key Go value. Pass the returned value to the `Verify` function.

func MaxAgeMap

func MaxAgeMap(maxAge time.Duration, claims Map)

MaxAgeMap is a helper to set "exp" and "iat" claims to a map claims. Usage: claims := map[string]interface{}{"foo": "bar"} MaxAgeMap(15 * time.Minute, claims) Sign(alg, key, claims)

func Merge

func Merge(claims interface{}, other interface{}) []byte

Merge accepts two claim structs or maps and returns a flattened JSON result of both (no checks for duplicatations are maden).

Usage:

claims := Merge(map[string]interface{}{"foo":"bar"}, Claims{
  MaxAge: 15 * time.Minute,
  Issuer: "an-issuer",
})
Sign(alg, key, claims)

Merge is automatically called when:

Sign(alg, key, claims, MaxAge(time.Duration))
Sign(alg, key, claims, Claims{...})

func MustGenerateRandom

func MustGenerateRandom(n int) []byte

MustGenerateRandom returns a random HMAC key. Usage:

MustGenerateRandom(64)

func MustLoadECDSA

func MustLoadECDSA(privateKeyFilename, publicKeyFilename string) (*ecdsa.PrivateKey, *ecdsa.PublicKey)

MustLoadECDSA accepts private and public PEM filenames and returns a pair of private and public ECDSA keys. Pass the returned private key to the `Token` (signing) function and the public key to the `Verify` function.

It panics on errors.

func MustLoadEdDSA

func MustLoadEdDSA(privateKeyFilename, publicKeyFilename string) (ed25519.PrivateKey, ed25519.PublicKey)

MustLoadEdDSA accepts private and public PEM filenames and returns a pair of private and public ed25519 keys. Pass the returned private key to `Token` (signing) function and the public key to the `Verify` function.

It panics on errors.

func MustLoadHMAC

func MustLoadHMAC(filenameOrRaw string) []byte

MustLoadHMAC accepts a single filename which its plain text data should contain the HMAC shared key. Pass the returned value to both `Token` and `Verify` functions.

It panics if the file was not found or unable to read from.

func MustLoadRSA

func MustLoadRSA(privateKeyFilename, publicKeyFilename string) (*rsa.PrivateKey, *rsa.PublicKey)

MustLoadRSA accepts private and public PEM file paths and returns a pair of private and public RSA keys. Pass the returned private key to the `Token` (signing) function and the public key to the `Verify` function.

It panics on errors.

func ParsePrivateKeyECDSA

func ParsePrivateKeyECDSA(key []byte) (*ecdsa.PrivateKey, error)

ParsePrivateKeyECDSA decodes and parses the PEM-encoded ECDSA private key's raw contents. Pass the result to the `Token` (signing) function.

func ParsePrivateKeyEdDSA

func ParsePrivateKeyEdDSA(key []byte) (ed25519.PrivateKey, error)

ParsePrivateKeyEdDSA decodes and parses the PEM-encoded ed25519 private key's raw contents. Pass the result to the `Token` (signing) function.

func ParsePrivateKeyRSA

func ParsePrivateKeyRSA(key []byte) (*rsa.PrivateKey, error)

ParsePrivateKeyRSA decodes and parses the PEM-encoded RSA private key's raw contents. Pass the result to the `Token` (signing) function.

func ParsePublicKeyECDSA

func ParsePublicKeyECDSA(key []byte) (*ecdsa.PublicKey, error)

ParsePublicKeyECDSA decodes and parses the PEM-encoded ECDSA public key's raw contents. Pass the result to the `Verify` function.

func ParsePublicKeyEdDSA

func ParsePublicKeyEdDSA(key []byte) (ed25519.PublicKey, error)

ParsePublicKeyEdDSA decodes and parses the PEM-encoded ed25519 public key's raw contents. Pass the result to the `Verify` function.

func ParsePublicKeyRSA

func ParsePublicKeyRSA(key []byte) (*rsa.PublicKey, error)

ParsePublicKeyRSA decodes and parses the PEM-encoded RSA public key's raw contents. Pass the result to the `Verify` function.

func Sign

func Sign(alg Alg, key PrivateKey, claims interface{}, opts ...SignOption) ([]byte, error)

Sign signs and generates a new token based on the algorithm and a secret key. The claims is the payload, the actual body of the token, should contain information about a specific authorized client. Note that the payload part is not encrypted, therefore it should NOT contain any private information (unless Encrypt/Decrypt functions are set, see GCM function too). See the `Verify` function to decode and verify the result token.

Example Code to pass only standard Claims:

token, err := jwt.Sign(jwt.HS256, []byte("secret"), jwt.Claims{...})

Example Code to pass custom and expiration Claims manually:

now := time.Now()
token, err := jwt.Sign(jwt.HS256, []byte("secret"), map[string]interface{}{
  "iat": now.Unix(),
  "exp": now.Add(15 * time.Minute).Unix(),
  "foo": "bar",
})

Example Code for custom and standard claims using a SignOption:

token, err := jwt.Sign(jwt.HS256, []byte("secret"), jwt.Map{"foo":"bar"}, jwt.MaxAge(15 * time.Minute))
OR
token, err := jwt.Sign(jwt.HS256, []byte("secret"), jwt.Map{"foo":"bar"}, jwt.Claims {Expiry: ...})

Example Code for custom type as Claims + standard Claims:

type User struct { Username string `json:"username"` }
token, err := jwt.Sign(jwt.HS256, []byte("secret"), User{Username: "kataras"}, jwt.MaxAge(15 * time.Minute))

func SignEncrypted

func SignEncrypted(alg Alg, key PrivateKey, encrypt InjectFunc, claims interface{}, opts ...SignOption) ([]byte, error)

SignEncrypted same as `Sign` but it encrypts the payload part with the given "encrypt" function. The "encrypt" function is called AFTER Marshal. Look the `GCM` function for details.

func UnmarshalWithRequired

func UnmarshalWithRequired(payload []byte, dest interface{}) error

UnmarshalWithRequired protects the custom fields of JWT claims based on the json:required tag e.g. `json:"name,required"`. It accepts a struct value to be validated later on. Returns ErrMissingKey if a required value is missing from the payload.

Usage:

Unmarshal = UnmarshalWithRequired
[...]
A Go struct like: UserClaims { Username string `json:"username,required" `}
[...]
And `Verify` as usual.

Types

type Alg

type Alg interface {
	// Name should return the "alg" JWT field.
	Name() string
	// Sign should accept the private key given on jwt.Sign and
	// the base64-encoded header and payload data.
	// Should return the signature.
	Sign(key PrivateKey, headerAndPayload []byte) ([]byte, error)
	// Verify should verify the JWT "signature" (base64-decoded) against
	// the header and payload (base64-encoded).
	Verify(key PublicKey, headerAndPayload []byte, signature []byte) error
}

Alg represents a signing and verifying algorithm.

var (
	// None for unsecured JWTs.
	// An unsecured JWT may be fit for client-side use.
	// For instance, if the session ID is a hard-to-guess number, and
	// the rest of the data is only used by the client for constructing a
	// view, the use of a signature is superfluous.
	// This data can be used by a single-page web application
	// to construct a view with the "pretty" name for the user
	// without hitting the backend while he gets
	// redirected to his last visited page. Even if a malicious user
	// were to modify this data he or she would gain nothing.
	// Example payload:
	//  {
	//    "sub": "user123",
	//    "session": "ch72gsb320000udocl363eofy",
	//    "name": "Pretty Name",
	//    "lastpage": "/views/settings"
	//  }
	NONE Alg = &algNONE{}
	// HMAC-SHA signing algorithms.
	// Keys should be type of []byte.
	//
	// HMAC shared secrets, as used by JWTs, are optimized for speed.
	// This allows many sign/verify operations to be performed efficiently
	// but make brute force attacks easier. So, the length of the shared secret
	// for HS256/384/512 is of the utmost importance. In fact, JSON Web
	// Algorithms9 defines the minimum key length to be equal to the size in bits of the hash function
	// used along with the HMAC algorithm:
	// > A key of the same size as the hash output (for instance, 256 bits for "HS256") or larger
	// MUST be used with this algorithm.” - JSON Web Algorithms (RFC 7518), 3.2 HMAC with SHA-2 Functions.
	//
	// In other words, many passwords that could be used in other contexts are simply not good enough for
	// use with HMAC-signed JWTs. 256-bits equals 32 ASCII characters, so if you are using something
	// human readable, CONSIDER that number to be the MINIMUM number of characters to include in the
	// secret. Another good option is to switch to RS256 or other public-key algorithms, which are much
	// more robust and flexible. This is NOT SIMPLY A HYPOTHETICAL ATTACK, it has been shown that brute
	// force attacks for HS256 are simple enough to perform11 if the shared secret is too short.
	HS256 Alg = &algHMAC{"HS256", crypto.SHA256}
	HS384 Alg = &algHMAC{"HS384", crypto.SHA384}
	HS512 Alg = &algHMAC{"HS512", crypto.SHA512}
	// RSA signing algorithms.
	// Sign   key: *rsa.PrivateKey
	// Verify key: *rsa.PublicKey (or *rsa.PrivateKey with its PublicKey filled)
	//
	// Signing and verifying RS256 signed tokens is just as easy.
	// The only difference lies in the use of a private/public key pair rather than a shared secret.
	// There are many ways to create RSA keys.
	// OpenSSL is one of the most popular libraries for key creation and management.
	// Generate a private key:
	// $ openssl genpkey -algorithm rsa -out private_key.pem -pkeyopt rsa_keygen_bits:2048
	// Derive the public key from the private key:
	// $ openssl rsa -pubout -in private_key.pem -out public_key.pem
	RS256 Alg = &algRSA{"RS256", crypto.SHA256}
	RS384 Alg = &algRSA{"RS384", crypto.SHA384}
	RS512 Alg = &algRSA{"RS512", crypto.SHA512}
	// RSASSA-PSS signing algorithms.
	// Sign   key: *rsa.PrivateKey
	// Verify key: *rsa.PublicKey (or *rsa.PrivateKey with its PublicKey filled)
	//
	// RSASSA-PSS is another signature scheme with appendix based on RSA.
	// PSS stands for Probabilistic Signature Scheme, in contrast with the usual deterministic approach.
	// This scheme makes use of a cryptographically secure random number generator.
	// If a secure RNG is not available, the resulting signature and verification operations
	// provide a level of security comparable to deterministic approaches.
	// This way RSASSA-PSS results in a net improvement over PKCS v1.5 signatures
	//
	// Note that the OpenSSL generates different OIDs to protect
	// reusing the same key material for different cryptosystems.
	PS256 Alg = &algRSAPSS{"PS256", &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthAuto, Hash: crypto.SHA256}}
	PS384 Alg = &algRSAPSS{"PS384", &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthAuto, Hash: crypto.SHA384}}
	PS512 Alg = &algRSAPSS{"PS512", &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthAuto, Hash: crypto.SHA512}}
	// ECDSA signing algorithms.
	// Sign   key: *ecdsa.PrivateKey
	// Verify key: *ecdsa.PublicKey (or *ecdsa.PrivateKey with its PublicKey filled)
	//
	// 4.2.3 ES256: ECDSA using P-256/xxx and SHA-256/xxx
	// ECDSA algorithms also make use of public keys. The math behind the algorithm is different,
	// though, so the steps to generate the keys are different as well. The "P-256" in the name of this
	// algorithm tells us exactly which version of the algorithm to use.
	//
	// Generate a private key:
	// $ openssl ecparam -name prime256v1 -genkey -noout -out ecdsa_private_key.pem
	// Derive the public key from the private key:
	// $ openssl ec -in ecdsa_private_key.pem -pubout -out ecdsa_public_key.pem
	//
	// If you open these files you will note that there is much less data in them.
	// This is one of the benefits of ECDSA over RSA.
	// The generated files are in PEM format as well,
	// so simply pasting them in your source will suffice.
	// It generates a smaller token (almost 3 times less).
	ES256 Alg = &algECDSA{"ES256", crypto.SHA256, 32, 256}
	ES384 Alg = &algECDSA{"ES384", crypto.SHA384, 48, 384}
	ES512 Alg = &algECDSA{"ES512", crypto.SHA512, 66, 521}
	// Ed25519 Edwards-curve Digital Signature Algorithm.
	// The algorithm's name is: "EdDSA".
	// Sign   key: ed25519.PrivateKey
	// Verify key: ed25519.PublicKey
	// EdDSA uses small public keys (32 or 57 bytes)
	// and signatures (64 or 114 bytes) for Ed25519 and Ed448, respectively.
	// EdDSA provides similar performance with ECDSA, HMAC is still the fastest one.
	// It is fairly new algorithm, this has its benefits and its downsides.
	// Its standard library, which this jwt package use, added on go1.13.
	EdDSA Alg = &algEdDSA{"EdDSA"}
)

The builtin signing available algorithms. Author's recommendation of choosing the best algorithm for your application: Already work with RSA public and private keys? Choose RSA(RS256/RS384/RS512/PS256/PS384/PS512) (length of produced token characters is bigger). If you need the separation between public and private key, choose ECDSA(ES256/ES384/ES512) or EdDSA. ECDSA and EdDSA produce smaller tokens than RSA. If you need performance and well-tested algorithm, choose HMAC(HS256/HS384/HS512). The basic difference between symmetric and an asymmetric algorithm is that symmetric uses one shared key for both signing and verifying, and the asymmetric uses private key for signing and a public key for verifying. In general, asymmetric data is more secure because it uses different keys for the signing and verifying process but it's slower than symmetric ones.

type Blocklist

type Blocklist struct {
	Clock func() time.Time
	// GetKey is a function which can be used how to extract
	// the unique identifier for a token, by default
	// it checks if the "jti" is not empty, if it's then the key is the token itself.
	GetKey func(token []byte, claims Claims) string
	// contains filtered or unexported fields
}

Blocklist is an in-memory storage of tokens that should be immediately invalidated by the server-side. The most common way to invalidate a token, e.g. on user logout, is to make the client-side remove the token itself.

The end-developer is free to design a custom database for blocked tokens (e.g. redis), as long as it implements the TokenValidator interface it is a valid option for the Verify function.

func NewBlocklist

func NewBlocklist(gcEvery time.Duration) *Blocklist

NewBlocklist returns a new up and running in-memory Token Blocklist. It accepts the clear every "x" duration. Indeed, this duration can match the usual tokens expiration one.

A blocklist implements the `TokenValidator` interface.

func NewBlocklistContext

func NewBlocklistContext(ctx context.Context, gcEvery time.Duration) *Blocklist

NewBlocklistContext same as `NewBlocklist` but it also accepts a standard Go Context for GC cancelation.

func (*Blocklist) Count

func (b *Blocklist) Count() (int64, error)

Count returns the total amount of blocked tokens.

func (*Blocklist) Del

func (b *Blocklist) Del(key string) error

Del removes a token based on its "key" from the blocklist.

func (*Blocklist) GC

func (b *Blocklist) GC() int

GC iterates over all entries and removes expired tokens. This method is helpful to keep the list size small. Depending on the application, the GC method can be scheduled to called every half or a whole hour. A good value for a GC cron task is the Token's max age.

func (*Blocklist) Has

func (b *Blocklist) Has(key string) (bool, error)

Has reports whether the given "key" is blocked by the server. This method is called before the token verification, so even if was expired it is removed from the blocklist.

func (*Blocklist) InvalidateToken

func (b *Blocklist) InvalidateToken(token []byte, c Claims) error

InvalidateToken invalidates a verified JWT token. It adds the request token, retrieved by Verify method, to this blocklist. Next request will be blocked, even if the token was not yet expired. This method can be used when the client-side does not clear the token on a user logout operation.

func (*Blocklist) ValidateToken

func (b *Blocklist) ValidateToken(token []byte, c Claims, err error) error

ValidateToken completes the `TokenValidator` interface. Returns ErrBlocked if the "token" was blocked by this Blocklist.

type Claims

type Claims struct {
	// The opposite of the exp claim. A number representing a specific
	// date and time in the format “seconds since epoch” as defined by POSIX.
	// This claim sets the exact moment from which this JWT is considered valid.
	// The current time (see `Clock` package-level variable)
	// must be equal to or later than this date and time.
	NotBefore int64 `json:"nbf,omitempty"`
	// A number representing a specific date and time (in the same
	// format as exp and nbf) at which this JWT was issued.
	IssuedAt int64 `json:"iat,omitempty"`
	// A number representing a specific date and time in the
	// format “seconds since epoch” as defined by POSIX6.
	// This claims sets the exact moment from which
	// this JWT is considered invalid. This implementation allow for a certain skew
	// between clocks (by considering this JWT to be valid for a few minutes after the expiration
	// date, modify the `Clock` variable).
	Expiry int64 `json:"exp,omitempty"`
	// A string representing a unique identifier for this JWT. This claim may be
	// used to differentiate JWTs with other similar content (preventing replays, for instance). It is
	// up to the implementation to guarantee uniqueness.
	ID string `json:"jti,omitempty"`
	// A string or URI that uniquely identifies the party
	// that issued the JWT. Its interpretation is application specific (there is no central authority
	// managing issuers).
	Issuer string `json:"iss,omitempty"`
	// A string or URI that uniquely identifies the party
	// that this JWT carries information about. In other words, the claims contained in this JWT
	// are statements about this party. The JWT spec specifies that this claim must be unique in
	// the context of the issuer or, in cases where that is not possible, globally unique. Handling of
	// this claim is application specific.
	Subject string `json:"sub,omitempty"`
	// Either a single string or URI or an array of such
	// values that uniquely identify the intended recipients of this JWT. In other words, when this
	// claim is present, the party reading the data in this JWT must find itself in the aud claim or
	// disregard the data contained in the JWT. As in the case of the iss and sub claims, this claim
	// is application specific.
	Audience []string `json:"aud,omitempty"`
}

Claims holds the standard JWT claims (payload fields). It can be used to validate the JWT and to sign it. It completes the `SignOption` interface.

func (Claims) Age

func (c Claims) Age() time.Duration

Age returns the total age of the claims, the result of issued at - expired time.

func (Claims) ApplyClaims

func (c Claims) ApplyClaims(dest *Claims)

ApplyClaims implements the `SignOption` interface.

func (Claims) ExpiresAt

func (c Claims) ExpiresAt() time.Time

ExpiresAt returns the time this token will be expired (round in second). It's a shortcut of time.Unix(c.Expiry).

func (Claims) Timeleft

func (c Claims) Timeleft() time.Duration

Timeleft returns the remaining time to be expired (round in second).

type Expected

type Expected Claims // We could use the same Claims structure but for concept separation we use a different one.

Expected is a TokenValidator which performs simple checks between standard claims values.

Usage:

 expected := Expected{
	  Issuer: "my-app",
 }
 verifiedToken, err := Verify(..., expected)

func (Expected) ValidateToken

func (e Expected) ValidateToken(token []byte, c Claims, err error) error

ValidateToken completes the TokenValidator interface. It performs simple checks against the expected "e" and the verified "c" claims. Can be passed at the Verify's last input argument.

It returns a type of ErrExpected on validation failures.

type InjectFunc

type InjectFunc func(plainPayload []byte) ([]byte, error)

InjectFunc can be used to further modify the final token's body part. Look the `GCM` function for a real implementation of this type.

func GCM

func GCM(key, additionalData []byte) (encrypt, decrypt InjectFunc, err error)

GCM sets the `Encrypt` and `Decrypt` package-level functions to provide encryption over the token's payload on Sign and decryption on Verify using the Galois Counter mode of operation with AES cipher symmetric-key cryptographic. It should be called once on initialization of the program and before any Sign/Verify operation.

The key argument should be the AES key, either 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.

The additionalData argument is optional. Can be set to nil to ignore.

Usage:

var encKey = MustGenerateRandom(32)
var sigKey = MustGenerateRandom(32)

encrypt, decrypt, err := GCM(encKey, nil)
if err != nil { ... }
token, err := SignEncrypted(jwt.HS256, sigKey, encrypt, claims, jwt.MaxAge(15 * time.Minute))
verifiedToken, err := VerifyEncrypted(jwt.HS256, sigKey, decrypt, token)

type Map

type Map = map[string]interface{}

Map is just a type alias, a shortcut of map[string]interface{}.

type PrivateKey

type PrivateKey interface{}

PrivateKey is a generic type, this key is responsible for signing the token.

type PublicKey

type PublicKey interface{}

PublicKey is a generic type, this key is responsible to verify the token.

type SignOption

type SignOption interface {
	// ApplyClaims should apply standard claims.
	// Accepts the destination claims.
	ApplyClaims(*Claims)
}

SignOption is just a helper which sets the standard claims at the `Sign` function.

Available SignOptions: - MaxAge(time.Duration) - Claims{}

type SignOptionFunc

type SignOptionFunc func(*Claims)

SignOptionFunc completes the `SignOption`. It's a helper to pass a `SignOption` as a function.

func MaxAge

func MaxAge(maxAge time.Duration) SignOptionFunc

MaxAge is a SignOption to set the expiration "exp", "iat" JWT standard claims. Can be passed as last input argument of the `Sign` function.

If maxAge > second then sets expiration to the token. It's a helper field to set the `Expiry` and `IssuedAt` fields at once.

See the `Clock` package-level variable to modify the current time function.

func (SignOptionFunc) ApplyClaims

func (f SignOptionFunc) ApplyClaims(c *Claims)

ApplyClaims completes the `SignOption` interface.

type TokenPair

type TokenPair struct {
	AccessToken  json.RawMessage `json:"access_token,omitempty"`
	RefreshToken json.RawMessage `json:"refresh_token,omitempty"`
}

TokenPair holds the access token and refresh token response.

func NewTokenPair

func NewTokenPair(accessToken, refreshToken []byte) TokenPair

NewTokenPair accepts raw access and refresh token and returns a structure which holds both of them, ready to be sent to the client as JSON.

type TokenValidator

type TokenValidator interface {
	// ValidateToken accepts the token, the claims extracted from that
	// and any error that may caused by claims validation (e.g. ErrExpired)
	// or the previous validator.
	// A token validator can skip the builtin validation and return a nil error.
	// Usage:
	//  func(v *myValidator) ValidateToken(token []byte, standardClaims Claims, err error) error {
	//    if err!=nil { return err } <- to respect the previous error
	//    // otherwise return nil or any custom error.
	//  }
	//
	// Look `Blocklist`, `Expected` and `Leeway` for builtin implementations.
	ValidateToken(token []byte, standardClaims Claims, err error) error
}

TokenValidator provides further token and claims validation.

type TokenValidatorFunc

type TokenValidatorFunc func(token []byte, standardClaims Claims, err error) error

TokenValidatorFunc is the interface-as-function shortcut for a TokenValidator.

func Leeway

func Leeway(leeway time.Duration) TokenValidatorFunc

Leeway adds validation for a leeway expiration time. If the token was not expired then a comparison between this "leeway" and the token's "exp" one is expected to pass instead (now+leeway > exp). Example of use case: disallow tokens that are going to be expired in 3 seconds from now, this is useful to make sure that the token is valid when the when the user fires a database call for example.

func (TokenValidatorFunc) ValidateToken

func (fn TokenValidatorFunc) ValidateToken(token []byte, standardClaims Claims, err error) error

ValidateToken completes the ValidateToken interface. It calls itself.

type VerifiedToken

type VerifiedToken struct {
	Token          []byte // The original token.
	Header         []byte // The header (decoded) part.
	Payload        []byte // The payload (decoded) part.
	Signature      []byte // The signature (decoded) part.
	StandardClaims Claims // Any standard claims extracted from the payload.
}

VerifiedToken holds the information about a verified token. Look `Verify` for more.

func Verify

func Verify(alg Alg, key PublicKey, token []byte, validators ...TokenValidator) (*VerifiedToken, error)

Verify decodes, verifies and validates the standard JWT claims of the given "token" using the algorithm and the secret key that this token was generated with.

It returns a VerifiedToken which can be used to read the standard claims and some read-only information about the token. That VerifiedToken contains a `Claims` method, useful to bind the token's payload(claims) to a custom Go struct or a map when necessary.

The last variadic input argument is optional, can be used for further claims validations before exit. Returns the verified token information.

Example Code:

verifiedToken, err := jwt.Verify(jwt.HS256, []byte("secret"), token)
[handle error...]
var claims map[string]interface{}
verifiedToken.Claims(&claims)

func VerifyEncrypted

func VerifyEncrypted(alg Alg, key PublicKey, decrypt InjectFunc, token []byte, validators ...TokenValidator) (*VerifiedToken, error)

VerifyEncrypted same as `Verify` but it decrypts the payload part with the given "decrypt" function. The "decrypt" function is called AFTER base64-decode and BEFORE Unmarshal. Look the `GCM` function for details.

func (*VerifiedToken) Claims

func (t *VerifiedToken) Claims(dest interface{}) error

Claims decodes the token's payload to the "dest". If the application requires custom claims, this is the method to Go.

It calls the `Unmarshal(t.Payload, dest)` package-level function . When called, it decodes the token's payload (aka claims) to the "dest" pointer of a struct or map value. Note that the `StandardClaims` field is always set, as it contains the standard JWT claims, and validated at the `Verify` function itself, therefore NO FURTHER STEP is required to validate the "exp", "iat" and "nbf" claims.