paseto

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Mar 11, 2018 License: MIT Imports: 21 Imported by: 0

README

Golang implementation of PASETO: Platform-Agnostic Security Tokens

License GoDoc Build Status Coverage Status Go Report Card

This is 100% compatible pure GO (Golang) implementation of PASETO library.

Paseto is everything you love about JOSE (JWT, JWE, JWS) without any of the many design deficits that plague the JOSE standards.

Contents

What is Paseto?

Paseto (Platform-Agnostic SEcurity TOkens) is a specification and reference implementation for secure stateless tokens.

Key Differences between Paseto and JWT

Unlike JSON Web Tokens (JWT), which gives developers more than enough rope with which to hang themselves, Paseto only allows secure operations. JWT gives you "algorithm agility", Paseto gives you "versioned protocols". It's incredibly unlikely that you'll be able to use Paseto in an insecure way.

Caution: Neither JWT nor Paseto were designed for stateless session management. Paseto is suitable for tamper-proof cookies, but cannot prevent replay attacks by itself.

Installation

To install the library use the following command:

$ go get -u github.com/o1egl/paseto

Usage

This library contains predefined JsonToken struct for using as payload but you are free to use any data types and structs you want. During encoding process payload of type string and []byte is used without transformation. For other data types library tries to encode payload to json.

Use general parser to parse all supported token versions:

b, err := hex.DecodeString("2d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0d0a4d494942496a414e42676b71686b6947397730424151454641414f43415138414d49494243674b43415145417878636e47724e4f6136426c41523458707050640d0a746146576946386f7279746c4b534d6a66446831314c687956627a4335416967556b706a457274394d7649482f46384d444a72324f39486b36594b454b574b6f0d0a72333566364b6853303679357a714f722b7a4e34312b39626a52365633322b527345776d5a737a3038375258764e41334e687242633264593647736e57336c5a0d0a34356f5341564a755639553667335a334a574138355972362b6350776134793755632f56726f6d7a674679627355656e33476f724254626a783142384f514a440d0a73652f4b6b6855433655693358384264514f473974523455454775742f6c39703970732b3661474d4c57694357495a54615456784d4f75653133596b777038740d0a3148467635747a6872493055635948687638464a6b315a6435386759464158634e797975737834346e6a6152594b595948646e6b4f6a486e33416b534c4d306b0d0a6c774944415141420d0a2d2d2d2d2d454e44205055424c4943204b45592d2d2d2d2d")
block, _ = pem.Decode(b)
rsaPubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
v1PublicKey := rsaPubInterface.(*rsa.PublicKey)

b, _ = hex.DecodeString("1eb9dbbbbc047c03fd70604e0071f0987e16b28b757225c11f00415d0e20b1a2")
v2PublicKey := ed25519.PublicKey(b)


var payload JsonToken
var footer string
version, err := Parse(token, &payload, &footer, symmetricKey, map[Version]crypto.PublicKey{V1: v1PublicKey, V2: v2PublicKey})

Create token using symmetric key (local mode):

symmetricKey := []byte("YELLOW SUBMARINE, BLACK WIZARDRY")
now := time.Now()
exp := now.Add(24 * time.Hour)
nbt := now

jsonToken := JsonToken{
		Audience:   "test",
		Issuer:     "test_service",
		Jti:        "123",
		Subject:    "test_subject",
		IssuedAt:   now,
		Expiration: exp,
		NotBefore:  nbt,
		}
// Add custom claim	to the token	
jsonToken.Set("data", "this is a signed message")
footer := "some footer"

v2 := NewV2()

// Encrypt data
token, err := v2.Encrypt(symmetricKey, jsonToken, WithFooter(footer))
// token = "v2.local.E42A2iMY9SaZVzt-WkCi45_aebky4vbSUJsfG45OcanamwXwieieMjSjUkgsyZzlbYt82miN1xD-X0zEIhLK_RhWUPLZc9nC0shmkkkHS5Exj2zTpdNWhrC5KJRyUrI0cupc5qrctuREFLAvdCgwZBjh1QSgBX74V631fzl1IErGBgnt2LV1aij5W3hw9cXv4gtm_jSwsfee9HZcCE0sgUgAvklJCDO__8v_fTY7i_Regp5ZPa7h0X0m3yf0n4OXY9PRplunUpD9uEsXJ_MTF5gSFR3qE29eCHbJtRt0FFl81x-GCsQ9H9701TzEjGehCC6Bhw.c29tZSBmb290ZXI"

