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]any{ "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]any err = verifiedToken.Claims(&claims) }
Index ¶
- Constants
- Variables
- func Base64Decode(src []byte) ([]byte, error)
- func Base64Encode(src []byte) []byte
- func BytesQuote(b []byte) []byte
- func BytesToString(b []byte) string
- func EncodePrivateKeyToPEM(key PrivateKey) (string, error)
- func EncodePublicKeyToPEM(key PublicKey) (string, error)
- func GenerateBase64EdDSA() (string, string, error)
- func GenerateEdDSA() (ed25519.PublicKey, ed25519.PrivateKey, error)
- func HasRequiredJSONTag(field reflect.StructField) bool
- func LoadHMAC(filenameOrRaw string) ([]byte, error)
- func LoadPrivateKeyECDSA(filename string) (*ecdsa.PrivateKey, error)
- func LoadPrivateKeyEdDSA(filename string) (ed25519.PrivateKey, error)
- func LoadPrivateKeyRSA(filename string) (*rsa.PrivateKey, error)
- func LoadPublicKeyECDSA(filename string) (*ecdsa.PublicKey, error)
- func LoadPublicKeyEdDSA(filename string) (ed25519.PublicKey, error)
- func LoadPublicKeyRSA(filename string) (*rsa.PublicKey, error)
- func MaxAgeMap(maxAge time.Duration, claims Map)
- func Merge(values ...any) ([]byte, error)
- func MustGenerateRandom(n int) []byte
- func MustGenerateRandomBase64(length int, padding rune) string
- func MustGenerateRandomString(length int) string
- func MustLoadECDSA(privateKeyFilename, publicKeyFilename string) (*ecdsa.PrivateKey, *ecdsa.PublicKey)
- func MustLoadEdDSA(privateKeyFilename, publicKeyFilename string) (ed25519.PrivateKey, ed25519.PublicKey)
- func MustLoadHMAC(filenameOrRaw string) []byte
- func MustLoadRSA(privateKeyFilename, publicKeyFilename string) (*rsa.PrivateKey, *rsa.PublicKey)
- func ParsePrivateKeyECDSA(key []byte) (*ecdsa.PrivateKey, error)
- func ParsePrivateKeyEdDSA(key []byte) (ed25519.PrivateKey, error)
- func ParsePrivateKeyRSA(key []byte) (*rsa.PrivateKey, error)
- func ParsePublicKeyECDSA(key []byte) (*ecdsa.PublicKey, error)
- func ParsePublicKeyEdDSA(key []byte) (ed25519.PublicKey, error)
- func ParsePublicKeyRSA(key []byte) (*rsa.PublicKey, error)
- func Sign(alg Alg, key PrivateKey, claims any, opts ...SignOption) ([]byte, error)
- func SignEncrypted(alg Alg, key PrivateKey, encrypt InjectFunc, claims any, opts ...SignOption) ([]byte, error)
- func SignEncryptedWithHeader(alg Alg, key PrivateKey, encrypt InjectFunc, claims any, customHeader any, ...) ([]byte, error)
- func SignWithHeader(alg Alg, key PrivateKey, claims any, customHeader any, opts ...SignOption) ([]byte, error)
- func UnmarshalWithRequired(payload []byte, dest any) error
- type AWSCognitoError
- type Alg
- type AlgParser
- type Audience
- type Blocklist
- func (b *Blocklist) Count() (int64, error)
- func (b *Blocklist) Del(key string) error
- func (b *Blocklist) GC() int
- func (b *Blocklist) Has(key string) (bool, error)
- func (b *Blocklist) InvalidateToken(token []byte, c Claims) error
- func (b *Blocklist) ValidateToken(token []byte, c Claims, err error) error
- type Claims
- type Expected
- type HTTPClient
- type HeaderValidator
- type HeaderWithKid
- type InjectFunc
- type JWK
- type JWKS
- type Key
- type KeyConfiguration
- type Keys
- func (keys Keys) Configuration() (KeysConfiguration, error)
- func (keys Keys) Get(kid string) (*Key, bool)
- func (keys Keys) JWKS() (*JWKS, error)
- func (keys Keys) Register(alg Alg, kid string, pubKey PublicKey, privKey PrivateKey)
- func (keys Keys) SignToken(kid string, claims any, opts ...SignOption) ([]byte, error)
- func (keys Keys) ValidateHeader(alg string, headerDecoded []byte) (Alg, PublicKey, InjectFunc, error)
- func (keys Keys) VerifyToken(token []byte, claimsPtr any, validators ...TokenValidator) error
- type KeysConfiguration
- type Map
- type PrivateKey
- type PublicKey
- type SignOption
- type SignOptionFunc
- type TokenPair
- type TokenValidator
- type TokenValidatorFunc
- type UnverifiedToken
- type VerifiedToken
- func Verify(alg Alg, key PublicKey, token []byte, validators ...TokenValidator) (*VerifiedToken, error)
- func VerifyEncrypted(alg Alg, key PublicKey, decrypt InjectFunc, token []byte, ...) (*VerifiedToken, error)
- func VerifyEncryptedWithHeaderValidator(alg Alg, key PublicKey, decrypt InjectFunc, token []byte, ...) (*VerifiedToken, error)
- func VerifyWithHeaderValidator(alg Alg, key PublicKey, token []byte, headerValidator HeaderValidator, ...) (*VerifiedToken, error)
Constants ¶
const NoPadding = base64.NoPadding
NoPadding is the base64.NoPadding.
Variables ¶
var ( // ErrTokenSignature indicates that the verification failed. ErrTokenSignature = errors.New("jwt: invalid token signature") // ErrInvalidKey indicates that an algorithm required secret key is not a valid type. ErrInvalidKey = errors.New("jwt: invalid key") )
var ( // ErrExpired indicates that token is used after expiry time indicated in "exp" claim. ErrExpired = errors.New("jwt: token expired") // ErrNotValidYet indicates that token is used before time indicated in "nbf" claim. ErrNotValidYet = errors.New("jwt: token not valid yet") // ErrIssuedInTheFuture indicates that the "iat" claim is in the future. ErrIssuedInTheFuture = errors.New("jwt: token issued in the future") )
var ( // ErrEmptyKid fires when the header is missing a "kid" field. ErrEmptyKid = errors.New("jwt: kid is empty") // ErrUnknownKid fires when the header has a "kid" field // but does not match with any of the registered ones. ErrUnknownKid = errors.New("jwt: unknown kid") )
var ( // ErrMissing indicates that a given token to `Verify` is empty. ErrMissing = errors.New("jwt: token is empty") // ErrTokenForm indicates that the extracted token has not the expected form . ErrTokenForm = errors.New("jwt: invalid token form") // ErrTokenAlg indicates that the given algorithm does not match the extracted one. ErrTokenAlg = errors.New("jwt: 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("jwt: token is blocked")
ErrBlocked indicates that the token has not yet expired but was blocked by the server's Blocklist.
var ErrDecrypt = errors.New("jwt: decrypt: payload authentication failed")
ErrDecrypt indicates a failure on payload decryption.
var ErrExpected = errors.New("jwt: field not match")
ErrExpected indicates a standard claims post-validation error. Usage:
verifiedToken, err := Verify(...) if errors.Is(ErrExpected, err) { }
var ErrMissingKey = errors.New("jwt: token is missing a required field")
ErrMissingKey when token does not contain a required JSON field. Check with errors.Is.
var Marshal = func(v any) ([]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 = os.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 `os.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 any 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 ¶
Base64Decode decodes "src" to jwt base64 url format. We could use the base64.RawURLEncoding but the below is a bit faster.
func Base64Encode ¶
Base64Encode encodes "src" to jwt base64 url format. We could use the base64.RawURLEncoding but the below is a bit faster.
func BytesQuote ¶ added in v0.0.4
BytesQuote returns a double-quoted []byte slice representing "b".
func BytesToString ¶
BytesToString converts a slice of bytes to string without memory allocation.
func EncodePrivateKeyToPEM ¶ added in v0.1.15
func EncodePrivateKeyToPEM(key PrivateKey) (string, error)
EncodePrivateKeyToPEM encodes a PrivateKey to a PEM-encoded string.
func EncodePublicKeyToPEM ¶ added in v0.1.15
EncodePublicKeyToPEM encodes a PublicKey to a PEM-encoded string.
func GenerateBase64EdDSA ¶ added in v0.0.14
GenerateBase64EdDSA generates random public and private keys for ed25519. The keys are returned as base64 encoded strings.
Usage:
publicKey, privateKey, err := GenerateBase64EdDSA()
func GenerateEdDSA ¶ added in v0.0.14
func GenerateEdDSA() (ed25519.PublicKey, ed25519.PrivateKey, error)
GenerateEdDSA generates random public and private keys for ed25519.
func HasRequiredJSONTag ¶ added in v0.0.4
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 ¶
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 ¶
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 ¶
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 ¶
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 ¶
MaxAgeMap is a helper to set "exp" and "iat" claims to a map claims. Usage: claims := map[string]any{"foo": "bar"} MaxAgeMap(15 * time.Minute, claims) Sign(alg, key, claims)
func Merge ¶
Merge merges a variadic number of values into a single JSON object. Each non‑nil value must marshal to a JSON object (i.e. it must start with '{' and end with '}'). Nil values and empty objects ("{}") are skipped. Returns an error if any non‑nil value does not marshal to a JSON object.
Usage:
claims, err := Merge(map[string]any{"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 ¶
MustGenerateRandom returns a random HMAC key. Usage:
MustGenerateRandom(64)
func MustGenerateRandomBase64 ¶ added in v0.0.14
MustGenerateRandomBase64 returns a random base64 string based on the passed length.
Usage:
MustGenerateRandomBase64(32, jwt.NoPadding)
func MustGenerateRandomString ¶ added in v0.0.14
MustGenerateRandomString returns a random string based on the passed length.
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 ¶
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 ¶
ParsePublicKeyECDSA decodes and parses the PEM-encoded ECDSA public key's raw contents. Pass the result to the `Verify` function.
func ParsePublicKeyEdDSA ¶
ParsePublicKeyEdDSA decodes and parses the PEM-encoded ed25519 public key's raw contents. Pass the result to the `Verify` function.
func ParsePublicKeyRSA ¶
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 any, 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]any{ "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 ¶ added in v0.0.3
func SignEncrypted(alg Alg, key PrivateKey, encrypt InjectFunc, claims any, 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 SignEncryptedWithHeader ¶ added in v0.0.14
func SignEncryptedWithHeader(alg Alg, key PrivateKey, encrypt InjectFunc, claims any, customHeader any, opts ...SignOption) ([]byte, error)
SignEncryptedWithHeader same as `SignEncrypted` but accepts a custom json header structure too.
func SignWithHeader ¶ added in v0.0.14
func SignWithHeader(alg Alg, key PrivateKey, claims any, customHeader any, opts ...SignOption) ([]byte, error)
SignWithHeader same as `Sign` but accepts a custom json header structure too.
func UnmarshalWithRequired ¶
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 AWSCognitoError ¶ added in v0.0.14
AWSCognitoError represents an error response from AWS Cognito. It implements the error interface.
func (AWSCognitoError) Error ¶ added in v0.0.14
func (e AWSCognitoError) Error() string
Error returns the error message.
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 AlgParser ¶ added in v0.0.14
type AlgParser interface {
Parse(private, public []byte) (PrivateKey, PublicKey, error)
}
AlgParser is an optional interface that an "Alg" can complete so parsing keys can be easier to be found based on the algorithm used.
See kid_keys.go.
type Audience ¶ added in v0.0.8
type Audience []string
Audience represents the "aud" standard JWT claim. See the `Claims` structure for details.
func (Audience) ApplyClaims ¶ added in v0.0.14
ApplyClaims implements the `SignOption` interface. It sets the Audience field to standard Claims instance.
Usage:
jwt.Sign(jwt.HS256, []byte("secret"), User{Username: "kataras"}, jwt.MaxAge(15 * time.Minute), jwt.Audience{"admin", "root"})
func (*Audience) UnmarshalJSON ¶ added in v0.0.8
UnmarshalJSON implements the json.Unmarshaler interface. The audience is expected to be single string an array of strings.
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 ¶
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 ¶
NewBlocklistContext same as `NewBlocklist` but it also accepts a standard Go Context for GC cancelation.
func (*Blocklist) GC ¶
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 ¶
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 ¶
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.
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"` // Origin JWT Token ID. This key is not part of the RFC. // May be the parent token's id. Useful for tokens invalidation. OriginID string `json:"origin_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 Audience `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 ¶ added in v0.0.4
Age returns the total age of the claims, the result of issued at - expired time.
func (Claims) ApplyClaims ¶
ApplyClaims implements the `SignOption` interface.
type Expected ¶ added in v0.0.3
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 ¶ added in v0.0.3
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 HTTPClient ¶ added in v0.0.14
HTTPClient is an interface that can be used to mock the http.Client. It is used to fetch the JSON Web Key Set (JWKS) from AWS Cognito.
type HeaderValidator ¶ added in v0.0.14
HeaderValidator is a function which can be used to customize how the header is validated, by default it makes sure the algorithm is the same as the "alg" field.
If the "alg" is empty then this function should return a non-nil algorithm based on the token contents. It should return a nil PublicKey and a non-nil error on validation failure. The out InjectFunc is optional. If it's not nil then decryption of the payload using GCM (AES key) is performed before verification. On success, if public key is not nil then it overrides the VerifyXXX method's one.
var CompareHeader HeaderValidator = compareHeader
CompareHeader is the function which compares and validates the decoded header against the defined signature algorithm. Defaults to a fast and simple implementation but it can be modified to support custom usage when third-party jwt signers signs the token (e.g. from a java spring application).
This affects every token of the current program. Use the `VerifyWithHeaderValidator` function to implement per-token validation instead.
type HeaderWithKid ¶ added in v0.0.14
HeaderWithKid represents a simple header part which holds the "kid" and "alg" fields.
type InjectFunc ¶ added in v0.0.3
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 ¶ added in v0.0.2
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 JWK ¶ added in v0.0.14
type JWK struct { Kty string `json:"kty"` // Key type (e.g., "RSA", "OKP" Octet Key Pair) Kid string `json:"kid"` // Key ID Use string `json:"use"` // Key use (e.g., "sig") Alg string `json:"alg"` // Algorithm (e.g., "RS256", "EdDSA") Crv string `json:"crv"` // Curve name (e.g., "Ed25519") N string `json:"n"` // RSA modulus (Base64 URL-encoded) E string `json:"e"` // RSA exponent (Base64 URL-encoded) Y string `json:"y"` // Elliptic y-coordinate (Base64 URL-encoded) X string `json:"x"` // EdDSA public key (Base64 URL-encoded) }
JWK represents a JSON Web Key.
func GenerateJWK ¶ added in v0.0.14
GenerateJWK generates a JSON Web Key (JWK) from the given public key. Supported public key types:
- RSA (RS256, RS384, RS512) as *rsa.PublicKey.
- Elliptic Curve (ES256, ES384, ES512) as ecdsa.PublicKey.
- EdDSA as ed25519.PublicKey.
type JWKS ¶ added in v0.0.14
type JWKS struct {
Keys []*JWK `json:"keys"`
}
JWKS represents a JSON Web Key Set.
func FetchJWKS ¶ added in v0.0.14
func FetchJWKS(client HTTPClient, url string) (*JWKS, error)
FetchJWKS fetches the JSON Web Key Set (JWKS) from the given URL. It returns the JWKS object or an error if the request fails. If the HTTP client is not set, the default http.Client is used.
The url is the URL of the JWKS endpoint, usually ends with: /.well-known/jwks.json.
func (*JWKS) PublicKeys ¶ added in v0.0.14
PublicKeys parse and returns the public keys as Keys map from the JSON Web Key Set (JWKS). It supports all RS256, RS384, RS512, ES256, ES384, ES512 and Ed25519 algorithms.
type Key ¶ added in v0.0.14
type Key struct { ID string Alg Alg Public PublicKey Private PrivateKey MaxAge time.Duration // optional. Encrypt InjectFunc // optional. Decrypt InjectFunc // optional. }
Key holds the Go parsed key pairs. This package has all the helpers you need to parse a file or a string to go crypto keys, e.g. `ParsePublicKeyRSA` and `ParsePrivateKeyRSA` package-level functions.
func (*Key) Configuration ¶ added in v0.1.15
func (key *Key) Configuration() (KeyConfiguration, error)
Configuration converts a Key to a key configuration. It will throw an error if the key includes encryption.
type KeyConfiguration ¶ added in v0.0.14
type KeyConfiguration struct { ID string `json:"id" yaml:"ID" toml:"ID" ini:"id"` // Alg declares the algorithm name. // Available values: // * HS256 // * HS384 // * HS512 // * RS256 // * RS384 // * RS512 // * PS256 // * PS384 // * PS512 // * ES256 // * ES384 // * ES512 // * EdDSA Alg string `json:"alg" yaml:"Alg" toml:"Alg" ini:"alg"` Private string `json:"private" yaml:"Private" toml:"Private" ini:"private"` Public string `json:"public" yaml:"Public" toml:"Public" ini:"public"` // MaxAge sets the token expiration. It is optional. // If greater than zero then the MaxAge token validation // will be appended to the "VerifyToken" and the token is invalid // after expiration of its sign time. MaxAge time.Duration `json:"max_age" yaml:"MaxAge" toml:"MaxAge" ini:"max_age"` // EncryptionKey enables encryption on the generated token. It is optional. // Encryption using the Galois Counter mode of operation with // AES cipher symmetric-key cryptographic. // // It should be HEX-encoded string value. // // The value should be the AES key, // either 16, 24, or 32 bytes to select // AES-128, AES-192, or AES-256. EncryptionKey string `json:"encryption_key" yaml:"EncryptionKey" toml:"EncryptionKey" ini:"encryption_key"` }
KeyConfiguration is a single key configuration. It's just a representation of the Key struct but with string fields.
func (KeyConfiguration) Clone ¶ added in v0.0.14
func (c KeyConfiguration) Clone() KeyConfiguration
Clone returns a new copy of the KeyConfiguration.
type Keys ¶ added in v0.0.14
Keys is a map which holds the key id and a key pair. User should initialize the keys once, not safe for concurrent writes. See its `SignToken`, `VerifyToken` and `ValidateHeader` methods. Usage:
var keys jwt.Keys keys.Register("api", jwt.RS256, apiPubKey, apiPrivKey) keys.Register("cognito", jwt.RS256, cognitoPubKey, nil) ... token, err := keys.SignToken("api", myClaims{...}, jwt.MaxAge(15*time.Minute)) ... var c myClaims err := keys.VerifyToken("api", token, &myClaims) } ... keys.JWKS() to generate a JSON Web Key Set to serve on /.well-known/jwks.json.
func FetchAWSCognitoPublicKeys ¶ added in v0.0.14
FetchAWSCognitoPublicKeys fetches the JSON Web Key Set (JWKS) from the AWS Cognito endpoint and returns the public keys as Keys map. It returns an error if the request fails or the JWKS is invalid.
func FetchPublicKeys ¶ added in v0.0.14
FetchPublicKeys fetches the JSON Web Key Set (JWKS) from the given URL and returns the public keys as Keys map. It returns an error if the request fails or the JWKS is invalid.
The url is the URL of the JWKS endpoint, usually ends with: /.well-known/jwks.json.
It supports all RS256, RS384, RS512, ES256, ES384, ES512 and Ed25519 algorithms.
func (Keys) Configuration ¶ added in v0.1.15
func (keys Keys) Configuration() (KeysConfiguration, error)
Configuration converts Keys to a keys configuration. It will throw an error if any key includes encryption.
Useful to construct a KeysConfiguration from JWKS#PublicKeys() method.
func (Keys) JWKS ¶ added in v0.0.14
JWKS returns the JSON Web Key Set (JWKS) based on the registered keys. Its result is ready for serving the JWKS on /.well-known/jwks.json.
See https://tools.ietf.org/html/rfc7517#section-5 for more.
func (Keys) Register ¶ added in v0.0.14
func (keys Keys) Register(alg Alg, kid string, pubKey PublicKey, privKey PrivateKey)
Register registers a keypair to a unique identifier per key.
func (Keys) SignToken ¶ added in v0.0.14
SignToken signs the "claims" using the given "alg" based a specific key.
func (Keys) ValidateHeader ¶ added in v0.0.14
func (keys Keys) ValidateHeader(alg string, headerDecoded []byte) (Alg, PublicKey, InjectFunc, error)
ValidateHeader validates the given json header value (base64 decoded) based on the "keys". Keys structure completes the `HeaderValidator` interface.
func (Keys) VerifyToken ¶ added in v0.0.14
func (keys Keys) VerifyToken(token []byte, claimsPtr any, validators ...TokenValidator) error
VerifyToken verifies the "token" using the given "alg" based on the registered public key(s) and sets the custom claims to the destination "claimsPtr".
type KeysConfiguration ¶ added in v0.0.14
type KeysConfiguration []KeyConfiguration
KeysConfiguration for multiple keys sign and validate. Look the MustLoad/Load method.
Example at: _examples/multiple-kids.
func (KeysConfiguration) Clone ¶ added in v0.0.14
func (c KeysConfiguration) Clone() KeysConfiguration
Clone returns a new copy of the KeysConfiguration. Load or MustLoad must be called to parse the keys after the clone.
func (KeysConfiguration) Get ¶ added in v0.0.14
func (c KeysConfiguration) Get(kid string) (KeyConfiguration, bool)
Get returns the key configuration based on its id.
func (KeysConfiguration) Load ¶ added in v0.0.14
func (c KeysConfiguration) Load() (Keys, error)
Load returns the keys parsed through the json, yaml, toml or ini configuration.
func (KeysConfiguration) MustLoad ¶ added in v0.0.14
func (c KeysConfiguration) MustLoad() Keys
MustLoad same as Load but it panics if errored.
type PrivateKey ¶
type PrivateKey = any
PrivateKey is a generic type, this key is responsible for signing the token.
type PublicKey ¶
type PublicKey = any
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) - NoMaxAge() - []Audience{"aud"} - Claims{}
type SignOptionFunc ¶
type SignOptionFunc func(*Claims)
SignOptionFunc completes the `SignOption`. It's a helper to pass a `SignOption` as a function.
var NoMaxAge SignOptionFunc = func(c *Claims) {
c.Expiry = 0
c.IssuedAt = 0
}
NoMaxAge is a SignOption to set the expiration "exp", "iat" JWT standard claims to zero.
Usage: Sign(alg, key, claims, NoMaxAge)
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 ¶ added in v0.0.4
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 ¶ added in v0.0.4
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 ¶ added in v0.0.3
TokenValidatorFunc is the interface-as-function shortcut for a TokenValidator.
func Future ¶ added in v0.0.14
func Future(dur time.Duration) TokenValidatorFunc
Future adds a validation for the "iat" claim. It checks if the token was issued in the future based on now+dur < iat.
Example of use case: allow tokens that are going to be issued in the future, for example a token that is going to be issued in 10 seconds from now.
func Leeway ¶ added in v0.0.3
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 ¶ added in v0.0.3
func (fn TokenValidatorFunc) ValidateToken(token []byte, standardClaims Claims, err error) error
ValidateToken completes the ValidateToken interface. It calls itself.
type UnverifiedToken ¶ added in v0.0.8
UnverifiedToken contains the compact form token parts. Look its `Claims` method to decode to a custom structure.
func Decode ¶ added in v0.0.8
func Decode(token []byte) (*UnverifiedToken, error)
Decode decodes the token of compact form WITHOUT verification and validation.
This function is only useful to read a token's claims when the source is trusted and no algorithm verification or direct signature and content validation is required.
Use `Verify/VerifyEncrypted` functions instead.
func (*UnverifiedToken) Claims ¶ added in v0.0.8
func (t *UnverifiedToken) Claims(dest any) error
Claims decodes the `Payload` field to the "dest".
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]any verifiedToken.Claims(&claims)
func VerifyEncrypted ¶ added in v0.0.3
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 VerifyEncryptedWithHeaderValidator ¶ added in v0.0.14
func VerifyEncryptedWithHeaderValidator(alg Alg, key PublicKey, decrypt InjectFunc, token []byte, headerValidator HeaderValidator, validators ...TokenValidator) (*VerifiedToken, error)
VerifyEncryptedWithHeaderValidator same as `VerifyEncrypted` but it accepts a custom header validator too.
func VerifyWithHeaderValidator ¶ added in v0.0.14
func VerifyWithHeaderValidator(alg Alg, key PublicKey, token []byte, headerValidator HeaderValidator, validators ...TokenValidator) (*VerifiedToken, error)
VerifyWithHeaderValidator same as `Verify` but it accepts a custom header validator too.
func (*VerifiedToken) Claims ¶
func (t *VerifiedToken) Claims(dest any) 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.