jwt

package
v0.6.0 Latest Latest
Warning

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

Go to latest
Published: Mar 28, 2024 License: MPL-2.0 Imports: 20 Imported by: 13

README

jwt

Go Reference

Package jwt provides signature verification and claims set validation for JSON Web Tokens (JWT) of the JSON Web Signature (JWS) form.

Primary types provided by the package:

  • KeySet: Represents a set of keys that can be used to verify the signatures of JWTs. A KeySet is expected to be backed by a set of local or remote keys.

  • Validator: Provides signature verification and claims set validation behavior for JWTs.

  • Expected: Defines the expected claims values to assert when validating a JWT.

  • Alg: Represents asymmetric signing algorithms.

Examples:

Please see docs_test.go for additional usage examples.

Documentation

Overview

Package jwt provides signature verification and claims set validation for JSON Web Tokens (JWT) of the JSON Web Signature (JWS) form.

JWT claims set validation provided by the package includes the option to validate all registered claim names defined in https://tools.ietf.org/html/rfc7519#section-4.1.

JOSE header validation provided by the the package includes the option to validate the "alg" (Algorithm) Header Parameter defined in https://tools.ietf.org/html/rfc7515#section-4.1.

JWT signature verification is supported by providing keys from the following sources:

  • JSON Web Key Set (JWKS) URL
  • OIDC Discovery mechanism
  • Local public keys

JWT signature verification supports the following asymmetric algorithms as defined in https://www.rfc-editor.org/rfc/rfc7518.html#section-3.1:

  • RS256: RSASSA-PKCS1-v1_5 using SHA-256
  • RS384: RSASSA-PKCS1-v1_5 using SHA-384
  • RS512: RSASSA-PKCS1-v1_5 using SHA-512
  • ES256: ECDSA using P-256 and SHA-256
  • ES384: ECDSA using P-384 and SHA-384
  • ES512: ECDSA using P-521 and SHA-512
  • PS256: RSASSA-PSS using SHA-256 and MGF1 with SHA-256
  • PS384: RSASSA-PSS using SHA-384 and MGF1 with SHA-384
  • PS512: RSASSA-PSS using SHA-512 and MGF1 with SHA-512
  • EdDSA: Ed25519 using SHA-512

Index

Examples

Constants

View Source
const DefaultLeewaySeconds = 150

DefaultLeewaySeconds defines the amount of leeway that's used by default for validating the "nbf" (Not Before) and "exp" (Expiration Time) claims.

Variables

This section is empty.

Functions

func ParsePublicKeyPEM

func ParsePublicKeyPEM(data []byte) (crypto.PublicKey, error)

ParsePublicKeyPEM is used to parse RSA and ECDSA public keys from PEMs. The given data must be of PEM-encoded x509 certificate or PKIX public key forms. It returns an *rsa.PublicKey or *ecdsa.PublicKey.

func SupportedSigningAlgorithm

func SupportedSigningAlgorithm(algs ...Alg) error

SupportedSigningAlgorithm returns an error if any of the given Algs are not supported signing algorithms.

Types

type Alg

type Alg string

Alg represents asymmetric signing algorithms

const (
	// JOSE asymmetric signing algorithm values as defined by RFC 7518.
	//
	// See: https://tools.ietf.org/html/rfc7518#section-3.1
	RS256 Alg = "RS256" // RSASSA-PKCS-v1.5 using SHA-256
	RS384 Alg = "RS384" // RSASSA-PKCS-v1.5 using SHA-384
	RS512 Alg = "RS512" // RSASSA-PKCS-v1.5 using SHA-512
	ES256 Alg = "ES256" // ECDSA using P-256 and SHA-256
	ES384 Alg = "ES384" // ECDSA using P-384 and SHA-384
	ES512 Alg = "ES512" // ECDSA using P-521 and SHA-512
	PS256 Alg = "PS256" // RSASSA-PSS using SHA256 and MGF1-SHA256
	PS384 Alg = "PS384" // RSASSA-PSS using SHA384 and MGF1-SHA384
	PS512 Alg = "PS512" // RSASSA-PSS using SHA512 and MGF1-SHA512
	EdDSA Alg = "EdDSA" // Ed25519 using SHA-512
)

