aboutsummaryrefslogtreecommitdiff
path: root/lib/paseto/v2/json_token.go
diff options
context:
space:
mode:
Diffstat (limited to 'lib/paseto/v2/json_token.go')
-rw-r--r--lib/paseto/v2/json_token.go83
1 files changed, 83 insertions, 0 deletions
diff --git a/lib/paseto/v2/json_token.go b/lib/paseto/v2/json_token.go
new file mode 100644
index 00000000..a3b6006d
--- /dev/null
+++ b/lib/paseto/v2/json_token.go
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: BSD-3-Clause
+// SPDX-FileCopyrightText: 2020 Shulhan <ms@kilabit.info>
+
+package pasetov2
+
+import (
+ "fmt"
+ "time"
+)
+
+const (
+ _validateTimeDrift = 5 * time.Second
+)
+
+// JSONToken define the metadata and data inside the token that are included
+// to generate the signature.
+type JSONToken struct {
+ Issuer string `json:"iss,omitempty"`
+ Subject string `json:"sub,omitempty"`
+ Audience string `json:"aud,omitempty"`
+ ExpiredAt *time.Time `json:"exp,omitempty"`
+ NotBefore *time.Time `json:"nbf,omitempty"`
+ IssuedAt *time.Time `json:"iat,omitempty"`
+ TokenID string `json:"jti,omitempty"`
+ Data string `json:"data"`
+}
+
+// Validate the JSON token fields,
+//
+// - The Issuer must equal to peer.ID
+// - The Audience must equal to received ID,
+// - If peer.AllowedSubjects is not empty, the Subject value must be in
+// one of them,
+// - The current time must be after IssuedAt field,
+// - The current time must after NotBefore "nbf" field,
+// - The current time must before ExpiredAt field.
+//
+// If one of the above condition is not passed, it will return an error.
+func (jtoken *JSONToken) Validate(audience string, peer Key) (err error) {
+ now := time.Now().Round(time.Second)
+ if jtoken.Issuer != peer.ID {
+ return fmt.Errorf("expecting issuer %q, got %q", peer.ID,
+ jtoken.Issuer)
+ }
+ if len(peer.AllowedSubjects) != 0 {
+ _, isAllowed := peer.AllowedSubjects[jtoken.Subject]
+ if !isAllowed {
+ return fmt.Errorf("token subject %q is not allowed for key %q",
+ jtoken.Subject, peer.ID)
+ }
+ }
+ if len(audience) != 0 {
+ if jtoken.Audience != audience {
+ return fmt.Errorf("expecting audience %q, got %q",
+ audience, jtoken.Audience)
+ }
+ }
+ if jtoken.IssuedAt != nil {
+ diff := now.Sub(*jtoken.IssuedAt)
+ if diff < 0 {
+ diff *= -1
+ }
+ if diff > _validateTimeDrift {
+ return fmt.Errorf("token issued at %s before current time %s",
+ jtoken.IssuedAt, now)
+ }
+ }
+ if jtoken.NotBefore != nil {
+ diff := now.Sub(*jtoken.NotBefore)
+ if diff < 0 {
+ diff *= -1
+ }
+ if diff > _validateTimeDrift {
+ return fmt.Errorf("token must not used before %s", jtoken.NotBefore)
+ }
+ }
+ if jtoken.ExpiredAt != nil {
+ if now.After(*jtoken.ExpiredAt) {
+ return fmt.Errorf("token is expired %s", jtoken.ExpiredAt)
+ }
+ }
+ return nil
+}