// Decrypt data
var newJsonToken JsonToken
var newFooter string
err := v2.Decrypt(token, symmetricKey, &newJsonToken, WithFooter(&newFooter))

Create token using asymetric key (public mode):

b, _ := hex.DecodeString("b4cbfb43df4ce210727d953e4a713307fa19bb7d9f85041438d9e11b942a37741eb9dbbbbc047c03fd70604e0071f0987e16b28b757225c11f00415d0e20b1a2")
privateKey := ed25519.PrivateKey(b)

b, _ = hex.DecodeString("1eb9dbbbbc047c03fd70604e0071f0987e16b28b757225c11f00415d0e20b1a2")
publicKey := ed25519.PublicKey(b)

jsonToken := JsonToken{
		Expiration: time.Now().Add(24 * time.Hour),
		}
		
// Add custom claim	to the token	
jsonToken.Set("data", "this is a signed message")
footer := "some footer"

v2 := NewV2()

// Sign data
token, err := v2.Sign(privateKey, jsonToken, WithFooter(footer))
// token = "v2.public.eyJkYXRhIjoidGhpcyBpcyBhIHNpZ25lZCBtZXNzYWdlIiwiZXhwIjoiMjAxOC0wMy0xMlQxOTowODo1NCswMTowMCJ9Ojv0uXlUNXSFhR88KXb568LheLRdeGy2oILR3uyOM_-b7r7i_fX8aljFYUiF-MRr5IRHMBcWPtM0fmn9SOd6Aw.c29tZSBmb290ZXI"

// Verify data
var newJsonToken JsonToken
var newFooter string
err := v2.Verify(token, publicKey, &newJsonToken, WithFooter(&newFooter))

For more information see *_test.go files.

Benchmarks

MacBook Pro (Retina, 15-inch, Late 2013) CPU: 2,3 GHz Intel Core i7 RAM: 16 GB 1600 MHz DDR3 OS: macOS 10.13.3 GO: 1.10

$ go test -bench . -benchmem

Benchmark_V2_JSONToken_Encrypt-8          100000             11729 ns/op            5808 B/op         63 allocs/op
Benchmark_V2_JSONToken_Decrypt-8          100000             11795 ns/op            3104 B/op         61 allocs/op
Benchmark_V2_JSONToken_Sign-8              20000             71034 ns/op            5136 B/op         60 allocs/op
Benchmark_V2_JSONToken_Verify-8            10000            167387 ns/op            2672 B/op         58 allocs/op
Benchmark_V2_String_Encrypt-8             300000              4295 ns/op            2240 B/op         32 allocs/op
Benchmark_V2_String_Decrypt-8            1000000              1854 ns/op            1512 B/op         22 allocs/op
Benchmark_V2_String_Sign-8                 20000             60374 ns/op            1296 B/op         28 allocs/op
Benchmark_V2_String_Verify-8               10000            156859 ns/op             776 B/op         18 allocs/op

Supported Paseto Versions

Version 2

Version 2 (the recommended version by the specification) is fully supported.

Version 1

Version 1 (the compatability version) is fully supported.

Documentation

Index

Constants

View Source
const (
	// V1 defines protocol version 1
	V1 = Version("v1")
	// V2 defines protocol version 1
	V2 = Version("v2")
)

Variables

View Source
var (
	// ErrUnsupportedTokenVersion unsupported parser version
	ErrUnsupportedTokenVersion = errors.New("unsupported parser version")
	// ErrUnsupportedTokenType unsupported token type
	ErrUnsupportedTokenType = errors.New("unsupported token type")
	// ErrIncorrectPrivateKeyType incorrect private key type
	ErrIncorrectPrivateKeyType = errors.New("incorrect private key type")
	// ErrIncorrectPublicKeyType incorrect public key type
	ErrIncorrectPublicKeyType = errors.New("incorrect public key type")
	// ErrPublicKeyNotFound public key for this version not found
	ErrPublicKeyNotFound = errors.New("public key for this version not found")
	// ErrIncorrectTokenFormat incorrect token format
	ErrIncorrectTokenFormat = errors.New("incorrect token format")
	// ErrIncorrectTokenHeader incorrect token header
	ErrIncorrectTokenHeader = errors.New("incorrect token header")
	// ErrInvalidTokenAuth invalid token authentication
	ErrInvalidTokenAuth = errors.New("invalid token authentication")
	// ErrInvalidSignature invalid signature
	ErrInvalidSignature = errors.New("invalid signature")
	// ErrDataUnmarshal can't unmarshal token data to the given type of value
	ErrDataUnmarshal = errors.New("can't unmarshal token data to the given type of value")
)

