jwt

package
v3.0.0-alpha1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 1, 2024 License: MIT Imports: 25 Imported by: 3

README

JWT Go Reference

Package jwt implements JSON Web Tokens as described in RFC7519.

  • Convenience methods for oft-used keys ("aud", "sub", "iss", etc)
  • Convenience functions to extract/parse from http.Request, http.Header, url.Values
  • Ability to Get/Set arbitrary keys
  • Conversion to and from JSON
  • Generate signed tokens
  • Verify signed tokens
  • Extra support for OpenID tokens via github.com/lestrrat-go/jwx/v3/jwt/openid

How-to style documentation can be found in the docs directory.

More examples are located in the examples directory (jwt_example_test.go)

SYNOPSIS

Verify a signed JWT

  token, err := jwt.Parse(payload, jwt.WithKey(alg, key))
  if err != nil {
    fmt.Printf("failed to parse payload: %s\n", err)
  }

Token Usage

func ExampleJWT() {
  const aLongLongTimeAgo = 233431200

  t := jwt.New()
  t.Set(jwt.SubjectKey, `https://github.com/lestrrat-go/jwx/v3/jwt`)
  t.Set(jwt.AudienceKey, `Golang Users`)
  t.Set(jwt.IssuedAtKey, time.Unix(aLongLongTimeAgo, 0))
  t.Set(`privateClaimKey`, `Hello, World!`)

  buf, err := json.MarshalIndent(t, "", "  ")
  if err != nil {
    fmt.Printf("failed to generate JSON: %s\n", err)
    return
  }

  fmt.Printf("%s\n", buf)
  fmt.Printf("aud -> '%s'\n", t.Audience())
  fmt.Printf("iat -> '%s'\n", t.IssuedAt().Format(time.RFC3339))
  if v, ok := t.Get(`privateClaimKey`); ok {
    fmt.Printf("privateClaimKey -> '%s'\n", v)
  }
  fmt.Printf("sub -> '%s'\n", t.Subject())

  key, err := rsa.GenerateKey(rand.Reader, 2048)
  if err != nil {
    log.Printf("failed to generate private key: %s", err)
    return
  }

  {
    // Signing a token (using raw rsa.PrivateKey)
    signed, err := jwt.Sign(t, jwt.WithKey(jwa.RS256, key))
    if err != nil {
      log.Printf("failed to sign token: %s", err)
      return
    }
    _ = signed
  }

  {
    // Signing a token (using JWK)
    jwkKey, err := jwk.New(key)
    if err != nil {
      log.Printf("failed to create JWK key: %s", err)
      return
    }

    signed, err := jwt.Sign(t, jwt.WithKey(jwa.RS256, jwkKey))
    if err != nil {
      log.Printf("failed to sign token: %s", err)
      return
    }
    _ = signed
  }
}

OpenID Claims

jwt package can work with token types other than the default one. For OpenID claims, use the token created by openid.New(), or use the jwt.WithToken(openid.New()). If you need to use other specialized claims, use jwt.WithToken() to specify the exact token type

func Example_openid() {
  const aLongLongTimeAgo = 233431200

  t := openid.New()
  t.Set(jwt.SubjectKey, `https://github.com/lestrrat-go/jwx/v3/jwt`)
  t.Set(jwt.AudienceKey, `Golang Users`)
  t.Set(jwt.IssuedAtKey, time.Unix(aLongLongTimeAgo, 0))
  t.Set(`privateClaimKey`, `Hello, World!`)

  addr := openid.NewAddress()
  addr.Set(openid.AddressPostalCodeKey, `105-0011`)
  addr.Set(openid.AddressCountryKey, `日本`)
  addr.Set(openid.AddressRegionKey, `東京都`)
  addr.Set(openid.AddressLocalityKey, `港区`)
  addr.Set(openid.AddressStreetAddressKey, `芝公園 4-2-8`)
  t.Set(openid.AddressKey, addr)

  buf, err := json.MarshalIndent(t, "", "  ")
  if err != nil {
    fmt.Printf("failed to generate JSON: %s\n", err)
    return
  }
  fmt.Printf("%s\n", buf)

  t2, err := jwt.Parse(buf, jwt.WithToken(openid.New()))
  if err != nil {
    fmt.Printf("failed to parse JSON: %s\n", err)
    return
  }
  if _, ok := t2.(openid.Token); !ok {
    fmt.Printf("using jwt.WithToken(openid.New()) creates an openid.Token instance")
    return
  }
}

FAQ

Why is jwt.Token an interface?

In this package, jwt.Token is an interface. This is not an arbitrary choice: there are actual reason for the type being an interface.

We understand that if you are migrating from another library this may be a deal breaker, but we hope you can at least appreciate the fact that this was not done arbitrarily, and that there were real technical trade offs that were evaluated.

No uninitialized tokens

First and foremost, by making it an interface, you cannot use an uninitialized token:

var token1 jwt.Token // this is nil, you can't just start using this
if err := json.Unmarshal(data, &token1); err != nil { // so you can't do this
   ...
}

// But you _can_ do this, and we _want_ you to do this so the object is properly initialized
token2 = jwt.New()
if err := json.Unmarshal(data, &token2); err != nil { // actually, in practice you should use jwt.Parse()
   ....
}
But why does it need to be initialized?

There are several reasons, but one of the reasons is that I'm using a sync.Mutex to avoid races. We want this to be properly initialized.

