Documentation ¶
Overview ¶
Package jwt implements “JSON Web Token (JWT)” RFC 7519. Signatures only; no unsecured nor encrypted tokens.
Example ¶
Note how the security is flawed without any purpose claims. The bare minimum should include time constraints.
package main import ( "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" "fmt" "time" "github.com/pascaldekloe/jwt" ) var ( RSAPrivateKey *rsa.PrivateKey RSAPublicKey *rsa.PublicKey ) func main() { var c jwt.Claims c.Issuer = "malory" c.Subject = "sterling" c.Audiences = []string{"armory"} // Approval is a custom claim element. type Approval struct { Name string `json:"name"` Count int `json:"count"` } c.Set = map[string]interface{}{ "approved": []Approval{{"RPG-7", 1}}, } // issue a JWT token, err := c.RSASign(jwt.RS256, RSAPrivateKey) if err != nil { fmt.Println("token creation failed on", err) return } // validate the JWT claims, err := jwt.RSACheck(token, RSAPublicKey) if err != nil { fmt.Println("credentials denied on", err) return } if !claims.Valid(time.Now()) { fmt.Println("time constraints exceeded") return } if !claims.AcceptAudience("armory") { fmt.Println("reject on audience", claims.Audiences) return } fmt.Println(string(claims.Raw)) }
Output: {"approved":[{"name":"RPG-7","count":1}],"aud":["armory"],"iss":"malory","sub":"sterling"}
Example (Extend) ¶
Non-Standard Algorithm & JOSE Heading
package main import ( "crypto" _ "crypto/md5" // link into binary "encoding/json" "fmt" "github.com/pascaldekloe/jwt" ) func init() { // static algorithm registration jwt.HMACAlgs["MD5"] = crypto.MD5 } // Non-Standard Algorithm & JOSE Heading func main() { c := jwt.Claims{KeyID: "№4b"} token, err := c.HMACSign("MD5", []byte("guest"), json.RawMessage(`{"lan": "XL9", "tcode": 102}`)) if err != nil { fmt.Println("sign error:", err) return } fmt.Println("token:", string(token)) got, err := jwt.HMACCheck(token, []byte("guest")) if err != nil { fmt.Println("check error:", err) return } fmt.Println("header:", string(got.RawHeader)) }
Output: token: eyJhbGciOiJNRDUiLCJraWQiOiLihJY0YiIsImxhbiI6IlhMOSIsInRjb2RlIjoxMDJ9.e30.Gfpw0GU5qxm8oNQZeYHhnQ header: {"alg":"MD5","kid":"№4b","lan":"XL9","tcode":102}
Example (HTTP) ¶
Standard HTTP Library Integration
package main import ( "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" "fmt" "io" "net/http" "net/http/httptest" "os" "github.com/pascaldekloe/jwt" ) var ( EdPrivateKey ed25519.PrivateKey EdPublicKey ed25519.PublicKey ) func main() { // standard HTTP handler http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { fmt.Fprintf(w, "Hello %s!\n", req.Header.Get("X-Verified-Name")) fmt.Fprintf(w, "You are authorized as %s.\n", req.Header.Get("X-Verified-User")) }) // secure service configuration srv := httptest.NewTLSServer(&jwt.Handler{ Target: http.DefaultServeMux, Keys: &jwt.KeyRegister{EdDSAs: []ed25519.PublicKey{EdPublicKey}}, HeaderPrefix: "X-Verified-", HeaderBinding: map[string]string{ "sub": "X-Verified-User", // registered [standard] claim name "fn": "X-Verified-Name", // private [custom] claim name }, }) defer srv.Close() // self-signed request req, _ := http.NewRequest("GET", srv.URL, nil) var claims jwt.Claims claims.Subject = "lakane" claims.Set = map[string]interface{}{ "fn": "Lana Anthony Kane", } if err := claims.EdDSASignHeader(req, EdPrivateKey); err != nil { fmt.Println("sign error:", err) } // call service resp, _ := srv.Client().Do(req) fmt.Println("HTTP", resp.Status) io.Copy(os.Stdout, resp.Body) }
Output: HTTP 200 OK Hello Lana Anthony Kane! You are authorized as lakane.
Index ¶
- Constants
- Variables
- type AlgError
- type Claims
- func ECDSACheck(token []byte, key *ecdsa.PublicKey) (*Claims, error)
- func ECDSACheckHeader(r *http.Request, key *ecdsa.PublicKey) (*Claims, error)
- func EdDSACheck(token []byte, key ed25519.PublicKey) (*Claims, error)
- func EdDSACheckHeader(r *http.Request, key ed25519.PublicKey) (*Claims, error)
- func HMACCheck(token, secret []byte) (*Claims, error)
- func HMACCheckHeader(r *http.Request, secret []byte) (*Claims, error)
- func ParseWithoutCheck(token []byte) (*Claims, error)
- func RSACheck(token []byte, key *rsa.PublicKey) (*Claims, error)
- func RSACheckHeader(r *http.Request, key *rsa.PublicKey) (*Claims, error)
- func (c *Claims) ECDSASign(alg string, key *ecdsa.PrivateKey, extraHeaders ...json.RawMessage) (token []byte, err error)
- func (c *Claims) ECDSASignHeader(r *http.Request, alg string, key *ecdsa.PrivateKey) error
- func (c *Claims) EdDSASign(key ed25519.PrivateKey, extraHeaders ...json.RawMessage) (token []byte, err error)
- func (c *Claims) EdDSASignHeader(r *http.Request, key ed25519.PrivateKey) error
- func (c *Claims) FormatWithoutSign(alg string, extraHeaders ...json.RawMessage) (tokenWithoutSignature []byte, err error)
- func (c *Claims) HMACSign(alg string, secret []byte, extraHeaders ...json.RawMessage) (token []byte, err error)
- func (c *Claims) HMACSignHeader(r *http.Request, alg string, secret []byte) error
- func (c *Claims) Number(name string) (value float64, ok bool)
- func (c *Claims) RSASign(alg string, key *rsa.PrivateKey, extraHeaders ...json.RawMessage) (token []byte, err error)
- func (c *Claims) RSASignHeader(r *http.Request, alg string, key *rsa.PrivateKey) error
- func (c *Claims) String(name string) (value string, ok bool)
- type Handler
- type KeyRegister
- func (keys *KeyRegister) Check(token []byte) (*Claims, error)
- func (keys *KeyRegister) CheckHeader(r *http.Request) (*Claims, error)
- func (keys *KeyRegister) LoadJWK(data []byte) (keysAdded int, err error)
- func (keys *KeyRegister) LoadPEM(text, password []byte) (keysAdded int, err error)
- func (keys *KeyRegister) PEM() ([]byte, error)
- type NumericTime
- type Registered
- Bugs
Examples ¶
Constants ¶
const ( EdDSA = "EdDSA" // EdDSA signature algorithms ES256 = "ES256" // ECDSA using P-256 and SHA-256 ES384 = "ES384" // ECDSA using P-384 and SHA-384 ES512 = "ES512" // ECDSA using P-521 and SHA-512 HS256 = "HS256" // HMAC using SHA-256 HS384 = "HS384" // HMAC using SHA-384 HS512 = "HS512" // HMAC using SHA-512 PS256 = "PS256" // RSASSA-PSS using SHA-256 and MGF1 with SHA-256 PS384 = "PS384" // RSASSA-PSS using SHA-384 and MGF1 with SHA-384 PS512 = "PS512" // RSASSA-PSS using SHA-512 and MGF1 with SHA-512 RS256 = "RS256" // RSASSA-PKCS1-v1_5 using SHA-256 RS384 = "RS384" // RSASSA-PKCS1-v1_5 using SHA-384 RS512 = "RS512" // RSASSA-PKCS1-v1_5 using SHA-512 )
Algorithm Identification Tokens
const MIMEType = "application/jwt"
MIMEType is the IANA registered media type.
const OAuthURN = "urn:ietf:params:oauth:token-type:jwt"
OAuthURN is the IANA registered OAuth URI.
Variables ¶
var ( ECDSAAlgs = map[string]crypto.Hash{ ES256: crypto.SHA256, ES384: crypto.SHA384, ES512: crypto.SHA512, } HMACAlgs = map[string]crypto.Hash{ HS256: crypto.SHA256, HS384: crypto.SHA384, HS512: crypto.SHA512, } RSAAlgs = map[string]crypto.Hash{ PS256: crypto.SHA256, PS384: crypto.SHA384, PS512: crypto.SHA512, RS256: crypto.SHA256, RS384: crypto.SHA384, RS512: crypto.SHA512, } )
Algorithm support is configured with hash registrations.
var ErrNoHeader = errors.New("jwt: no HTTP authorization header")
ErrNoHeader signals an HTTP request without authorization.
var ErrSigMiss = errors.New("jwt: signature mismatch")
ErrSigMiss means the signature check failed.
Functions ¶
This section is empty.
Types ¶
type Claims ¶
type Claims struct { // Registered field values take precedence over Set. Registered // Set maps claims by name, for usecases beyond the Registered fields. // The Sign methods copy each non-zero Registered value into Set when // the map is not nil. The Check methods map claims in Set if the name // doesn't match any of the Registered, or if the data type won't fit. // Entries are treated conform the encoding/json package. // // bool, for JSON booleans // float64, for JSON numbers // string, for JSON strings // []interface{}, for JSON arrays // map[string]interface{}, for JSON objects // nil for JSON null // Set map[string]interface{} // Raw payload encoding as is within the token. This field is read-only. Raw json.RawMessage // RawHeader encoding as is within the token. This field is read-only. RawHeader json.RawMessage // “The "kid" (key ID) Header Parameter is a hint indicating which key // was used to secure the JWS. This parameter allows originators to // explicitly signal a change of key to recipients. The structure of the // "kid" value is unspecified. Its value MUST be a case-sensitive // string. Use of this Header Parameter is OPTIONAL.” // — “JSON Web Signature (JWS)” RFC 7515, subsection 4.1.4 KeyID string }
Claims are the (signed) statements of a JWT.
Example (ByName) ¶
Typed Claim Lookups
package main import ( "fmt" "time" "github.com/pascaldekloe/jwt" ) func main() { now := time.Unix(1537622794, 0) c := jwt.Claims{ Registered: jwt.Registered{ Issuer: "a", Subject: "b", Audiences: []string{"c"}, Expires: jwt.NewNumericTime(now.Add(time.Minute)), NotBefore: jwt.NewNumericTime(now.Add(-time.Second)), Issued: jwt.NewNumericTime(now), ID: "d", }, Set: map[string]interface{}{ "ext": "e", }, } for _, name := range []string{"iss", "sub", "aud", "exp", "nbf", "iat", "jti", "ext"} { if s, ok := c.String(name); ok { fmt.Printf("%q: %q\n", name, s) } if n, ok := c.Number(name); ok { fmt.Printf("%q: %0.f\n", name, n) } } }
Output: "iss": "a" "sub": "b" "aud": "c" "exp": 1537622854 "nbf": 1537622793 "iat": 1537622794 "jti": "d" "ext": "e"
func ECDSACheck ¶
ECDSACheck parses a JWT if, and only if, the signature checks out. The return is an AlgError when the algorithm is not in ECDSAAlgs. Use Valid to complete the verification.
func ECDSACheckHeader ¶
ECDSACheckHeader applies ECDSACheck on a HTTP request. Specifically it looks for a bearer token in the Authorization header.
func EdDSACheck ¶
EdDSACheck parses a JWT if, and only if, the signature checks out. Use Valid to complete the verification.
func EdDSACheckHeader ¶
EdDSACheckHeader applies EdDSACheck on a HTTP request. Specifically it looks for a bearer token in the Authorization header.
func HMACCheck ¶
HMACCheck parses a JWT if, and only if, the signature checks out. The return is an AlgError when the algorithm is not in HMACAlgs. Use Valid to complete the verification.
func HMACCheckHeader ¶
HMACCheckHeader applies HMACCheck on a HTTP request. Specifically it looks for a bearer token in the Authorization header.
func ParseWithoutCheck ¶
ParseWithoutCheck skips the signature validation.
func RSACheck ¶
RSACheck parses a JWT if, and only if, the signature checks out. The return is an AlgError when the algorithm is not in RSAAlgs. Use Valid to complete the verification.
func RSACheckHeader ¶
RSACheckHeader applies RSACheck on a HTTP request. Specifically it looks for a bearer token in the Authorization header.
func (*Claims) ECDSASign ¶
func (c *Claims) ECDSASign(alg string, key *ecdsa.PrivateKey, extraHeaders ...json.RawMessage) (token []byte, err error)
ECDSASign updates the Raw fields and returns a new JWT. The return is an AlgError when alg is not in ECDSAAlgs. The caller must use the correct key for the respective algorithm (P-256 for ES256, P-384 for ES384 and P-521 for ES512) or risk malformed token production.
The JOSE header (content) can be extended with extraHeaders, in the form of JSON objects. Redundant and/or duplicate keys are applied as provided.
func (*Claims) ECDSASignHeader ¶
ECDSASignHeader applies ECDSASign on a HTTP request. Specifically it sets a bearer token in the Authorization header.
func (*Claims) EdDSASign ¶
func (c *Claims) EdDSASign(key ed25519.PrivateKey, extraHeaders ...json.RawMessage) (token []byte, err error)
EdDSASign updates the Raw fields and returns a new JWT.
The JOSE header (content) can be extended with extraHeaders, in the form of JSON objects. Redundant and/or duplicate keys are applied as provided.
func (*Claims) EdDSASignHeader ¶
EdDSASignHeader applies ECDSASign on a HTTP request. Specifically it sets a bearer token in the Authorization header.
func (*Claims) FormatWithoutSign ¶
func (c *Claims) FormatWithoutSign(alg string, extraHeaders ...json.RawMessage) (tokenWithoutSignature []byte, err error)
FormatWithoutSign updates the Raw fields and returns a new JWT, with only the first two parts.
tokenWithoutSignature :≡ header-base64 '.' payload-base64 token :≡ tokenWithoutSignature '.' signature-base64
The JOSE header (content) can be extended with extraHeaders, in the form of JSON objects. Redundant and/or duplicate keys are applied as provided.
func (*Claims) HMACSign ¶
func (c *Claims) HMACSign(alg string, secret []byte, extraHeaders ...json.RawMessage) (token []byte, err error)
HMACSign updates the Raw fields and returns a new JWT. The return is an AlgError when alg is not in HMACAlgs.
The JOSE header (content) can be extended with extraHeaders, in the form of JSON objects. Redundant and/or duplicate keys are applied as provided.
func (*Claims) HMACSignHeader ¶
HMACSignHeader applies HMACSign on a HTTP request. Specifically it sets a bearer token in the Authorization header.
func (*Claims) Number ¶
Number returns the claim when present and if the representation is a JSON number.
func (*Claims) RSASign ¶
func (c *Claims) RSASign(alg string, key *rsa.PrivateKey, extraHeaders ...json.RawMessage) (token []byte, err error)
RSASign updates the Raw fields and returns a new JWT. The return is an AlgError when alg is not in RSAAlgs.
The JOSE header (content) can be extended with extraHeaders, in the form of JSON objects. Redundant and/or duplicate keys are applied as provided.
func (*Claims) RSASignHeader ¶
RSASignHeader applies RSASign on a HTTP request. Specifically it sets a bearer token in the Authorization header.
type Handler ¶
type Handler struct { // Target is the secured service. Target http.Handler // Keys defines the trusted credentials. Keys *KeyRegister // HeaderBinding maps JWT claim names to HTTP header names. // All requests passed to Target have these headers set. In // case of failure the request is rejected with status code // 401 (Unauthorized) and a description. HeaderBinding map[string]string // HeaderPrefix is an optional constraint for JWT claim binding. // Any client headers that match the prefix are removed from the // request. HeaderBinding entries that don't match the prefix // are ignored. HeaderPrefix string // ContextKey places the validated Claims in the context of // each respective request passed to Target when set. See // http.Request.Context and context.Context.Value. ContextKey interface{} // When not nil, then Func is called after the JWT validation // succeeds and before any header bindings. Target is skipped // [request drop] when the return is false. // This feature may be used to further customise requests or // as a filter or as an extended http.HandlerFunc. Func func(http.ResponseWriter, *http.Request, *Claims) (pass bool) // Error sends a custom response. Nil defaults to http.Error. // The appropriate WWW-Authenticate value is already present. Error func(w http.ResponseWriter, error string, statusCode int) }
Handler protects an http.Handler with security enforcements. Requests are only passed to Target if the JWT checks out.
Example (Context) ¶
Claims Access From Request Context
package main import ( "fmt" "net/http" "net/http/httptest" "time" "github.com/pascaldekloe/jwt" ) func main() { h := &jwt.Handler{ Target: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { claims := req.Context().Value("verified-jwt").(*jwt.Claims) if n, ok := claims.Number("deadline"); !ok { fmt.Fprintln(w, "no deadline") } else { fmt.Fprintln(w, "deadline at", (*jwt.NumericTime)(&n)) } }), Keys: &jwt.KeyRegister{Secrets: [][]byte{[]byte("killarcherdie")}}, ContextKey: "verified-jwt", } // build request req := httptest.NewRequest("GET", "/status", nil) var c jwt.Claims c.Set = map[string]interface{}{ "deadline": jwt.NewNumericTime(time.Date(1991, 4, 12, 23, 59, 59, 0, time.UTC)), } if err := c.HMACSignHeader(req, jwt.HS384, []byte("killarcherdie")); err != nil { fmt.Println("sign error:", err) } // get response resp := httptest.NewRecorder() h.ServeHTTP(resp, req) fmt.Println("HTTP", resp.Code) fmt.Println(resp.Body) }
Output: HTTP 200 deadline at 1991-04-12T23:59:59Z
Example (Error) ¶
Custom Response Format
package main import ( "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" "fmt" "net/http" "net/http/httptest" "time" "github.com/pascaldekloe/jwt" ) var ( ECPrivateKey *ecdsa.PrivateKey ECPublicKey *ecdsa.PublicKey ) func main() { h := &jwt.Handler{ Target: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "My plan is to crowdsource a plan!") }), Keys: &jwt.KeyRegister{ECDSAs: []*ecdsa.PublicKey{ECPublicKey}}, Error: func(w http.ResponseWriter, error string, statusCode int) { // JSON messages instead of plain text w.Header().Set("Content-Type", "application/json;charset=UTF-8") w.WriteHeader(statusCode) fmt.Fprintf(w, `{"msg": %q}`, error) }, } // build request req := httptest.NewRequest("GET", "/had-something-for-this", nil) var c jwt.Claims c.Expires = jwt.NewNumericTime(time.Now().Add(-time.Second)) if err := c.ECDSASignHeader(req, jwt.ES512, ECPrivateKey); err != nil { fmt.Println("sign error:", err) } // get response resp := httptest.NewRecorder() h.ServeHTTP(resp, req) fmt.Println("HTTP", resp.Code) fmt.Println(resp.Header().Get("WWW-Authenticate")) fmt.Println(resp.Body) }
Output: HTTP 401 Bearer error="invalid_token", error_description="jwt: time constraints exceeded" {"msg": "jwt: time constraints exceeded"}
Example (Filter) ¶
Func As A Request Filter
package main import ( "crypto/ecdsa" "crypto/ed25519" "crypto/rsa" "fmt" "net/http" "net/http/httptest" "github.com/pascaldekloe/jwt" ) var ( RSAPrivateKey *rsa.PrivateKey RSAPublicKey *rsa.PublicKey ) func main() { h := &jwt.Handler{ Target: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { fmt.Fprintln(w, "Elaborate voicemail hoax!") }), Keys: &jwt.KeyRegister{RSAs: []*rsa.PublicKey{RSAPublicKey}}, Func: func(w http.ResponseWriter, req *http.Request, claims *jwt.Claims) (pass bool) { if claims.Subject != "marcher" { http.Error(w, "Ring, ring!", http.StatusServiceUnavailable) return false } return true }, } // build request req := httptest.NewRequest("GET", "/urgent", nil) if err := new(jwt.Claims).RSASignHeader(req, jwt.PS512, RSAPrivateKey); err != nil { fmt.Println("sign error:", err) } // get response resp := httptest.NewRecorder() h.ServeHTTP(resp, req) fmt.Println("HTTP", resp.Code) fmt.Println(resp.Body) }
Output: HTTP 503 Ring, ring!
type KeyRegister ¶
type KeyRegister struct { ECDSAs []*ecdsa.PublicKey // ECDSA credentials EdDSAs []ed25519.PublicKey // EdDSA credentials RSAs []*rsa.PublicKey // RSA credentials Secrets [][]byte // HMAC credentials // Optional key identification. See Claims.KeyID for details. // Non-empty strings match the respective key or secret by index. ECDSAIDs []string // ECDSAs key ID mapping EdDSAIDs []string // EdDSA key ID mapping RSAIDs []string // RSAs key ID mapping SecretIDs []string // Secrets key ID mapping }
KeyRegister is a collection of recognized credentials.
func (*KeyRegister) Check ¶
func (keys *KeyRegister) Check(token []byte) (*Claims, error)
Check parses a JWT if, and only if, the signature checks out. Use Claims.Valid to complete the verification.
func (*KeyRegister) CheckHeader ¶
func (keys *KeyRegister) CheckHeader(r *http.Request) (*Claims, error)
CheckHeader applies KeyRegister.Check on a HTTP request. Specifically it looks for a bearer token in the Authorization header.
func (*KeyRegister) LoadJWK ¶
func (keys *KeyRegister) LoadJWK(data []byte) (keysAdded int, err error)
LoadJWK adds keys from the JSON data to the register, including the key ID, a.k.a "kid", when present. If the object has a "keys" attribute, then data is read as a JWKS (JSON Web Key Set). Otherwise, data is read as a single JWK.
Example ¶
JWKS With Key IDs
package main import ( "fmt" "github.com/pascaldekloe/jwt" ) func main() { const json = `{ "keys": [ {"kty": "OKP", "crv":"Ed25519", "kid": "kazak", "d":"nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A", "x":"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"}, {"kty":"oct", "k":"a29mdGE", "kid": "good old"} ] }` var keys jwt.KeyRegister _, err := keys.LoadJWK([]byte(json)) if err != nil { fmt.Println("load error:", err) } fmt.Printf("got %d EdDSA %q", len(keys.EdDSAs), keys.EdDSAIDs) fmt.Printf(" + %d secret %q", len(keys.Secrets), keys.SecretIDs) }
Output: got 1 EdDSA ["kazak"] + 1 secret ["good old"]
func (*KeyRegister) LoadPEM ¶
func (keys *KeyRegister) LoadPEM(text, password []byte) (keysAdded int, err error)
LoadPEM scans text for PEM-encoded keys. Each occurrence found is then added to the register. Extraction works with certificates, public keys and private keys. PEM encryption is enforced with a non-empty password to ensure security when ordered.
Example (Encrypted) ¶
PEM With Password Protection
package main import ( "fmt" "github.com/pascaldekloe/jwt" ) func main() { const pem = `Keep it private! ✨ -----BEGIN RSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: AES-128-CBC,65789712555A3E9FECD1D5E235B97B0C o0Dz8S6QjGVq59yQdlakuKkoO0jKDN0PDu2L05ZLXwBQSGdIbRXtAOBRCNEME0V1 IF9pM6uRU7tqFoVneNTHD3XySJG8AHrTPSKC3Xw31pjEolMfoNDBAu1bYR6XxM2X oDu2UNVB9vd/3b4bwTH9q5ISWdCVhS/ky0lC9lHXman/F/7MsemiVVCQ4XTIi9CR nitMxJuXvkNBMtsyv+inmFMegKU6dj1DU93B9JpsFRRvy3TCfj9kRjhKWEpyindo yaZMH3EGOA3ALW5kWyr+XegyYznQbVdDlo/ikO9BAywBOx+DdRG4xYxRdxYt8/HH qXwPAGQe2veMlR7Iq3GjwHLebyuVc+iHbC7feRmNBpAT1RR7J+RIGlDPOBMUpuDT A8HbNzPkoXPGh9vMsREXtR5aPCaZISdcm8DTlNiZCPaX5VHL4SRJ5XjI2rnahaOE rhCFy0mxqQaKnEI9kCWWFmhX/MqzzfiW3yg0qFIAVLDQZZMFJr3jMHIvkxPk09rP nQIjMRBalFXmSiksx8UEhAzyriqiXwwgEI0gJVHcs3EIQGD5jNqvIYTX67/rqSF2 OXoYuq0MHrAJgEfDncXvZFFMuAS/5KMvzSXfWr5/L0ncCU9UykjdPrFvetG/7IXQ BT1TX4pOeW15a6fg6KwSZ5KPrt3o8qtRfW4Ov49hPD2EhnCTMbkCRBbW8F13+9YF xzvC4Vm1r/Oa4TTUbf5tVto7ua/lZvwnu5DIWn2zy5ZUPrtn22r1ymVui7Iuhl0b SRcADdHh3NgrjDjalhLDB95ho5omG39l7qBKBTlBAYJhDuAk9rIk1FCfCB8upztt -----END RSA PRIVATE KEY-----` var keys jwt.KeyRegister n, err := keys.LoadPEM([]byte(pem), []byte("dangerzone")) if err != nil { fmt.Println("load error:", err) } fmt.Println(n, "keys added") }
Output: 1 keys added
func (*KeyRegister) PEM ¶
func (keys *KeyRegister) PEM() ([]byte, error)
PEM exports the (public) keys as PEM-encoded PKIX. Elements from the Secret field, if any, are not included.
type NumericTime ¶
type NumericTime float64
NumericTime implements NumericDate: “A JSON numeric value representing the number of seconds from 1970-01-01T00:00:00Z UTC until the specified UTC date/time, ignoring leap seconds.”
func NewNumericTime ¶
func NewNumericTime(t time.Time) *NumericTime
NewNumericTime returns the the corresponding representation with nil for the zero value. Do t.Round(time.Second) for slightly smaller token production and compatibility. See the bugs section for details.
func (*NumericTime) String ¶
func (n *NumericTime) String() string
String returns the ISO representation or the empty string for nil.
func (*NumericTime) Time ¶
func (n *NumericTime) Time() time.Time
Time returns the Go mapping with the zero value for nil.
type Registered ¶
type Registered struct { // Issuer identifies the principal that issued the JWT. Issuer string `json:"iss,omitempty"` // Subject identifies the principal that is the subject of the JWT. Subject string `json:"sub,omitempty"` // Audiences identifies the recipients that the JWT is intended for. Audiences []string `json:"aud,omitempty"` // Expires identifies the expiration time on or after which the JWT // must not be accepted for processing. Expires *NumericTime `json:"exp,omitempty"` // NotBefore identifies the time before which the JWT must not be // accepted for processing. NotBefore *NumericTime `json:"nbf,omitempty"` // Issued identifies the time at which the JWT was issued. Issued *NumericTime `json:"iat,omitempty"` // ID provides a unique identifier for the JWT. ID string `json:"jti,omitempty"` }
Registered “JSON Web Token Claims” has a subset of the IANA registration. See <https://www.iana.org/assignments/jwt/claims.csv> for the full listing.
Each field is optional—there are no required claims. The string values are case sensitive.
func (*Registered) AcceptAudience ¶
func (r *Registered) AcceptAudience(stringOrURI string) bool
AcceptAudience verifies the applicability of an audience identified as stringOrURI. Any stringOrURI is accepted on absence of the aud(ience) claim.
Notes ¶
Bugs ¶
Some broken JWT implementations fail to parse tokens with fractions in Registered.Expires, .NotBefore or .Issued. Round to seconds—like NewNumericDate(time.Now().Round(time.Second))—for compatibility.