type Expected

type Expected struct {
	// The expected JWT "iss" (issuer) claim value. If empty, validation is skipped.
	Issuer string

	// The expected JWT "sub" (subject) claim value. If empty, validation is skipped.
	Subject string

	// The expected JWT "jti" (JWT ID) claim value. If empty, validation is skipped.
	ID string

	// The list of expected JWT "aud" (audience) claim values to match against.
	// The JWT claim will be considered valid if it matches any of the expected
	// audiences. If empty, validation is skipped.
	Audiences []string

	// SigningAlgorithms provides the list of expected JWS "alg" (algorithm) header
	// parameter values to match against. The JWS header parameter will be considered
	// valid if it matches any of the expected signing algorithms. The following
	// algorithms are supported: RS256, RS384, RS512, ES256, ES384, ES512, PS256,
	// PS384, PS512, EdDSA. If empty, defaults to RS256.
	SigningAlgorithms []Alg

	// NotBeforeLeeway provides the option to set an amount of leeway to use when
	// validating the "nbf" (Not Before) claim. If the duration is zero or not
	// provided, a default leeway of 150 seconds will be used. If the duration is
	// negative, no leeway will be used.
	NotBeforeLeeway time.Duration

	// ExpirationLeeway provides the option to set an amount of leeway to use when
	// validating the "exp" (Expiration Time) claim. If the duration is zero or not
	// provided, a default leeway of 150 seconds will be used. If the duration is
	// negative, no leeway will be used.
	ExpirationLeeway time.Duration

	// ClockSkewLeeway provides the option to set an amount of leeway to use when
	// validating the "nbf" (Not Before), "exp" (Expiration Time), and "iat" (Issued At)
	// claims. If the duration is zero or not provided, a default leeway of 60 seconds
	// will be used. If the duration is negative, no leeway will be used.
	ClockSkewLeeway time.Duration

	// Now provides the option to specify a func for determining what the current time is.
	// The func will be used to provide the current time when validating a JWT with respect to
	// the "nbf" (Not Before), "exp" (Expiration Time), and "iat" (Issued At) claims. If not
	// provided, defaults to returning time.Now().
	Now func() time.Time
}

Expected defines the expected claims values to assert when validating a JWT. For claims that involve validation of the JWT with respect to time, leeway fields are provided to account for potential clock skew.

type KeySet

type KeySet interface {
	// VerifySignature parses the given JWT, verifies its signature, and returns the claims in its payload.
	// The given JWT must be of the JWS compact serialization form.
	VerifySignature(ctx context.Context, token string) (claims map[string]interface{}, err error)
}

KeySet represents a set of keys that can be used to verify the signatures of JWTs. A KeySet is expected to be backed by a set of local or remote keys.

func NewJSONWebKeySet

func NewJSONWebKeySet(ctx context.Context, jwksURL string, jwksCAPEM string) (KeySet, error)

NewJSONWebKeySet returns a KeySet that verifies JWT signatures using keys from the JSON Web Key Set (JWKS) at the given jwksURL. The client used to obtain the remote JWKS will verify server certificates using the root certificates provided by jwksCAPEM. If jwksCAPEM is not provided, system certificates are used.

Example
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/hashicorp/cap/jwt"
)

