jwt

package module
v0.0.0-...-0cfe6fb Latest Latest
Warning

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

Go to latest
Published: Aug 8, 2020 License: MIT Imports: 15 Imported by: 0

README

Json Web Token (RFC7519) Library

Mission

This library has two goals.

  • Make generating and validating JWTs as intuitive and easy as possible, with the ability to add complexity if the developer chooses
  • Follow RFC7519 and implement the recommended cryptographic algorithms for both JWS and JWE
Disclaimer

This library is extremely new. Integrate it with your applications at your own risk. Notably, the library could rapidly change in design - causing breaking changes.

Quickstart

If all you want to do is generate and validate a JWT, use these examples.

Generating a HS256 JWT
package main

import (
    "fmt"
    . "github.com/bmwadforth/jwt"
    "log"
    "time"
)

func main(){
    key := []byte("Key")

    claims := NewClaimSet()
    claims.Add(string(Audience), "your_audience")
    claims.Add(string(Subject), "your_subject")
    claims.Add(string(IssuedAt), time.Now())
    claims.Add("my_claim", "some_value")

    //Create new HS256 token, set claims and key
    token, err := New(HS256, claims, key)
    if err != nil {
        log.Fatal(err)
    }

    //Encode token
    tokenBytes, err := token.Encode()
    fmt.Println(string(tokenBytes))
    //eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ5b3VyX2F1ZGllbmNlIiwiaWF0IjoiMjAyMC0wMS0wMlQyMTo1NTo1OS40MzE1ODErMTE6MDAiLCJteV9jbGFpbSI6InNvbWVfdmFsdWUiLCJzdWIiOiJ5b3VyX3N1YmplY3QifQ.PAR_a60R6VZakCmBZg8aMgt3eXDi-CMC4P4p08yJy-I
}
Validating a HS256 JWT
package main

import (
    "fmt"
    . "github.com/bmwadforth/jwt"
    "log"
)

func main(){
    key := []byte("Key")
    tokenString := "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOiJ5b3VyX2F1ZGllbmNlIiwiaWF0IjoiMjAyMC0wMS0wMlQyMTo1NTo1OS40MzE1ODErMTE6MDAiLCJteV9jbGFpbSI6InNvbWVfdmFsdWUiLCJzdWIiOiJ5b3VyX3N1YmplY3QifQ.PAR_a60R6VZakCmBZg8aMgt3eXDi-CMC4P4p08yJy-I"
    
    //Parse token string
    token, err := Parse(tokenString, key)
    if err != nil {
        log.Fatal(err)
    }
    
    //Validate token
    _, err = Validate(token)
    if err != nil {
        log.Fatal(err)
    }   
    
    //Token is valid
}
Custom Signing Method

If you would prefer to define your own JWS signing method, you can define your own signing function. Notably:

  • The signing function will always receive a base64 encoded header and payload as the bytes to sign, per the JWS specification
  • What you return from the signing function is base 64 encoded and attached to the signature component of the JWS

A good example of when you would want to implement your own signing function is when you want more control over how to sign your token. For example, RS256:

package main

import (
    "fmt"
    . "github.com/bmwadforth/jwt"
    "io/ioutil"
    "log"
    "crypto/x509"
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha256"
    "crypto"
    "encoding/pem"
)