The other reason is that we support custom claims out of the box. The map[string]interface{} container is initialized during new. This is important when checking for equality using reflect-y methods (akin to reflect.DeepEqual), because if you allowed zero values, you could end up with "empty" tokens, that actually differ. Consider the following:

// assume jwt.Token was s struct, not an interface
token1 := jwt.Token{ privateClaims: make(map[string]interface{}) }
token2 := jwt.Token{ privateClaims: nil }

These are semantically equivalent, but users would need to be aware of this difference when comparing values. By forcing the user to use a constructor, we can force a uniform empty state.

Standard way to store values

Unlike some other libraries, this library allows you to store standard claims and non-standard claims in the same token.

You want to store standard claims in a properly typed field, which we do for fields like "iss", "nbf", etc. But for non-standard claims, there is just no way of doing this, so we have to use a container like map[string]interface{}

This means that if you allow direct access to these fields via a struct, you will have two different ways to access the claims, which is confusing:

tok.Issuer = ...
tok.PrivateClaims["foo"] = ...

So we want to hide where this data is stored, and use a standard method like Set() and Get() to store all the values. At this point you are effectively going to hide the implementation detail from the user, so you end up with a struct like below, which is fundamentally not so different from providing just an interface{}:

type Token struct {
  // unexported fields
}

func (tok *Token) Set(...) { ... }
Use of pointers to store values

We wanted to differentiate the state between a claim being uninitialized, and a claim being initialized to empty.

So we use pointers to store values:

type stdToken struct {
  ....
  issuer *string // if nil, uninitialized. if &(""), initialized to empty
}

This is fine for us, but we doubt that this would be something users would want to do. This is a subtle difference, but cluttering up the API with slight variations of the same type (i.e. pointers vs non-pointers) seemed like a bad idea to us.

token.Issuer = &issuer // want to avoid this

token.Set(jwt.IssuerKey, "foobar") // so this is what we picked

This way users no longer need to care how the data is internally stored.

Allow more than one type of token through the same interface

dgrijalva/jwt-go does this in a different way, but we felt that it would be more intuitive for all tokens to follow a single interface so there is fewer type conversions required.

See the openid token for an example.

Documentation

Overview

Package jwt implements JSON Web Tokens as described in https://tools.ietf.org/html/rfc7519

Index

Constants

View Source
const (
	AudienceKey   = "aud"
	ExpirationKey = "exp"
	IssuedAtKey   = "iat"
	IssuerKey     = "iss"
	JwtIDKey      = "jti"
	NotBeforeKey  = "nbf"
	SubjectKey    = "sub"
)

Variables

This section is empty.

Functions

func Equal

func Equal(t1, t2 Token) bool

Equal compares two JWT tokens. Do not use `reflect.Equal` or the like to compare tokens as they will also compare extra detail such as sync.Mutex objects used to control concurrent access.

The comparison for values is currently done using a simple equality ("=="), except for time.Time, which uses time.Equal after dropping the monotonic clock and truncating the values to 1 second accuracy.

if both t1 and t2 are nil, returns true

func InvalidAudienceError

func InvalidAudienceError() error

InvalidAudienceError returns the immutable error used when `aud` claim is not satisfied

The return value should only be used for comparison using `errors.Is()`

func InvalidIssuedAtError

func InvalidIssuedAtError() error

InvalidIssuedAtError returns the immutable error used when `iat` claim is not satisfied

The return value should only be used for comparison using `errors.Is()`

func InvalidIssuerError

func InvalidIssuerError() error

InvalidIssuerError returns the immutable error used when `iss` claim is not satisfied

The return value should only be used for comparison using `errors.Is()`

func MissingRequiredClaimError

func MissingRequiredClaimError() error

MissingRequiredClaimError returns the immutable error used when the claim specified by `jwt.IsRequired()` is not present.

The return value should only be used for comparison using `errors.Is()`

func ParseError

func ParseError() error

ParseError returns an error that can be passed to `errors.Is` to check if the error is a parse error.

func RegisterCustomField

func RegisterCustomField(name string, object interface{})

RegisterCustomField allows users to specify that a private field be decoded as an instance of the specified type. This option has a global effect.

For example, suppose you have a custom field `x-birthday`, which you want to represent as a string formatted in RFC3339 in JSON, but want it back as `time.Time`.

In such case you would register a custom field as follows

jwt.RegisterCustomField(`x-birthday`, time.Time{})

Then you can use a `time.Time` variable to extract the value of `x-birthday` field, instead of having to use `interface{}` and later convert it to `time.Time`

var bday time.Time
_ = token.Get(`x-birthday`, &bday)

If you need a more fine-tuned control over the decoding process, you can register a `CustomDecoder`. For example, below shows how to register a decoder that can parse RFC822 format string:

jwt.RegisterCustomField(`x-birthday`, jwt.CustomDecodeFunc(func(data []byte) (interface{}, error) {
  return time.Parse(time.RFC822, string(data))
}))

Please note that use of custom fields can be problematic if you are using a library that does not implement MarshalJSON/UnmarshalJSON and you try to roundtrip from an object to JSON, and then back to an object. For example, in the above example, you can _parse_ time values formatted in the format specified in RFC822, but when you convert an object into JSON, it will be formatted in RFC3339, because that's what `time.Time` likes to do. To avoid this, it's always better to use a custom type that wraps your desired type (in this case `time.Time`) and implement MarshalJSON and UnmashalJSON.