Functions

func GetTokenInfo

func GetTokenInfo(token string) (Version, Purpose, error)

GetTokenInfo returns token version and purpose

func ParseFooter

func ParseFooter(token string, footer interface{}) error

ParseFooter parses footer from token

func WithFooter

func WithFooter(footer interface{}) func(*options)

WithFooter adds footer to the token

Types

type JSONToken added in v0.2.0

type JSONToken struct {
	Audience   string
	Issuer     string
	Jti        string
	Subject    string
	Expiration time.Time
	IssuedAt   time.Time
	NotBefore  time.Time
	// contains filtered or unexported fields
}

JSONToken defines predefined token payload struct

func (*JSONToken) Get added in v0.2.0

func (t *JSONToken) Get(key string) string

Get return custom claim

func (JSONToken) MarshalJSON added in v0.2.0

func (t JSONToken) MarshalJSON() ([]byte, error)

MarshalJSON implements json.Marshaler interface

func (*JSONToken) Set added in v0.2.0

func (t *JSONToken) Set(key string, value string)

Set sets custom claim

func (*JSONToken) UnmarshalJSON added in v0.2.0

func (t *JSONToken) UnmarshalJSON(data []byte) error

UnmarshalJSON implements json.Unmarshaler interface

func (*JSONToken) Validate added in v0.2.0

func (t *JSONToken) Validate(validators ...Validator) error

Validate validates token with given validators. If no validators specified, then by default it validates token with ValidAt(time.Now()) which checks IssuedAt, NotBefore and Expiration fields with current time.

type Protocol

type Protocol interface {
	// Encrypt encrypts token with symmetric key
	Encrypt(key []byte, payload interface{}, options ...opsFunc) (string, error)
	// Decrypt decrypts key encrypted with symmetric key
	Decrypt(token string, key []byte, payload interface{}, footer interface{}) error
	// Sign signs token with given private key
	Sign(privateKey crypto.PrivateKey, payload interface{}, options ...opsFunc) (string, error)
	// Verify verifies token with given public key
	Verify(token string, publicKey crypto.PublicKey, value interface{}, footer interface{}) error
}

Protocol defines PASETO tokes protocol

func NewV1

func NewV1() Protocol

NewV1 return V1 implementation on paseto tokens

func NewV2

func NewV2() Protocol

NewV2 return V2 implementation on paseto tokens

type Purpose

type Purpose int

Purpose defines token type

const (
	// LOCAL defines symmetric encrypted token type
	LOCAL Purpose = iota
	// PUBLIC defines asymmetric signed token type
	PUBLIC
)

type Validator added in v0.2.0

type Validator func(token *JSONToken) error

Validator defines JSONToken validator function

func ForAudience added in v0.2.0

func ForAudience(audience string) Validator

ForAudience validates JSONToken audience

func IdentifiedBy added in v0.2.0

func IdentifiedBy(jti string) Validator

IdentifiedBy validates JSONToken JTI

func IssuedBy added in v0.2.0

func IssuedBy(issuer string) Validator

IssuedBy validates JSONToken issuer

func Subject added in v0.2.0

func Subject(subject string) Validator

Subject validates JSONToken subject

func ValidAt added in v0.2.0

func ValidAt(t time.Time) Validator

ValidAt validates if token valid at specified time based on IssuedAt, NotBefore and Expiration fields

type Version

type Version string

Version defines token version

func Parse

func Parse(token string, payload interface{}, footer interface{},
	symmetricKey []byte, publicKeys map[Version]crypto.PublicKey) (Version, error)

Parse extracts payload and footer from token. To parse public tokens need to specify v1 and v2 public keys.

Jump to

Keyboard shortcuts

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