func main(){
    b, _ := ioutil.ReadFile("./rsa_private.pem")

    block, _ := pem.Decode(b)
    key, _ := x509.ParsePKCS1PrivateKey(block.Bytes)

    token, err := New(RS256, NewClaimSet(), block.Bytes)
    if err != nil {
        log.Fatal(err)
    }

    //Before calling sign, set SignFunc
    token.SignFunc = func(t *Token, signingInput []byte) (bytes []byte, e error) {
        // crypto/rand.Reader is a good source of entropy for blinding the RSA
        // operation.
        rng := rand.Reader
        hashed := sha256.Sum256(signingInput)

        signature, err := rsa.SignPKCS1v15(rng, key, crypto.SHA256, hashed[:])
        if err != nil {
            return nil, err
        }

        return signature, nil
    }

    signedBytes, err := token.Sign()
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println(string(signedBytes))
    //eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.e30.uZTBWMOdIYMlSxyJgGOgjPXwISnMDzLyiOE5k9GK2ruWc2IvWkOLtmZ9ECOwDqwLM93WH7CMIP7IEOMVZJzkHkFj16GgQnz-KSgY9MK8fBROij4R09XyXVRMvmBjVAyPxBS8dK9j-FuZIceu5TEN3-FmjcTq87OQfc3-mO6_3mruQfg59m9dSbcVL2SEQrRyrG-Jitkma7f_up8BSJHt0Q08ASVBivHjws2Z_QGYb3NkrI0oEcH_yoXlvJohsEQtNaycFLGNDtzujABHp9ZT5a2L-U8WCf8K9JwttGnuVTMhDviEjWC2M2weXAB8WimiwqQB2zER-4ILpbUhhL_MjA
}
Custom Validation Method

Just as you can create a custom signing method, you can also create a custom validation method.

package main

import (
    "fmt"
    . "github.com/bmwadforth/jwt"
    "io/ioutil"
    "log"
    "crypto/x509"
    "crypto/rand"
    "crypto/rsa"
    "crypto/sha256"
    "crypto"
    "encoding/pem"
    "encoding/base64"
)

func main(){
    b, _ := ioutil.ReadFile("./rsa_private.pem")
    block, _ := pem.Decode(b)
    key, _ := x509.ParsePKCS1PrivateKey(block.Bytes)

    tokenString := "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.e30.uZTBWMOdIYMlSxyJgGOgjPXwISnMDzLyiOE5k9GK2ruWc2IvWkOLtmZ9ECOwDqwLM93WH7CMIP7IEOMVZJzkHkFj16GgQnz-KSgY9MK8fBROij4R09XyXVRMvmBjVAyPxBS8dK9j-FuZIceu5TEN3-FmjcTq87OQfc3-mO6_3mruQfg59m9dSbcVL2SEQrRyrG-Jitkma7f_up8BSJHt0Q08ASVBivHjws2Z_QGYb3NkrI0oEcH_yoXlvJohsEQtNaycFLGNDtzujABHp9ZT5a2L-U8WCf8K9JwttGnuVTMhDviEjWC2M2weXAB8WimiwqQB2zER-4ILpbUhhL_MjA"

    token, err := Parse(tokenString, b)
    if err != nil {
        log.Fatal(err)
    }

    //Before calling validate, set ValidateFunc
    token.ValidateFunc = func(t *Token) (b bool, e error) {
        headerB64, _ := t.Header.ToBase64()
        payloadB64, _ := t.Payload.ToBase64()
        hashed := sha256.Sum256([]byte(fmt.Sprintf("%s.%s", headerB64, payloadB64)))
        decodedSignature, err := base64.RawURLEncoding.DecodeString(string(t.Signature.Raw))
        if err != nil {
            return false, err
        }
        err = rsa.VerifyPKCS1v15(&key.PublicKey, crypto.SHA256, hashed[:], decodedSignature)
        if err != nil {
            return false, err
        }
        return true, nil
    }

    _, err = token.Validate()
    if err != nil {
        log.Fatal(err)
    }

    //Token is valid
}
Supported Algorithms

This library currently supports JWS only.

JWS
"alg" Param Digital Signature/MAC Algorithm Implementation Requirement Implemented
HS256 HMAC using SHA-256 Required
HS384 HMAC using SHA-384 Optional
HS512 HMAC using SHA-512 Optional
RS256 RSASSA-PKCS1-v1_5 using SHA-256 Recommended
RS384 RSASSA-PKCS1-v1_5 using SHA-384 Optional
RS512 RSASSA-PKCS1-v1_5 using SHA-512 Optional
ES256 ECDSA using P-256 and SHA-256 Recommended+
ES384 ECDSA using P-384 and SHA-384 Optional
ES512 ECDSA using P-521 and SHA-512 Optional
PS256 RSASSA-PSS using SHA-256 and MGF1 with SHA-256 Optional
PS384 RSASSA-PSS using SHA-384 and MGF1 with SHA-384 Optional
PS512 RSASSA-PSS using SHA-512 and MGF1 with SHA-512 Optional
none No digital signature or MAC performed Optional
JWE

JWE has not been implemented in this library yet

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Validate

func Validate(t *Token) (bool, error)

Types

type AlgorithmType

type AlgorithmType string
const (
	HS256 AlgorithmType = "HS256"

	RS256 AlgorithmType = "RS256"
	None  AlgorithmType = "none"
)

type ClaimSet

type ClaimSet struct {
	Claims map[string]interface{}
}

func NewClaimSet

func NewClaimSet() ClaimSet

func (*ClaimSet) Add

func (c *ClaimSet) Add(key string, value interface{}) error

func (*ClaimSet) Remove

func (c *ClaimSet) Remove(key string) error
type Header struct {
	Properties map[string]interface{}
	// contains filtered or unexported fields
}

func (*Header) FromBase64

func (h *Header) FromBase64(b []byte) (*Header, error)

Deserialize b64 into JSON and then into header struct

func (*Header) FromJson

func (h *Header) FromJson(b []byte) (*Header, error)

Deserialize JSON into header struct

func (*Header) ToBase64

func (h *Header) ToBase64() ([]byte, error)

Serialize header struct into JSON and then Encode in b64

func (*Header) ToJson

func (h *Header) ToJson() ([]byte, error)

Serialize header struct into JSON

type Payload

type Payload struct {
	ClaimSet
	// contains filtered or unexported fields
}

func (*Payload) FromBase64

func (p *Payload) FromBase64(b []byte) (*Payload, error)

Deserialize b64 into JSON and then into payload struct

func (*Payload) FromJson

func (p *Payload) FromJson(b []byte) (*Payload, error)

Deserialize JSON into payload struct

func (*Payload) ToBase64

func (p *Payload) ToBase64() ([]byte, error)

Serialize payload struct into JSON and then Encode in b64

func (*Payload) ToJson

func (p *Payload) ToJson() ([]byte, error)

Serialize payload struct into JSON

type RegisteredClaim

type RegisteredClaim string
const (
	Issuer         RegisteredClaim = "iss"
	Subject        RegisteredClaim = "sub"
	Audience       RegisteredClaim = "aud"
	ExpirationTime RegisteredClaim = "exp"
	NotBefore      RegisteredClaim = "nbf"
	IssuedAt       RegisteredClaim = "iat"
	JwtID          RegisteredClaim = "jti"
)

type SignFunc

type SignFunc func(t *Token, signingInput []byte) ([]byte, error)

type Signature

type Signature struct {
	Raw []byte
}

type Signer

type Signer struct {
	*Token
	SignFunc
}

type Token

type Token struct {
	Header
	Payload
	Signature
	SignFunc
	ValidateFunc
	// contains filtered or unexported fields
}

func New

func New(alg AlgorithmType, claims ClaimSet, key []byte) (*Token, error)

func Parse

func Parse(tokenString string, key []byte) (*Token, error)

func (*Token) Decode

func (t *Token) Decode() error

func (*Token) Encode

func (t *Token) Encode() ([]byte, error)

func (*Token) Sign

func (t *Token) Sign() ([]byte, error)

func (*Token) Validate

func (t *Token) Validate() (bool, error)

type TokenType

type TokenType string
const (
	JWS TokenType = "jws"
	JWE TokenType = "jwe"
)

func DetermineTokenType

func DetermineTokenType(alg AlgorithmType) (TokenType, error)

type ValidateFunc

type ValidateFunc func(t *Token) (bool, error)

type Validator

type Validator struct {
	*Token
	ValidateFunc
}

Jump to

Keyboard shortcuts

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