func SetValidationCtxClock

func SetValidationCtxClock(ctx context.Context, cl Clock) context.Context

func SetValidationCtxSkew

func SetValidationCtxSkew(ctx context.Context, dur time.Duration) context.Context

func SetValidationCtxTruncation

func SetValidationCtxTruncation(ctx context.Context, dur time.Duration) context.Context

func Settings

func Settings(options ...GlobalOption)

Settings controls global settings that are specific to JWTs.

func Sign

func Sign(t Token, options ...SignOption) ([]byte, error)

Sign is a convenience function to create a signed JWT token serialized in compact form.

It accepts either a raw key (e.g. rsa.PrivateKey, ecdsa.PrivateKey, etc) or a jwk.Key, and the name of the algorithm that should be used to sign the token.

If the key is a jwk.Key and the key contains a key ID (`kid` field), then it is added to the protected header generated by the signature

The algorithm specified in the `alg` parameter must be able to support the type of key you provided, otherwise an error is returned. For convenience `alg` is of type jwa.KeyAlgorithm so you can pass the return value of `(jwk.Key).Algorithm()` directly, but in practice it must be an instance of jwa.SignatureAlgorithm, otherwise an error is returned.

The protected header will also automatically have the `typ` field set to the literal value `JWT`, unless you provide a custom value for it by jws.WithProtectedHeaders option, that can be passed to `jwt.WithKey“.

func TokenExpiredError

func TokenExpiredError() error

TokenExpiredError returns the immutable error used when `exp` claim is not satisfied.

The return value should only be used for comparison using `errors.Is()`

func TokenNotYetValidError

func TokenNotYetValidError() error

TokenNotYetValidError returns the immutable error used when `nbf` claim is not satisfied

The return value should only be used for comparison using `errors.Is()`

func UnknownPayloadTypeError

func UnknownPayloadTypeError() error

UnknownPayloadTypeError returns the opaque error value that is returned when `jwt.Parse` fails due to not being able to deduce the format of the incoming buffer

func Validate

func Validate(t Token, options ...ValidateOption) error

Validate makes sure that the essential claims stand.

See the various `WithXXX` functions for optional parameters that can control the behavior of this method.

func ValidateError

func ValidateError() error

func ValidationCtxSkew

func ValidationCtxSkew(ctx context.Context) time.Duration

func ValidationCtxTruncation

func ValidationCtxTruncation(ctx context.Context) time.Duration

Types

type Builder

type Builder struct {
	// contains filtered or unexported fields
}

Builder is a convenience wrapper around the New() constructor and the Set() methods to assign values to Token claims. Users can successively call Claim() on the Builder, and have it construct the Token when Build() is called. This alleviates the need for the user to check for the return value of every single Set() method call. Note that each call to Claim() overwrites the value set from the previous call.

func NewBuilder

func NewBuilder() *Builder

func (*Builder) Audience

func (b *Builder) Audience(v []string) *Builder

func (*Builder) Build

func (b *Builder) Build() (Token, error)

Build creates a new token based on the claims that the builder has received so far. If a claim cannot be set, then the method returns a nil Token with a en error as a second return value

Once `Build()` is called, all claims are cleared from the Builder, and the Builder can be reused to build another token

func (*Builder) Claim

func (b *Builder) Claim(name string, value interface{}) *Builder

func (*Builder) Expiration

func (b *Builder) Expiration(v time.Time) *Builder

func (*Builder) IssuedAt

func (b *Builder) IssuedAt(v time.Time) *Builder

func (*Builder) Issuer

func (b *Builder) Issuer(v string) *Builder

func (*Builder) JwtID

func (b *Builder) JwtID(v string) *Builder

func (*Builder) NotBefore

func (b *Builder) NotBefore(v time.Time) *Builder

func (*Builder) Subject

func (b *Builder) Subject(v string) *Builder

type Clock

type Clock interface {
	Now() time.Time
}

func ValidationCtxClock

func ValidationCtxClock(ctx context.Context) Clock

ValidationCtxClock returns the Clock object associated with the current validation context. This value will always be available during validation of tokens.

type ClockFunc

type ClockFunc func() time.Time

func (ClockFunc) Now

func (f ClockFunc) Now() time.Time

type CustomDecodeFunc

type CustomDecodeFunc = json.CustomDecodeFunc

type CustomDecoder

type CustomDecoder = json.CustomDecoder

type DecodeCtx

type DecodeCtx = json.DecodeCtx

type EncryptOption

type EncryptOption interface {
	Option
	// contains filtered or unexported methods
}

EncryptOption describes an Option that can be passed to (jwt.Serializer).Encrypt

func WithEncryptOption

func WithEncryptOption(v jwe.EncryptOption) EncryptOption

WithEncryptOption provides an escape hatch for cases where extra options to `(jws.Serializer).Encrypt()` must be specified when using `jwt.Sign()`. Normally you do not need to use this.

type GlobalOption

type GlobalOption interface {
	Option
	// contains filtered or unexported methods
}

GlobalOption describes an Option that can be passed to `Settings()`.

func WithFlattenAudience

func WithFlattenAudience(v bool) GlobalOption

WithFlattenAudience specifies the the `jwt.FlattenAudience` option on every token defaults to enabled. You can still disable this on a per-object basis using the `jwt.Options().Disable(jwt.FlattenAudience)` method call.

See the documentation for `jwt.TokenOptionSet`, `(jwt.Token).Options`, and `jwt.FlattenAudience` for more details

func WithNumericDateFormatPrecision

func WithNumericDateFormatPrecision(v int) GlobalOption

WithNumericDateFormatPrecision sets the precision up to which the library uses to format fractional dates found in the numeric date fields. Default is 0 (second, no fractions), max is 9 (nanosecond)

func WithNumericDateParsePedantic

func WithNumericDateParsePedantic(v bool) GlobalOption

WithNumericDateParsePedantic specifies if the parser should behave in a pedantic manner when parsing numeric dates. Normally this library attempts to interpret timestamps as a numeric value representing number of seconds (with an optional fractional part), but if that fails it tries to parse using a RFC3339 parser. This allows us to parse payloads from non-conforming servers.

However, when you set WithNumericDateParePedantic to `true`, the RFC3339 parser is not tried, and we expect a numeric value strictly

func WithNumericDateParsePrecision

func WithNumericDateParsePrecision(v int) GlobalOption

WithNumericDateParsePrecision sets the precision up to which the library uses to parse fractional dates found in the numeric date fields. Default is 0 (second, no fractions), max is 9 (nanosecond)

type Option

type Option = option.Interface

type ParseOption

type ParseOption interface {
	Option
	// contains filtered or unexported methods
}

ParseOption describes an Option that can be passed to `jwt.Parse()`. ParseOption also implements ReadFileOption, therefore it may be safely pass them to `jwt.ReadFile()`

func WithCookie

func WithCookie(v **http.Cookie) ParseOption

WithCookie is used to specify a variable to store the cookie used when `jwt.ParseCookie()` is called. This allows you to inspect the cookie for additional information after a successful parsing of the JWT token stored in the cookie.

While the type system allows this option to be passed to `jwt.Parse()` directly, doing so will have no effect. Only use it for HTTP request parsing functions

func WithCookieKey

func WithCookieKey(v string) ParseOption

WithCookieKey is used to specify cookie keys to search for tokens.

While the type system allows this option to be passed to `jwt.Parse()` directly, doing so will have no effect. Only use it for HTTP request parsing functions

func WithFormKey

func WithFormKey(v string) ParseOption

WithFormKey is used to specify header keys to search for tokens.

While the type system allows this option to be passed to jwt.Parse() directly, doing so will have no effect. Only use it for HTTP request parsing functions

func WithHeaderKey

func WithHeaderKey(v string) ParseOption

WithHeaderKey is used to specify header keys to search for tokens.

While the type system allows this option to be passed to `jwt.Parse()` directly, doing so will have no effect. Only use it for HTTP request parsing functions

func WithKeyProvider

func WithKeyProvider(v jws.KeyProvider) ParseOption

WithKeyProvider allows users to specify an object to provide keys to sign/verify tokens using arbitrary code. Please read the documentation for `jws.KeyProvider` in the `jws` package for details on how this works.

func WithKeySet

func WithKeySet(set jwk.Set, options ...interface{}) ParseOption

WithKeySet forces the Parse method to verify the JWT message using one of the keys in the given key set.

Key IDs (`kid`) in the JWS message and the JWK in the given `jwk.Set` must match in order for the key to be a candidate to be used for verification.

This is for security reasons. If you must disable it, you can do so by specifying `jws.WithRequireKid(false)` in the suboptions. But we don't recommend it unless you know exactly what the security implications are

When using this option, keys MUST have a proper 'alg' field set. This is because we need to know the exact algorithm that you (the user) wants to use to verify the token. We do NOT trust the token's headers, because they can easily be tampered with.

However, there _is_ a workaround if you do understand the risks of allowing a library to automatically choose a signature verification strategy, and you do not mind the verification process having to possibly attempt using multiple times before succeeding to verify. See `jws.InferAlgorithmFromKey` option

If you have only one key in the set, and are sure you want to use that key, you can use the `jwt.WithDefaultKey` option.

func WithPedantic

func WithPedantic(v bool) ParseOption

WithPedantic enables pedantic mode for parsing JWTs. Currently this only applies to checking for the correct `typ` and/or `cty` when necessary.

func WithToken

func WithToken(v Token) ParseOption

WithToken specifies the token instance in which the resulting JWT is stored when parsing JWT tokens

func WithTypedClaim

func WithTypedClaim(name string, object interface{}) ParseOption

WithTypedClaim allows a private claim to be parsed into the object type of your choice. It works much like the RegisterCustomField, but the effect is only applicable to the jwt.Parse function call which receives this option.

While this can be extremely useful, this option should be used with caution: There are many caveats that your entire team/user-base needs to be aware of, and therefore in general its use is discouraged. Only use it when you know what you are doing, and you document its use clearly for others.

First and foremost, this is a "per-object" option. Meaning that given the same serialized format, it is possible to generate two objects whose internal representations may differ. That is, if you parse one _WITH_ the option, and the other _WITHOUT_, their internal representation may completely differ. This could potentially lead to problems.

Second, specifying this option will slightly slow down the decoding process as it needs to consult multiple definitions sources (global and local), so be careful if you are decoding a large number of tokens, as the effects will stack up.

Finally, this option will also NOT work unless the tokens themselves support such parsing mechanism. For example, while tokens obtained from `jwt.New()` and `openid.New()` will respect this option, if you provide your own custom token type, it will need to implement the TokenWithDecodeCtx interface.

func WithValidate

func WithValidate(v bool) ParseOption

WithValidate is passed to `Parse()` method to denote that the validation of the JWT token should be performed (or not) after a successful parsing of the incoming payload.

This option is enabled by default.

If you would like disable validation, you must use `jwt.WithValidate(false)` or use `jwt.ParseInsecure()`

func WithVerify

func WithVerify(v bool) ParseOption

WithVerify is passed to `Parse()` method to denote that the signature verification should be performed after a successful deserialization of the incoming payload.

This option is enabled by default.

If you do not provide any verification key sources, `jwt.Parse()` would return an error.

If you would like to only parse the JWT payload and not verify it, you must use `jwt.WithVerify(false)` or use `jwt.ParseInsecure()`

func WithVerifyAuto

func WithVerifyAuto(f jwk.Fetcher, options ...jwk.FetchOption) ParseOption

WithVerifyAuto specifies that the JWS verification should be attempted by using the data available in the JWS message. Currently only verification method available is to use the keys available in the JWKS URL pointed in the `jku` field.

Please read the documentation for `jws.VerifyAuto` for more details.

type ReadFileOption

type ReadFileOption interface {
	Option
	// contains filtered or unexported methods
}

ReadFileOption is a type of `Option` that can be passed to `jws.ReadFile`

func WithFS

func WithFS(v fs.FS) ReadFileOption

WithFS specifies the source `fs.FS` object to read the file from.

type SerializeCtx

type SerializeCtx interface {
	Step() int
	Nested() bool
}

type SerializeStep

type SerializeStep interface {
	Serialize(SerializeCtx, interface{}) (interface{}, error)
}

type Serializer

type Serializer struct {
	// contains filtered or unexported fields
}

Serializer is a generic serializer for JWTs. Whereas other convenience functions can only do one thing (such as generate a JWS signed JWT), Using this construct you can serialize the token however you want.

By default, the serializer only marshals the token into a JSON payload. You must set up the rest of the steps that should be taken by the serializer.

For example, to marshal the token into JSON, then apply JWS and JWE in that order, you would do:

serialized, err := jwt.NewSerializer().
   Sign(jwa.RS256, key).
   Encrypt(jwa.RSA_OAEP, key.PublicKey).
   Serialize(token)

The `jwt.Sign()` function is equivalent to

serialized, err := jwt.NewSerializer().
   Sign(...args...).
   Serialize(token)

func NewSerializer

func NewSerializer() *Serializer

NewSerializer creates a new empty serializer.

func (*Serializer) Encrypt

func (s *Serializer) Encrypt(options ...EncryptOption) *Serializer

Encrypt specifies the JWT to be serialized as an encrypted payload.

One notable difference between this method and `jwe.Encrypt()` is that while `jwe.Encrypt()` OVERWRITES the previous headers when `jwe.WithProtectedHeaders()` is provided, this method MERGES them. This is due to the fact that we MUST add some extra headers to construct a proper JWE message. Be careful when you pass multiple `jwe.EncryptOption`s.

func (*Serializer) Reset

func (s *Serializer) Reset() *Serializer

Reset clears all of the registered steps.

func (*Serializer) Serialize

func (s *Serializer) Serialize(t Token) ([]byte, error)

func (*Serializer) Sign

func (s *Serializer) Sign(options ...SignOption) *Serializer

func (*Serializer) Step

func (s *Serializer) Step(step SerializeStep) *Serializer

Step adds a new Step to the serialization process

type SignEncryptParseOption

type SignEncryptParseOption interface {
	Option
	// contains filtered or unexported methods
}

SignEncryptParseOption describes an Option that can be passed to both `jwt.Sign()` or `jwt.Parse()`

func WithKey

func WithKey(alg jwa.KeyAlgorithm, key interface{}, suboptions ...Option) SignEncryptParseOption

WithKey is a multipurpose option. It can be used for either jwt.Sign, jwt.Parse (and its siblings), and jwt.Serializer methods. For signatures, please see the documentation for `jws.WithKey` for more details. For encryption, please see the documentation for `jwe.WithKey`.

It is the caller's responsibility to match the suboptions to the operation that they are performing. For example, you are not allowed to do this, because the operation is to generate a signature, and yet you are passing options for jwe:

jwt.Sign(token, jwt.WithKey(alg, key, jweOptions...))

In the above example, the creation of the option via `jwt.WithKey()` will work, but when `jwt.Sign()` is called, the fact that you passed JWE suboptions will be detected, and an error will occur.

type SignOption

type SignOption interface {
	Option
	// contains filtered or unexported methods
}

SignOption describes an Option that can be passed to `jwt.Sign()` or (jwt.Serializer).Sign

func WithInsecureNoSignature

func WithInsecureNoSignature() SignOption

func WithSignOption

func WithSignOption(v jws.SignOption) SignOption

WithSignOption provides an escape hatch for cases where extra options to `jws.Sign()` must be specified when using `jwt.Sign()`. Normally you do not need to use this.

type Token

type Token interface {
	// Audience returns the value for "aud" field of the token
	Audience() ([]string, bool)

	// Expiration returns the value for "exp" field of the token
	Expiration() (time.Time, bool)

	// IssuedAt returns the value for "iat" field of the token
	IssuedAt() (time.Time, bool)

	// Issuer returns the value for "iss" field of the token
	Issuer() (string, bool)

	// JwtID returns the value for "jti" field of the token
	JwtID() (string, bool)

	// NotBefore returns the value for "nbf" field of the token
	NotBefore() (time.Time, bool)

	// Subject returns the value for "sub" field of the token
	Subject() (string, bool)

	// Get is used to extract the value of any claim, including non-standard claims, out of the token.
	//
	// The first argument is the name of the claim. The second argument is a pointer
	// to a variable that will receive the value of the claim. The method returns
	// an error if the claim does not exist, or if the value cannot be assigned to
	// the destination variable.  Note that a field is considered to "exist" even if
	// the value is empty-ish (e.g. 0, false, ""), as long as it is explicitly set.
	//
	// For standard claims, you can use the corresponding getter method, such as
	// `Issuer()`, `Subject()`, `Audience()`, `IssuedAt()`, `NotBefore()`, `ExpiresAt()`
	//
	// Note that fields of JWS/JWE are NOT accessible through this method. You need
	// to use `jws.Parse` and `jwe.Parse` to obtain the JWS/JWE message (and NOT
	// the payload, which presumably is the JWT), and then use their `Get` methods in their respective packages
	Get(string, interface{}) error

	// Set assigns a value to the corresponding field in the token. Some
	// pre-defined fields such as `nbf`, `iat`, `iss` need their values to
	// be of a specific type. See the other getter methods in this interface
	// for the types of each of these fields
	Set(string, interface{}) error

	// Has returns true if the specified claim has a value, even if
	// the value is empty-ish (e.g. 0, false, "")  as long as it has been
	// explicitly set.
	Has(string) bool
	Remove(string) error

	// Options returns the per-token options associated with this token.
	// The options set value will be copied when the token is cloned via `Clone()`
	// but it will not survive when the token goes through marshaling/unmarshaling
	// such as `json.Marshal` and `json.Unmarshal`
	Options() *TokenOptionSet
	Clone() (Token, error)
	Keys() []string
}

Token represents a generic JWT token. which are type-aware (to an extent). Other claims may be accessed via the `Get`/`Set` methods but their types are not taken into consideration at all. If you have non-standard claims that you must frequently access, consider creating accessors functions like the following

func SetFoo(tok jwt.Token) error func GetFoo(tok jwt.Token) (*Customtyp, error)

Embedding jwt.Token into another struct is not recommended, because jwt.Token needs to handle private claims, and this really does not work well when it is embedded in other structure

func New

func New() Token

New creates a standard token, with minimal knowledge of possible claims. Standard claims include"aud", "exp", "iat", "iss", "jti", "nbf" and "sub". Convenience accessors are provided for these standard claims

func Parse

func Parse(s []byte, options ...ParseOption) (Token, error)

Parse parses the JWT token payload and creates a new `jwt.Token` object. The token must be encoded in JWS compact format, or a raw JSON form of JWT without any signatures.

If you need JWE support on top of JWS, you will need to rollout your own workaround.

If the token is signed, and you want to verify the payload matches the signature, you must pass the jwt.WithKey(alg, key) or jwt.WithKeySet(jwk.Set) option. If you do not specify these parameters, no verification will be performed.

During verification, if the JWS headers specify a key ID (`kid`), the key used for verification must match the specified ID. If you are somehow using a key without a `kid` (which is highly unlikely if you are working with a JWT from a well-know provider), you can work around this by modifying the `jwk.Key` and setting the `kid` header.

If you also want to assert the validity of the JWT itself (i.e. expiration and such), use the `Validate()` function on the returned token, or pass the `WithValidate(true)` option. Validate options can also be passed to `Parse`

This function takes both ParseOption and ValidateOption types: ParseOptions control the parsing behavior, and ValidateOptions are passed to `Validate()` when `jwt.WithValidate` is specified.

func ParseCookie

func ParseCookie(req *http.Request, name string, options ...ParseOption) (Token, error)

ParseCookie parses a JWT stored in a http.Cookie with the given name. If the specified cookie is not found, http.ErrNoCookie is returned.

func ParseForm

func ParseForm(values url.Values, name string, options ...ParseOption) (Token, error)

ParseForm parses a JWT stored in a url.Value.

func ParseHeader

func ParseHeader(hdr http.Header, name string, options ...ParseOption) (Token, error)

ParseHeader parses a JWT stored in a http.Header.

For the header "Authorization", it will strip the prefix "Bearer " and will treat the remaining value as a JWT.

func ParseInsecure

func ParseInsecure(s []byte, options ...ParseOption) (Token, error)

ParseInsecure is exactly the same as Parse(), but it disables signature verification and token validation.

You cannot override `jwt.WithVerify()` or `jwt.WithValidate()` using this function. Providing these options would result in an error

func ParseReader

func ParseReader(src io.Reader, options ...ParseOption) (Token, error)

ParseReader calls Parse against an io.Reader

func ParseRequest

func ParseRequest(req *http.Request, options ...ParseOption) (Token, error)

ParseRequest searches a http.Request object for a JWT token.

Specifying WithHeaderKey() will tell it to search under a specific header key. Specifying WithFormKey() will tell it to search under a specific form field.

If none of jwt.WithHeaderKey()/jwt.WithCookieKey()/jwt.WithFormKey() is used, "Authorization" header will be searched. If any of these options are specified, you must explicitly re-enable searching for "Authorization" header if you also want to search for it.

# searches for "Authorization"
jwt.ParseRequest(req)

# searches for "x-my-token" ONLY.
jwt.ParseRequest(req, jwt.WithHeaderKey("x-my-token"))

# searches for "Authorization" AND "x-my-token"
jwt.ParseRequest(req, jwt.WithHeaderKey("Authorization"), jwt.WithHeaderKey("x-my-token"))

Cookies are searched using (http.Request).Cookie(). If you have multiple cookies with the same name, and you want to search for a specific one that (http.Request).Cookie() would not return, you will need to implement your own logic to extract the cookie and use jwt.ParseString().

func ParseString

func ParseString(s string, options ...ParseOption) (Token, error)

ParseString calls Parse against a string

func ReadFile

func ReadFile(path string, options ...ReadFileOption) (Token, error)

type TokenOption

type TokenOption uint64

TokenOption describes a single token option that can be set on the per-token option set (TokenOptionSet)

const (
	// FlattenAudience option controls whether the "aud" claim should be flattened
	// to a single string upon the token being serialized to JSON.
	//
	// This is sometimes important when a JWT consumer does not understand that
	// the "aud" claim can actually take the form of an array of strings.
	// (We have been notified by users that AWS Cognito has manifested this behavior
	// at some point)
	//
	// Unless the global option is set using `jwt.Settings()`, the default value is
	// `disabled`, which means that "aud" claims are always rendered as a arrays of
	// strings when serialized to JSON.
	FlattenAudience TokenOption = 1 << iota

	// MaxPerTokenOption is a marker to denote the last value that an option can take.
	// This value has no meaning other than to be used as a marker.
	MaxPerTokenOption
)

func (TokenOption) String

func (i TokenOption) String() string

func (TokenOption) Value

func (o TokenOption) Value() uint64

Value returns the uint64 value of a single option

type TokenOptionSet

type TokenOptionSet uint64

TokenOptionSet is a bit flag containing per-token options.

func DefaultOptionSet

func DefaultOptionSet() TokenOptionSet

DefaultOptionSet creates a new TokenOptionSet using the default option set. This may differ depending on if/when functions that change the global state has been called, such as `jwt.Settings`

func (*TokenOptionSet) Clear

func (o *TokenOptionSet) Clear()

Clear sets all bits to zero, effectively disabling all options

func (*TokenOptionSet) Disable

func (o *TokenOptionSet) Disable(flag TokenOption)

Enable sets the appropriate value to disable the option in the option set

func (*TokenOptionSet) Enable

func (o *TokenOptionSet) Enable(flag TokenOption)

Enable sets the appropriate value to enable the option in the option set

func (TokenOptionSet) IsEnabled

func (o TokenOptionSet) IsEnabled(flag TokenOption) bool

IsEnabled returns true if the given bit on the option set is enabled.

func (*TokenOptionSet) Set

func (o *TokenOptionSet) Set(s TokenOptionSet)

Set sets the value of this option set, effectively *replacing* the entire option set with the new value. This is NOT the same as Enable/Disable.

func (TokenOptionSet) Value

func (o TokenOptionSet) Value() uint64

Value returns the uint64 bit flag value of an option set

type TokenWithDecodeCtx

type TokenWithDecodeCtx = json.DecodeCtxContainer

type ValidateOption

type ValidateOption interface {
	Option
	// contains filtered or unexported methods
}

ValidateOption describes an Option that can be passed to Validate(). ValidateOption also implements ParseOption, therefore it may be safely passed to `Parse()` (and thus `jwt.ReadFile()`)

func WithAcceptableSkew

func WithAcceptableSkew(v time.Duration) ValidateOption

WithAcceptableSkew specifies the duration in which exp, iat and nbf claims may differ by. This value should be positive

func WithAudience

func WithAudience(s string) ValidateOption

WithAudience specifies that expected audience value. `Validate()` will return true if one of the values in the `aud` element matches this value. If not specified, the value of `aud` is not verified at all.

func WithClaimValue

func WithClaimValue(name string, v interface{}) ValidateOption

WithClaimValue specifies the expected value for a given claim

func WithClock

func WithClock(v Clock) ValidateOption

WithClock specifies the `Clock` to be used when verifying exp, iat and nbf claims.

func WithContext

func WithContext(v context.Context) ValidateOption

WithContext allows you to specify a context.Context object to be used with `jwt.Validate()` option.

Please be aware that in the next major release of this library, `jwt.Validate()`'s signature will change to include an explicit `context.Context` object.

func WithIssuer

func WithIssuer(s string) ValidateOption

WithIssuer specifies that expected issuer value. If not specified, the value of issuer is not verified at all.

func WithJwtID

func WithJwtID(s string) ValidateOption

WithJwtID specifies that expected jti value. If not specified, the value of jti is not verified at all.

func WithMaxDelta

func WithMaxDelta(dur time.Duration, c1, c2 string) ValidateOption

WithMaxDelta specifies that given two claims `c1` and `c2` that represent time, the difference in time.Duration must be less than equal to the value specified by `d`. If `c1` or `c2` is the empty string, the current time (as computed by `time.Now` or the object passed via `WithClock()`) is used for the comparison.

`c1` and `c2` are also assumed to be required, therefore not providing either claim in the token will result in an error.

Because there is no way of reliably knowing how to parse private claims, we currently only support `iat`, `exp`, and `nbf` claims.

If the empty string is passed to c1 or c2, then the current time (as calculated by time.Now() or the clock object provided via WithClock()) is used.

For example, in order to specify that `exp` - `iat` should be less than 10*time.Second, you would write

jwt.Validate(token, jwt.WithMaxDelta(10*time.Second, jwt.ExpirationKey, jwt.IssuedAtKey))

If AcceptableSkew of 2 second is specified, the above will return valid for any value of `exp` - `iat` between 8 (10-2) and 12 (10+2).

func WithMinDelta

func WithMinDelta(dur time.Duration, c1, c2 string) ValidateOption

WithMinDelta is almost exactly the same as WithMaxDelta, but force validation to fail if the difference between time claims are less than dur.

For example, in order to specify that `exp` - `iat` should be greater than 10*time.Second, you would write

jwt.Validate(token, jwt.WithMinDelta(10*time.Second, jwt.ExpirationKey, jwt.IssuedAtKey))

The validation would fail if the difference is less than 10 seconds.

func WithRequiredClaim

func WithRequiredClaim(name string) ValidateOption

WithRequiredClaim specifies that the claim identified the given name must exist in the token. Only the existence of the claim is checked: the actual value associated with that field is not checked.

func WithResetValidators

func WithResetValidators(v bool) ValidateOption

WithResetValidators specifies that the default validators should be reset before applying the custom validators. By default `jwt.Validate()` checks for the validity of JWT by checking `exp`, `nbf`, and `iat`, even when you specify more validators through other options.

You SHOULD NOT use this option unless you know exactly what you are doing, as this will pose significant security issues when used incorrectly.

Using this option with the value `true` will remove all default checks, and will expect you to specify validators as options. This is useful when you want to skip the default validators and only use specific validators, such as for https://openid.net/specs/openid-connect-rpinitiated-1_0.html, where the token could be accepted even if the token is expired.

If you set this option to true and you do not specify any validators, `jwt.Validate()` will return an error.

The default value is `false` (`iat`, `exp`, and `nbf` are automatically checked).

func WithSubject

func WithSubject(s string) ValidateOption

WithSubject specifies that expected subject value. If not specified, the value of subject is not verified at all.

func WithTruncation

func WithTruncation(v time.Duration) ValidateOption

WithTruncation specifies the amount that should be used when truncating time values used during time-based validation routines. By default time values are truncated down to second accuracy. If you want to use sub-second accuracy, you will need to set this value to 0.

func WithValidator

func WithValidator(v Validator) ValidateOption

WithValidator validates the token with the given Validator.

For example, in order to validate tokens that are only valid during August, you would write

validator := jwt.ValidatorFunc(func(_ context.Context, t jwt.Token) error {
	if time.Now().Month() != 8 {
		return fmt.Errorf(`tokens are only valid during August!`)
	}
	return nil
})
err := jwt.Validate(token, jwt.WithValidator(validator))

type Validator

type Validator interface {
	// Validate should return an error if a required conditions is not met.
	Validate(context.Context, Token) error
}

Validator describes interface to validate a Token.

func ClaimContainsString

func ClaimContainsString(name, value string) Validator

ClaimContainsString can be used to check if the claim called `name`, which is expected to be a list of strings, contains `value`. Currently, because of the implementation, this will probably only work for `aud` fields.

func ClaimValueIs

func ClaimValueIs(name string, value interface{}) Validator

ClaimValueIs creates a Validator that checks if the value of claim `name` matches `value`. The comparison is done using a simple `==` comparison, and therefore complex comparisons may fail using this code. If you need to do more, use a custom Validator.

func IsExpirationValid

func IsExpirationValid() Validator

IsExpirationValid is one of the default validators that will be executed. It does not need to be specified by users, but it exists as an exported field so that you can check what it does.

The supplied context.Context object must have the "clock" and "skew" populated with appropriate values using SetValidationCtxClock() and SetValidationCtxSkew()

func IsIssuedAtValid

func IsIssuedAtValid() Validator

IsIssuedAtValid is one of the default validators that will be executed. It does not need to be specified by users, but it exists as an exported field so that you can check what it does.

The supplied context.Context object must have the "clock" and "skew" populated with appropriate values using SetValidationCtxClock() and SetValidationCtxSkew()

func IsNbfValid

func IsNbfValid() Validator

IsNbfValid is one of the default validators that will be executed. It does not need to be specified by users, but it exists as an exported field so that you can check what it does.

The supplied context.Context object must have the "clock" and "skew" populated with appropriate values using SetValidationCtxClock() and SetValidationCtxSkew()

func IsRequired

func IsRequired(name string) Validator

IsRequired creates a Validator that checks if the required claim `name` exists in the token

func MaxDeltaIs

func MaxDeltaIs(c1, c2 string, dur time.Duration) Validator

MaxDeltaIs implements the logic behind `WithMaxDelta()` option

func MinDeltaIs

func MinDeltaIs(c1, c2 string, dur time.Duration) Validator

MinDeltaIs implements the logic behind `WithMinDelta()` option

type ValidatorFunc

type ValidatorFunc func(context.Context, Token) error

ValidatorFunc is a type of Validator that does not have any state, that is implemented as a function

func (ValidatorFunc) Validate

func (vf ValidatorFunc) Validate(ctx context.Context, tok Token) error

Directories

Path Synopsis
internal
Package openid provides a specialized token that provides utilities to work with OpenID JWT tokens.
Package openid provides a specialized token that provides utilities to work with OpenID JWT tokens.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL