jwt: began basic JWT.
crypto: moved SigningMethod into crypto
diff --git a/jws/ecdsa.go b/crypto/ecdsa.go
similarity index 99%
rename from jws/ecdsa.go
rename to crypto/ecdsa.go
index ce46b47..c518c9d 100644
--- a/jws/ecdsa.go
+++ b/crypto/ecdsa.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
 
 import (
 	"crypto"
diff --git a/jws/ecdsa_test.go b/crypto/ecdsa_test.go
similarity index 99%
rename from jws/ecdsa_test.go
rename to crypto/ecdsa_test.go
index 30a0f60..e557d1a 100644
--- a/jws/ecdsa_test.go
+++ b/crypto/ecdsa_test.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
 
 // import (
 // 	"crypto/ecdsa"
diff --git a/jws/ecdsa_utils.go b/crypto/ecdsa_utils.go
similarity index 98%
rename from jws/ecdsa_utils.go
rename to crypto/ecdsa_utils.go
index e08a346..4bd75d2 100644
--- a/jws/ecdsa_utils.go
+++ b/crypto/ecdsa_utils.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
 
 import (
 	"crypto/ecdsa"
diff --git a/crypto/errors.go b/crypto/errors.go
new file mode 100644
index 0000000..34fbd25
--- /dev/null
+++ b/crypto/errors.go
@@ -0,0 +1,9 @@
+package crypto
+
+import "errors"
+
+var (
+	// ErrInvalidKey means the key argument passed to SigningMethod.Verify
+	// was not the correct type.
+	ErrInvalidKey = errors.New("key is invalid")
+)
diff --git a/jws/hmac.go b/crypto/hmac.go
similarity index 98%
rename from jws/hmac.go
rename to crypto/hmac.go
index 1d25d72..a9afb1f 100644
--- a/jws/hmac.go
+++ b/crypto/hmac.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
 
 import (
 	"crypto"
diff --git a/jws/hmac_test.go b/crypto/hmac_test.go
similarity index 99%
rename from jws/hmac_test.go
rename to crypto/hmac_test.go
index 86b357e..ff46861 100644
--- a/jws/hmac_test.go
+++ b/crypto/hmac_test.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
 
 // import (
 // 	"github.com/dgrijalva/jwt-go"
diff --git a/jws/none.go b/crypto/none.go
similarity index 93%
rename from jws/none.go
rename to crypto/none.go
index 5d0a4bf..2b27af4 100644
--- a/jws/none.go
+++ b/crypto/none.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
 
 import (
 	"crypto"
@@ -7,10 +7,7 @@
 	"io"
 )
 
-func init() {
-	crypto.RegisterHash(crypto.Hash(0), h)
-	RegisterSigningMethod(Unsecured)
-}
+func init() { crypto.RegisterHash(crypto.Hash(0), h) }
 
 // h is passed to crypto.RegisterHash.
 func h() hash.Hash { return &f{Writer: nil} }
diff --git a/jws/rsa.go b/crypto/rsa.go
similarity index 98%
rename from jws/rsa.go
rename to crypto/rsa.go
index 9174478..80596df 100644
--- a/jws/rsa.go
+++ b/crypto/rsa.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
 
 import (
 	"crypto"
diff --git a/jws/rsa_pss.go b/crypto/rsa_pss.go
similarity index 98%
rename from jws/rsa_pss.go
rename to crypto/rsa_pss.go
index 81330b8..3847ae2 100644
--- a/jws/rsa_pss.go
+++ b/crypto/rsa_pss.go
@@ -1,6 +1,6 @@
 // +build go1.4
 
-package jws
+package crypto
 
 import (
 	"crypto"
diff --git a/jws/rsa_pss_test.go b/crypto/rsa_pss_test.go
similarity index 99%
rename from jws/rsa_pss_test.go
rename to crypto/rsa_pss_test.go
index c45ecf7..c88f949 100644
--- a/jws/rsa_pss_test.go
+++ b/crypto/rsa_pss_test.go
@@ -1,6 +1,6 @@
 // +build go1.4
 
-package jws_test
+package crypto_test
 
 // import (
 // 	"crypto/rsa"
diff --git a/jws/rsa_test.go b/crypto/rsa_test.go
similarity index 99%
rename from jws/rsa_test.go
rename to crypto/rsa_test.go
index 7eb9753..c594605 100644
--- a/jws/rsa_test.go
+++ b/crypto/rsa_test.go
@@ -1,4 +1,4 @@
-package jws_test
+package crypto_test
 
 // import (
 // 	"github.com/dgrijalva/jwt-go"
diff --git a/jws/rsa_utils.go b/crypto/rsa_utils.go
similarity index 98%
rename from jws/rsa_utils.go
rename to crypto/rsa_utils.go
index d8a1a75..350c394 100644
--- a/jws/rsa_utils.go
+++ b/crypto/rsa_utils.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
 
 import (
 	"crypto/rsa"
diff --git a/jws/signature.go b/crypto/signature.go
similarity index 97%
rename from jws/signature.go
rename to crypto/signature.go
index 6fbdc78..37571f9 100644
--- a/jws/signature.go
+++ b/crypto/signature.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
 
 import (
 	"encoding/json"
diff --git a/jws/signature_test.go b/crypto/signature_test.go
similarity index 95%
rename from jws/signature_test.go
rename to crypto/signature_test.go
index 74714be..7601065 100644
--- a/jws/signature_test.go
+++ b/crypto/signature_test.go
@@ -1,4 +1,4 @@
-package jws
+package crypto
 
 import (
 	"bytes"
diff --git a/crypto/signing_method.go b/crypto/signing_method.go
new file mode 100644
index 0000000..998ac59
--- /dev/null
+++ b/crypto/signing_method.go
@@ -0,0 +1,24 @@
+package crypto
+
+// SigningMethod is an interface that provides a way to sign JWS tokens.
+import "crypto"
+
+type SigningMethod interface {
+	// Alg describes the signing algorithm, and is used to uniquely
+	// describe the specific crypto.SigningMethod.
+	Alg() string
+
+	// Verify accepts the raw content, the signature, and the key used
+	// to sign the raw content, and returns any errors found while validating
+	// the signature and content.
+	Verify(raw []byte, sig Signature, key interface{}) error
+
+	// Sign returns a Signature for the raw bytes, as well as any errors
+	// that occurred during the signing.
+	Sign(raw []byte, key interface{}) (Signature, error)
+
+	// Used to cause quick panics when a crypto.SigningMethod whose form of hashing
+	// isn't linked in the binary when you register a crypto.SigningMethod.
+	// To spoof this, see "crypto.SigningMethodNone".
+	Hasher() crypto.Hash
+}
diff --git a/crypto/stubs_test.go b/crypto/stubs_test.go
new file mode 100644
index 0000000..96ec4fd
--- /dev/null
+++ b/crypto/stubs_test.go
@@ -0,0 +1,22 @@
+package crypto
+
+import (
+	"fmt"
+	"testing"
+)
+
+func Error(t *testing.T, want, got interface{}) {
+	format := "\nWanted: %s\nGot: %s"
+
+	switch want.(type) {
+	case []byte, string, nil:
+	default:
+		format = fmt.Sprintf(format, "%v", "%v")
+	}
+
+	t.Errorf(format, want, got)
+}
+
+func ErrorTypes(t *testing.T, want, got interface{}) {
+	t.Errorf("\nWanted: %T\nGot: %T", want, got)
+}
diff --git a/jws/errors.go b/jws/errors.go
index 2d48368..6f6de54 100644
--- a/jws/errors.go
+++ b/jws/errors.go
@@ -3,9 +3,6 @@
 import "errors"
 
 var (
-	// ErrInvalidKey means the key argument passed to SigningMethod.Verify
-	// was not the correct type.
-	ErrInvalidKey = errors.New("key is invalid")
 
 	// ErrNotEnoughMethods is returned if New was called _or_ the Flat/Compact
 	// methods were called with 0 SigningMethods.
@@ -49,4 +46,10 @@
 	// reasons. For example, if there aren't any signatures/payloads/headers
 	// to actually validate.
 	ErrCannotValidate = errors.New("cannot validate")
+
+	// ErrIsNotJWT means the given JWS is not a JWT.
+	ErrIsNotJWT = errors.New("JWS is not a JWT")
+
+	// ErrHoldsJWE means the given JWS holds a JWE inside its payload.
+	ErrHoldsJWE = errors.New("JWS holds JWE")
 )
diff --git a/jws/jws.go b/jws/jws.go
index 4147d37..2a65f25 100644
--- a/jws/jws.go
+++ b/jws/jws.go
@@ -6,6 +6,7 @@
 	"sort"
 
 	"github.com/SermoDigital/jose"
+	"github.com/SermoDigital/jose/crypto"
 )
 
 // JWS represents a specific JWS.
@@ -15,8 +16,13 @@
 	clean   bool
 
 	sb []sigHead
+
+	isJWT bool
 }
 
+// Payload returns the JWS' payload.
+func (j *JWS) Payload() interface{} { return j.payload.v }
+
 // sigHead represents the 'signatures' member of the JWS' "general"
 // serialization form per
 // https://tools.ietf.org/html/rfc7515#section-7.2.1
@@ -24,15 +30,15 @@
 // It's embedded inside the "flat" structure in order to properly
 // create the "flat" JWS.
 type sigHead struct {
-	Protected   rawBase64 `json:"protected,omitempty"`
-	Unprotected rawBase64 `json:"header,omitempty"`
-	Signature   Signature `json:"signature"`
+	Protected   rawBase64        `json:"protected,omitempty"`
+	Unprotected rawBase64        `json:"header,omitempty"`
+	Signature   crypto.Signature `json:"signature"`
 
-	protected   jose.Protected `json:"-"`
-	unprotected jose.Header    `json:"-"`
-	clean       bool           `json:"-"`
+	protected   jose.Protected
+	unprotected jose.Header
+	clean       bool
 
-	method SigningMethod
+	method crypto.SigningMethod
 }
 
 func (s *sigHead) unmarshal() error {
@@ -45,8 +51,8 @@
 	return nil
 }
 
-// New creates a new JWS with the provided SigningMethods.
-func New(content interface{}, methods ...SigningMethod) *JWS {
+// New creates a new JWS with the provided crypto.SigningMethods.
+func New(content interface{}, methods ...crypto.SigningMethod) *JWS {
 	sb := make([]sigHead, len(methods))
 	for i := range methods {
 		sb[i] = sigHead{
@@ -218,6 +224,10 @@
 // For information on the json.Unmarshaler parameter, see Parse.
 func ParseCompact(encoded []byte, u ...json.Unmarshaler) (*JWS, error) {
 
+	// This section loosely follows
+	// https://tools.ietf.org/html/rfc7519#section-7.2
+	// because it's used to parse _both_ JWS and JWTs.
+
 	parts := bytes.Split(encoded, []byte{'.'})
 	if len(parts) != 3 {
 		return nil, ErrNotCompact
@@ -252,6 +262,11 @@
 		return nil, err
 	}
 
+	// https://tools.ietf.org/html/rfc7519#section-7.2.8
+	cty, ok := p.Get("cty").(string)
+	if ok && cty == "JWT" {
+		return &j, ErrHoldsJWE
+	}
 	return &j, nil
 }
 
@@ -279,6 +294,8 @@
 	return nil
 }
 
+// Any means any of the JWS signatures need to validate.
+// Refer to ValidateMulti for more information.
 const Any int = -1
 
 // ValidateMulti validates the current JWS as-is. Since it's meant to be
@@ -286,14 +303,16 @@
 // internal parsing like the Sign, Flat, Compact, or General methods do.
 // idx represents which signatures need to validate
 // in order for the JWS to be considered valid.
-// Use the constant `Any` (-1) if _any_ should validate the JWS. Otherwise,
+// Use the constant `Any` (-1) if *any* should validate the JWS. Otherwise,
 // use the indexes of the signatures that need to validate in order
 // for the JWS to be considered valid.
-// Note: if idx is omitted it defaults to requiring _all_
-// signatures validate, and the JWS spec required _at least_ one
-// signature to validate in order for the JWS to be considered
-// valid.
-func (j *JWS) ValidateMulti(keys []interface{}, methods []SigningMethod, idx ...int) error {
+//
+// Notes:
+//     1.) If idx is omitted it defaults to requiring *all*
+//         signatures validate
+//     2.) The JWS spec requires *at least* one
+//         signature to validate in order for the JWS to be considered valid.
+func (j *JWS) ValidateMulti(keys []interface{}, methods []crypto.SigningMethod, idx ...int) error {
 
 	if len(j.sb) != len(methods) {
 		return ErrNotEnoughMethods
@@ -333,14 +352,17 @@
 
 // Validate validates the current JWS as-is. Refer to ValidateMulti
 // for more information.
-func (j *JWS) Validate(key interface{}, method SigningMethod) error {
+func (j *JWS) Validate(key interface{}, method crypto.SigningMethod) error {
 	if len(j.sb) < 1 {
 		return ErrCannotValidate
 	}
+	if j.isJWT {
+		return j.validateJWT(key, method)
+	}
 	return j.sb[0].validate(j.plcache, key, method)
 }
 
-func (s *sigHead) validate(pl []byte, key interface{}, method SigningMethod) error {
+func (s *sigHead) validate(pl []byte, key interface{}, method crypto.SigningMethod) error {
 	if s.method != method {
 		return ErrMismatchedAlgorithms
 	}
diff --git a/jws/jws_serialize.go b/jws/jws_serialize.go
index 46ecd38..33369dd 100644
--- a/jws/jws_serialize.go
+++ b/jws/jws_serialize.go
@@ -27,8 +27,8 @@
 // https://tools.ietf.org/html/rfc7515#section-7.2.1
 //
 // If only one key is passed it's used for all the provided
-// SigningMethods. Otherwise, len(keys) must equal the number
-// of SigningMethods added.
+// crypto.SigningMethods. Otherwise, len(keys) must equal the number
+// of crypto.SigningMethods added.
 func (j *JWS) General(keys ...interface{}) ([]byte, error) {
 	if err := j.sign(keys...); err != nil {
 		return nil, err
diff --git a/jws/jws_serialize_test.go b/jws/jws_serialize_test.go
index 124a3b4..6472fe3 100644
--- a/jws/jws_serialize_test.go
+++ b/jws/jws_serialize_test.go
@@ -6,6 +6,7 @@
 	"testing"
 
 	"github.com/SermoDigital/jose"
+	"github.com/SermoDigital/jose/crypto"
 )
 
 var dataRaw = struct {
@@ -44,7 +45,7 @@
 }
 
 func TestGeneralIntegrity(t *testing.T) {
-	j := New(dataRaw, SigningMethodRS512)
+	j := New(dataRaw, crypto.SigningMethodRS512)
 	b, err := j.General(rsaPriv)
 	if err != nil {
 		t.Error(err)
@@ -70,7 +71,7 @@
 }
 
 func TestFlatIntegrity(t *testing.T) {
-	j := New(dataRaw, SigningMethodRS512)
+	j := New(dataRaw, crypto.SigningMethodRS512)
 	b, err := j.Flat(rsaPriv)
 	if err != nil {
 		t.Error(err)
@@ -96,7 +97,7 @@
 }
 
 func TestCompactIntegrity(t *testing.T) {
-	j := New(dataRaw, SigningMethodRS512)
+	j := New(dataRaw, crypto.SigningMethodRS512)
 	b, err := j.Compact(rsaPriv)
 	if err != nil {
 		t.Error(err)
diff --git a/jws/jws_test.go b/jws/jws_test.go
index ebd7cf0..6c8355f 100644
--- a/jws/jws_test.go
+++ b/jws/jws_test.go
@@ -5,6 +5,8 @@
 	"encoding/base64"
 	"encoding/json"
 	"testing"
+
+	"github.com/SermoDigital/jose/crypto"
 )
 
 type easy []byte
@@ -29,7 +31,7 @@
 var easyData = easy("easy data!")
 
 func TestParseWithUnmarshaler(t *testing.T) {
-	j := New(easyData, SigningMethodRS512)
+	j := New(easyData, crypto.SigningMethodRS512)
 	b, err := j.Flat(rsaPriv)
 	if err != nil {
 		t.Error(err)
@@ -47,7 +49,7 @@
 }
 
 func TestParseCompact(t *testing.T) {
-	j := New(easyData, SigningMethodRS512)
+	j := New(easyData, crypto.SigningMethodRS512)
 	b, err := j.Compact(rsaPriv)
 	if err != nil {
 		t.Error(err)
@@ -69,7 +71,7 @@
 }
 
 func TestParseGeneral(t *testing.T) {
-	sm := []SigningMethod{SigningMethodRS512, SigningMethodPS384, SigningMethodPS256}
+	sm := []crypto.SigningMethod{crypto.SigningMethodRS512, crypto.SigningMethodPS384, crypto.SigningMethodPS256}
 	j := New(easyData, sm...)
 	b, err := j.General(rsaPriv)
 	if err != nil {
@@ -90,7 +92,7 @@
 }
 
 func TestValidateMulti(t *testing.T) {
-	sm := []SigningMethod{SigningMethodRS512, SigningMethodPS384, SigningMethodPS256}
+	sm := []crypto.SigningMethod{crypto.SigningMethodRS512, crypto.SigningMethodPS384, crypto.SigningMethodPS256}
 	j := New(easyData, sm...)
 	b, err := j.General(rsaPriv)
 	if err != nil {
@@ -109,7 +111,7 @@
 }
 
 func TestValidateMultiMismatchedAlgs(t *testing.T) {
-	sm := []SigningMethod{SigningMethodRS256, SigningMethodPS384, SigningMethodPS512}
+	sm := []crypto.SigningMethod{crypto.SigningMethodRS256, crypto.SigningMethodPS384, crypto.SigningMethodPS512}
 	j := New(easyData, sm...)
 	b, err := j.General(rsaPriv)
 	if err != nil {
@@ -122,7 +124,7 @@
 	}
 
 	// Shuffle it.
-	sm = []SigningMethod{SigningMethodRS512, SigningMethodPS256, SigningMethodPS384}
+	sm = []crypto.SigningMethod{crypto.SigningMethodRS512, crypto.SigningMethodPS256, crypto.SigningMethodPS384}
 
 	keys := []interface{}{rsaPub, rsaPub, rsaPub}
 	if err := j2.ValidateMulti(keys, sm, Any); err == nil {
@@ -131,7 +133,7 @@
 }
 
 func TestValidateMultiNotEnoughMethods(t *testing.T) {
-	sm := []SigningMethod{SigningMethodRS256, SigningMethodPS384, SigningMethodPS512}
+	sm := []crypto.SigningMethod{crypto.SigningMethodRS256, crypto.SigningMethodPS384, crypto.SigningMethodPS512}
 	j := New(easyData, sm...)
 	b, err := j.General(rsaPriv)
 	if err != nil {
@@ -152,7 +154,7 @@
 }
 
 func TestValidateMultiNotEnoughKeys(t *testing.T) {
-	sm := []SigningMethod{SigningMethodRS256, SigningMethodPS384, SigningMethodPS512}
+	sm := []crypto.SigningMethod{crypto.SigningMethodRS256, crypto.SigningMethodPS384, crypto.SigningMethodPS512}
 	j := New(easyData, sm...)
 	b, err := j.General(rsaPriv)
 	if err != nil {
@@ -171,7 +173,7 @@
 }
 
 func TestValidate(t *testing.T) {
-	j := New(easyData, SigningMethodPS512)
+	j := New(easyData, crypto.SigningMethodPS512)
 	b, err := j.Flat(rsaPriv)
 	if err != nil {
 		t.Error(err)
@@ -182,7 +184,7 @@
 		t.Error(err)
 	}
 
-	if err := j2.Validate(rsaPub, SigningMethodPS512); err != nil {
+	if err := j2.Validate(rsaPub, crypto.SigningMethodPS512); err != nil {
 		t.Error(err)
 	}
 }
diff --git a/jws/jwt.go b/jws/jwt.go
new file mode 100644
index 0000000..ce2e985
--- /dev/null
+++ b/jws/jwt.go
@@ -0,0 +1,48 @@
+package jws
+
+import (
+	"github.com/SermoDigital/jose/crypto"
+	"github.com/SermoDigital/jose/jwt"
+)
+
+// Claims represents a set of JOSE Claims.
+type Claims jwt.Claims
+
+// NewJWT creates a new JWT with the given claims.
+func NewJWT(claims Claims, method crypto.SigningMethod) jwt.JWT {
+	j := New(claims, method)
+	j.isJWT = true
+	return j
+}
+
+// Serialize helps implements jwt.JWT.
+func (j *JWS) Serialize(key interface{}) ([]byte, error) {
+	if j.isJWT {
+		return j.Compact(key)
+	}
+	return nil, ErrIsNotJWT
+}
+
+// Claims helps implements jwt.JWT.
+func (j *JWS) Claims() jwt.Claims {
+	if j.isJWT {
+		if c, ok := j.payload.v.(Claims); ok {
+			return jwt.Claims(c)
+		}
+	}
+	return nil
+}
+
+// ParseJWT parses a serialized JWT into a physical JWT.
+func ParseJWT(encoded []byte) (JWT, error) {
+	return ParseCompact(encoded)
+}
+
+// IsJWT returns true if the JWS is a JWT.
+func (j *JWS) IsJWT() bool { return j.isJWT }
+
+func (j *JWS) validateJWT(key interface{}, m crypto.SigningMethod) error {
+	return nil
+}
+
+var _ jwt.JWT = (*JWS)(nil)
diff --git a/jws/signing_methods.go b/jws/signing_methods.go
index bc21d69..1b6665f 100644
--- a/jws/signing_methods.go
+++ b/jws/signing_methods.go
@@ -1,56 +1,38 @@
 package jws
 
 import (
-	"crypto"
 	"sync"
+
+	"github.com/SermoDigital/jose/crypto"
 )
 
 var (
 	mu = &sync.RWMutex{}
 
-	signingMethods = map[string]SigningMethod{
-		SigningMethodES256.Alg(): SigningMethodES256,
-		SigningMethodES384.Alg(): SigningMethodES384,
-		SigningMethodES512.Alg(): SigningMethodES512,
+	signingMethods = map[string]crypto.SigningMethod{
+		crypto.SigningMethodES256.Alg(): crypto.SigningMethodES256,
+		crypto.SigningMethodES384.Alg(): crypto.SigningMethodES384,
+		crypto.SigningMethodES512.Alg(): crypto.SigningMethodES512,
 
-		SigningMethodPS256.Alg(): SigningMethodPS256,
-		SigningMethodPS384.Alg(): SigningMethodPS384,
-		SigningMethodPS512.Alg(): SigningMethodPS512,
+		crypto.SigningMethodPS256.Alg(): crypto.SigningMethodPS256,
+		crypto.SigningMethodPS384.Alg(): crypto.SigningMethodPS384,
+		crypto.SigningMethodPS512.Alg(): crypto.SigningMethodPS512,
 
-		SigningMethodRS256.Alg(): SigningMethodRS256,
-		SigningMethodRS384.Alg(): SigningMethodRS384,
-		SigningMethodRS512.Alg(): SigningMethodRS512,
+		crypto.SigningMethodRS256.Alg(): crypto.SigningMethodRS256,
+		crypto.SigningMethodRS384.Alg(): crypto.SigningMethodRS384,
+		crypto.SigningMethodRS512.Alg(): crypto.SigningMethodRS512,
 
-		SigningMethodHS256.Alg(): SigningMethodHS256,
-		SigningMethodHS384.Alg(): SigningMethodHS384,
-		SigningMethodHS512.Alg(): SigningMethodHS512,
+		crypto.SigningMethodHS256.Alg(): crypto.SigningMethodHS256,
+		crypto.SigningMethodHS384.Alg(): crypto.SigningMethodHS384,
+		crypto.SigningMethodHS512.Alg(): crypto.SigningMethodHS512,
+
+		crypto.Unsecured.Alg(): crypto.Unsecured,
 	}
 )
 
-// SigningMethod is an interface that provides a way to sign JWS tokens.
-type SigningMethod interface {
-	// Alg describes the signing algorithm, and is used to uniquely
-	// describe the specific SigningMethod.
-	Alg() string
-
-	// Verify accepts the raw content, the signature, and the key used
-	// to sign the raw content, and returns any errors found while validating
-	// the signature and content.
-	Verify(raw []byte, sig Signature, key interface{}) error
-
-	// Sign returns a Signature for the raw bytes, as well as any errors
-	// that occurred during the signing.
-	Sign(raw []byte, key interface{}) (Signature, error)
-
-	// Used to cause quick panics when a SigningMethod whose form of hashing
-	// isn't linked in the binary when you register a SigningMethod.
-	// To spoof this, see "SigningMethodNone".
-	Hasher() crypto.Hash
-}
-
-// RegisterSigningMethod registers the SigningMethod in the global map.
+// RegisterSigningMethod registers the crypto.SigningMethod in the global map.
 // This is typically done inside the caller's init function.
-func RegisterSigningMethod(sm SigningMethod) {
+func RegisterSigningMethod(sm crypto.SigningMethod) {
 	if GetSigningMethod(sm.Alg()) != nil {
 		panic("jose/jws: cannot duplicate signing methods")
 	}
@@ -64,15 +46,15 @@
 	mu.Unlock()
 }
 
-// RemoveSigningMethod removes the SigningMethod from the global map.
-func RemoveSigningMethod(sm SigningMethod) {
+// RemoveSigningMethod removes the crypto.SigningMethod from the global map.
+func RemoveSigningMethod(sm crypto.SigningMethod) {
 	mu.Lock()
 	delete(signingMethods, sm.Alg())
 	mu.Unlock()
 }
 
-// GetSigningMethod retrieves a SigningMethod from the global map.
-func GetSigningMethod(alg string) SigningMethod {
+// GetSigningMethod retrieves a crypto.SigningMethod from the global map.
+func GetSigningMethod(alg string) crypto.SigningMethod {
 	mu.RLock()
 	defer mu.RUnlock()
 	return signingMethods[alg]
diff --git a/jws/signing_methods_test.go b/jws/signing_methods_test.go
index 59d52c2..017d482 100644
--- a/jws/signing_methods_test.go
+++ b/jws/signing_methods_test.go
@@ -5,6 +5,8 @@
 	"hash"
 	"io"
 	"testing"
+
+	c "github.com/SermoDigital/jose/crypto"
 )
 
 func init() { crypto.RegisterHash(crypto.Hash(0), HH) }
@@ -29,11 +31,11 @@
 	Hash crypto.Hash
 }
 
-func (m *TestSigningMethod) Verify(_ []byte, _ Signature, _ interface{}) error {
+func (m *TestSigningMethod) Verify(_ []byte, _ c.Signature, _ interface{}) error {
 	return nil
 }
 
-func (m *TestSigningMethod) Sign(_ []byte, _ interface{}) (Signature, error) {
+func (m *TestSigningMethod) Sign(_ []byte, _ interface{}) (c.Signature, error) {
 	return nil, nil
 }
 
diff --git a/jws/stubs_test.go b/jws/stubs_test.go
index 0b9e9b2..513c6ef 100644
--- a/jws/stubs_test.go
+++ b/jws/stubs_test.go
@@ -9,6 +9,8 @@
 	"io/ioutil"
 	"path/filepath"
 	"testing"
+
+	"github.com/SermoDigital/jose/crypto"
 )
 
 func Error(t *testing.T, want, got interface{}) {
@@ -66,7 +68,7 @@
 	if err != nil {
 		panic(err)
 	}
-	ec256Priv, err = ParseECPrivateKeyFromPEM(ecData)
+	ec256Priv, err = crypto.ParseECPrivateKeyFromPEM(ecData)
 	if err != nil {
 		panic(err)
 	}
@@ -74,7 +76,7 @@
 	if err != nil {
 		panic(err)
 	}
-	ec256Pub, err = ParseECPublicKeyFromPEM(ecData)
+	ec256Pub, err = crypto.ParseECPublicKeyFromPEM(ecData)
 	if err != nil {
 		panic(err)
 	}
@@ -82,7 +84,7 @@
 	if err != nil {
 		panic(err)
 	}
-	ec384Priv, err = ParseECPrivateKeyFromPEM(ecData)
+	ec384Priv, err = crypto.ParseECPrivateKeyFromPEM(ecData)
 	if err != nil {
 		panic(err)
 	}
@@ -90,7 +92,7 @@
 	if err != nil {
 		panic(err)
 	}
-	ec384Pub, err = ParseECPublicKeyFromPEM(ecData)
+	ec384Pub, err = crypto.ParseECPublicKeyFromPEM(ecData)
 	if err != nil {
 		panic(err)
 	}
@@ -98,7 +100,7 @@
 	if err != nil {
 		panic(err)
 	}
-	ec512Priv, err = ParseECPrivateKeyFromPEM(ecData)
+	ec512Priv, err = crypto.ParseECPrivateKeyFromPEM(ecData)
 	if err != nil {
 		panic(err)
 	}
@@ -106,7 +108,7 @@
 	if err != nil {
 		panic(err)
 	}
-	ec512Pub, err = ParseECPublicKeyFromPEM(ecData)
+	ec512Pub, err = crypto.ParseECPublicKeyFromPEM(ecData)
 	if err != nil {
 		panic(err)
 	}
diff --git a/jwt/claims.go b/jwt/claims.go
new file mode 100644
index 0000000..46076d9
--- /dev/null
+++ b/jwt/claims.go
@@ -0,0 +1,76 @@
+package jwt
+
+import (
+	"encoding/json"
+
+	"github.com/SermoDigital/jose"
+)
+
+// Claims implements a JOSE Claim set with the addition of some helper
+// methods, similar to net/url.Values.
+type Claims map[string]interface{}
+
+// Get retrieves the value corresponding with key from the Claims.
+func (c Claims) Get(key string) interface{} {
+	if c == nil {
+		return nil
+	}
+	return c[key]
+}
+
+// Set sets Claims[key] = val. It'll overwrite without warning.
+func (c Claims) Set(key string, val interface{}) {
+	c[key] = val
+}
+
+// Del removes the value that corresponds with key from the Claims.
+func (c Claims) Del(key string) {
+	delete(c, key)
+}
+
+// Has returns true if a value for the given key exists inside the Claims.
+func (c Claims) Has(key string) bool {
+	_, ok := c[key]
+	return ok
+}
+
+// MarshalJSON implements json.Marshaler for Claims.
+func (c Claims) MarshalJSON() ([]byte, error) {
+	if c == nil || len(c) == 0 {
+		return nil, nil
+	}
+	b, err := json.Marshal(map[string]interface{}(c))
+	if err != nil {
+		return nil, err
+	}
+	return jose.EncodeEscape(b), nil
+}
+
+// Base64 implements the Encoder interface.
+func (c Claims) Base64() ([]byte, error) {
+	return c.MarshalJSON()
+}
+
+// UnmarshalJSON implements json.Unmarshaler for Claims.
+func (c *Claims) UnmarshalJSON(b []byte) error {
+	if b == nil {
+		return nil
+	}
+
+	b, err := jose.DecodeEscaped(b)
+	if err != nil {
+		return err
+	}
+
+	// Since json.Unmarshal calls UnmarshalJSON,
+	// calling json.Unmarshal on *p would be infinitely recursive
+	// A temp variable is needed because &map[string]interface{}(*p) is
+	// invalid Go.
+
+	tmp := map[string]interface{}(*c)
+	if err = json.Unmarshal(b, &tmp); err != nil {
+		return err
+	}
+	*c = Claims(tmp)
+	return nil
+}
diff --git a/jwt/claims_test.go b/jwt/claims_test.go
new file mode 100644
index 0000000..e22cb07
--- /dev/null
+++ b/jwt/claims_test.go
@@ -0,0 +1 @@
+package jwt
diff --git a/jwt/jwt.go b/jwt/jwt.go
new file mode 100644
index 0000000..bd09ec0
--- /dev/null
+++ b/jwt/jwt.go
@@ -0,0 +1,16 @@
+package jwt
+
+import "github.com/SermoDigital/jose/crypto"
+
+type JWT interface {
+	// Claims returns the set of Claims.
+	Claims() Claims
+
+	// Validate returns an error describing any issues found while
+	// validating the JWT.
+	Validate(key interface{}, method crypto.SigningMethod) error
+
+	// Serialize serializes the JWT into its on-the-wire
+	// representation.
+	Serialize(key interface{}) ([]byte, error)
+}