func main() {
	ctx := context.Background()

	keySet, err := jwt.NewJSONWebKeySet(ctx, "your_jwks_url", "your_jwks_ca_pem")
	if err != nil {
		log.Fatal(err)
	}

	token := "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJleHBfaXNzIiwiZXhwIjoxNTI2MjM5MDIyfQ.XG1xYJcuPMfgu8xkMzVjkYK2WIUyl4-A1Zq1j4Dfr99-PJUN36ZAgi8Fj08modiexXETrg05MqSxkJAE5Czns1IhqEEypx6xfYHSINp0SLKxBFHPA4BCi0IW83T-e225JjjVEGFR_Wo8QM6Rc-qQVJ9bqwKD4kcbQeMACkgGFcgNurtNkOM9vtOEs0Pe9tb4nHYw4ef1stCytTi9GFZwGoHQf0pjpWCpjlxaFIR4vmHQ4YB3w29o_tKN6zqyA2FITnvkzGnaLvdPecJNskRSCPUTRfYcVVNXCOnCvTdpvwK-c4nCs5yGnw3eeFoT6mhQSp39KYti1MpHNQTYwZrLTA"
	claims, err := keySet.VerifySignature(ctx, token)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(claims)
}
Output:

func NewOIDCDiscoveryKeySet

func NewOIDCDiscoveryKeySet(ctx context.Context, issuer string, issuerCAPEM string) (KeySet, error)

NewOIDCDiscoveryKeySet returns a KeySet that verifies JWT signatures using keys from the JSON Web Key Set (JWKS) published in the discovery document at the given issuer URL. The client used to obtain the remote keys will verify server certificates using the root certificates provided by issuerCAPEM. If issuerCAPEM is not provided, system certificates are used.

Example
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/hashicorp/cap/jwt"
)

func main() {
	ctx := context.Background()

	keySet, err := jwt.NewOIDCDiscoveryKeySet(ctx, "your_issuer_url", "your_issuer_ca_pem")
	if err != nil {
		log.Fatal(err)
	}

	token := "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJleHBfaXNzIiwiZXhwIjoxNTI2MjM5MDIyfQ.XG1xYJcuPMfgu8xkMzVjkYK2WIUyl4-A1Zq1j4Dfr99-PJUN36ZAgi8Fj08modiexXETrg05MqSxkJAE5Czns1IhqEEypx6xfYHSINp0SLKxBFHPA4BCi0IW83T-e225JjjVEGFR_Wo8QM6Rc-qQVJ9bqwKD4kcbQeMACkgGFcgNurtNkOM9vtOEs0Pe9tb4nHYw4ef1stCytTi9GFZwGoHQf0pjpWCpjlxaFIR4vmHQ4YB3w29o_tKN6zqyA2FITnvkzGnaLvdPecJNskRSCPUTRfYcVVNXCOnCvTdpvwK-c4nCs5yGnw3eeFoT6mhQSp39KYti1MpHNQTYwZrLTA"
	claims, err := keySet.VerifySignature(ctx, token)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(claims)
}
Output:

func NewStaticKeySet

func NewStaticKeySet(publicKeys []crypto.PublicKey) (KeySet, error)

NewStaticKeySet returns a KeySet that verifies JWT signatures using the given publicKeys.

Example
package main

import (
	"context"
	"crypto"
	"crypto/rand"
	"crypto/rsa"
	"fmt"
	"log"

	"github.com/hashicorp/cap/jwt"
)

func main() {
	ctx := context.Background()

	rsaKey, err := rsa.GenerateKey(rand.Reader, 4096)
	if err != nil {
		log.Fatal(err)
	}

	keys := []crypto.PublicKey{
		rsaKey.Public(),
	}

	keySet, err := jwt.NewStaticKeySet(keys)
	if err != nil {
		log.Fatal(err)
	}

	token := "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJleHBfaXNzIiwiZXhwIjoxNTI2MjM5MDIyfQ.XG1xYJcuPMfgu8xkMzVjkYK2WIUyl4-A1Zq1j4Dfr99-PJUN36ZAgi8Fj08modiexXETrg05MqSxkJAE5Czns1IhqEEypx6xfYHSINp0SLKxBFHPA4BCi0IW83T-e225JjjVEGFR_Wo8QM6Rc-qQVJ9bqwKD4kcbQeMACkgGFcgNurtNkOM9vtOEs0Pe9tb4nHYw4ef1stCytTi9GFZwGoHQf0pjpWCpjlxaFIR4vmHQ4YB3w29o_tKN6zqyA2FITnvkzGnaLvdPecJNskRSCPUTRfYcVVNXCOnCvTdpvwK-c4nCs5yGnw3eeFoT6mhQSp39KYti1MpHNQTYwZrLTA"
	claims, err := keySet.VerifySignature(ctx, token)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(claims)
}
Output:

type Validator

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

Validator validates JSON Web Tokens (JWT) by providing signature verification and claims set validation. Validator can contain either a single or multiple KeySets and will attempt to verify the JWT by iterating through the configured KeySets.

func NewValidator

func NewValidator(keySets ...KeySet) (*Validator, error)

NewValidator returns a Validator that uses the given KeySet to verify JWT signatures.

func (*Validator) Validate

func (v *Validator) Validate(ctx context.Context, token string, expected Expected) (map[string]interface{}, error)

Validate validates JWTs of the JWS compact serialization form.

The given JWT is considered valid if:

  1. Its signature is successfully verified.
  2. Its claims set and header parameter values match what's given by Expected.
  3. It's valid with respect to the current time. This means that the current time must be within the times (inclusive) given by the "nbf" (Not Before) and "exp" (Expiration Time) claims and after the time given by the "iat" (Issued At) claim, with configurable leeway. See Expected.Now() for details on how the current time is provided for validation.
Example
package main

import (
	"context"
	"fmt"
	"log"

	"github.com/hashicorp/cap/jwt"
)

func main() {
	ctx := context.Background()

	keySet, err := jwt.NewJSONWebKeySet(ctx, "your_jwks_url", "your_jwks_ca_pem")
	if err != nil {
		log.Fatal(err)
	}

	validator, err := jwt.NewValidator(keySet)
	if err != nil {
		log.Fatal(err)
	}

	expected := jwt.Expected{
		Issuer:            "your_expected_issuer",
		Subject:           "your_expected_subject",
		ID:                "your_expected_jwt_id",
		Audiences:         []string{"your_expected_audiences"},
		SigningAlgorithms: []jwt.Alg{jwt.RS256},
	}

	token := "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJleHBfaXNzIiwiZXhwIjoxNTI2MjM5MDIyfQ.XG1xYJcuPMfgu8xkMzVjkYK2WIUyl4-A1Zq1j4Dfr99-PJUN36ZAgi8Fj08modiexXETrg05MqSxkJAE5Czns1IhqEEypx6xfYHSINp0SLKxBFHPA4BCi0IW83T-e225JjjVEGFR_Wo8QM6Rc-qQVJ9bqwKD4kcbQeMACkgGFcgNurtNkOM9vtOEs0Pe9tb4nHYw4ef1stCytTi9GFZwGoHQf0pjpWCpjlxaFIR4vmHQ4YB3w29o_tKN6zqyA2FITnvkzGnaLvdPecJNskRSCPUTRfYcVVNXCOnCvTdpvwK-c4nCs5yGnw3eeFoT6mhQSp39KYti1MpHNQTYwZrLTA"
	claims, err := validator.Validate(ctx, token, expected)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(claims)
}
Output:

func (*Validator) ValidateAllowMissingIatNbfExp added in v0.3.0

func (v *Validator) ValidateAllowMissingIatNbfExp(ctx context.Context, token string, expected Expected) (map[string]interface{}, error)

ValidateAllowMissingIatNbfExp validates JWTs of the JWS compact serialization form.

The given JWT is considered valid if:

  1. Its signature is successfully verified.
  2. Its claims set and header parameter values match what's given by Expected.
  3. It's valid with respect to the current time. This means that the current time must be within the times (inclusive) given by the "nbf" (Not Before) and "exp" (Expiration Time) claims and after the time given by the "iat" (Issued At) claim, with configurable leeway, if they are present. If all of "nbf", "exp", and "iat" are missing, then this check is skipped. See Expected.Now() for details on how the current time is provided for validation.

Jump to

Keyboard shortcuts

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