aboutsummaryrefslogtreecommitdiff
path: root/lib/paseto
diff options
context:
space:
mode:
authorShulhan <ms@kilabit.info>2026-03-30 03:49:19 +0700
committerShulhan <ms@kilabit.info>2026-03-30 06:35:53 +0700
commite931ffed0aada7427d7016ce681b2d038b668ba3 (patch)
treeef3efc06d880698cd0cecf80f3792bfc69db7c68 /lib/paseto
parent5335f8d5e049866c904b506e28a7e48c8c787024 (diff)
downloadpakakeh.go-e931ffed0aada7427d7016ce681b2d038b668ba3.tar.xz
lib/paseto: store the time as Unix epoch inside Payload
Previously, we use time.Time to store the value for ExpiredAt, NotBefore, and IssuedAt. Even thought this is allowed (see RFC 7519 section 2, NumericDate) but it is not a standard practices. This changes them to store Unix epoch with int64.
Diffstat (limited to 'lib/paseto')
-rw-r--r--lib/paseto/paseto.go3
-rw-r--r--lib/paseto/payload.go32
-rw-r--r--lib/paseto/payload_test.go10
-rw-r--r--lib/paseto/v2/public_mode.go10
4 files changed, 27 insertions, 28 deletions
diff --git a/lib/paseto/paseto.go b/lib/paseto/paseto.go
index 05865bcb..9268a383 100644
--- a/lib/paseto/paseto.go
+++ b/lib/paseto/paseto.go
@@ -18,13 +18,12 @@ import (
"bytes"
"encoding/binary"
"fmt"
- "time"
)
// DefaultTTL define the time-to-live of a message, by setting ExpiredAt to
// current time + [DefaultTTL].
// This value can be changes to increase the message expiration time.
-var DefaultTTL = 60 * time.Second
+var DefaultTTL int64 = 60
// PreAuthEncode encodes each piece into single block.
func PreAuthEncode(pieces ...[]byte) (b []byte, err error) {
diff --git a/lib/paseto/payload.go b/lib/paseto/payload.go
index 2f0de5fe..b9335afd 100644
--- a/lib/paseto/payload.go
+++ b/lib/paseto/payload.go
@@ -11,7 +11,7 @@ import (
// DriftSeconds defines the time differences in seconds allowed in
// [Payload.ExpiredAt] and [Payload.NotBefore].
-const DriftSeconds = 5 * time.Second
+const DriftSeconds = 5
// List of errors for [Payload.Validate].
var (
@@ -27,6 +27,10 @@ var (
// The claims follow RFC 7519 that includes issuer, subject, audience,
// expiration time, not-before time, issued-at, and ID.
type Payload struct {
+ // Data defines actual information to be send in message.
+ // Data must be JSON encodable.
+ Data any `json:"data"`
+
// Issuer defines the peer ID that issued the payload.
Issuer string `json:"iss,omitempty"`
@@ -36,23 +40,19 @@ type Payload struct {
// Audience defines the peer ID that receive the payload.
Audience string `json:"aud,omitempty"`
+ // TokenID defines the unique identifier for the payload.
+ TokenID string `json:"jti,omitempty"`
+
// ExpiredAt defines the expiration time when the payload MUST NOT
// be accepted for processing.
- ExpiredAt *time.Time `json:"exp,omitempty"`
+ ExpiredAt int64 `json:"exp,omitempty"`
// NotBefore defines the time when the payload MUST NOT be accepted
// for processing.
- NotBefore *time.Time `json:"nbf,omitempty"`
+ NotBefore int64 `json:"nbf,omitempty"`
// IssuedAt defines the time at which the payload is issued.
- IssuedAt *time.Time `json:"iat,omitempty"`
-
- // TokenID defines the unique identifier for the payload.
- TokenID string `json:"jti,omitempty"`
-
- // Data defines actual information to be send in message.
- // Data must be JSON encodable.
- Data any `json:"data"`
+ IssuedAt int64 `json:"iat,omitempty"`
}
// Validate validates the the payload and returns nil when all of the
@@ -77,7 +77,7 @@ type Payload struct {
func (pload *Payload) Validate(recvID string, sender Peer) (err error) {
logp := `payload`
- now := time.Now().Round(time.Second)
+ now := time.Now().UTC().Unix()
if pload.Issuer != sender.ID {
return fmt.Errorf(`%s: %w`, logp, ErrUnknownIssuer)
}
@@ -90,8 +90,8 @@ func (pload *Payload) Validate(recvID string, sender Peer) (err error) {
if len(recvID) != 0 && pload.Audience != recvID {
return fmt.Errorf(`%s: %w`, logp, ErrInvalidAudience)
}
- if pload.ExpiredAt != nil {
- diff := pload.ExpiredAt.Sub(now)
+ if pload.ExpiredAt != 0 {
+ diff := pload.ExpiredAt - now
diff -= DefaultTTL
if diff < 0 {
diff *= -1
@@ -100,8 +100,8 @@ func (pload *Payload) Validate(recvID string, sender Peer) (err error) {
return fmt.Errorf(`%s: %w`, logp, ErrExpired)
}
}
- if pload.NotBefore != nil {
- diff := now.Sub(*pload.NotBefore)
+ if pload.NotBefore != 0 {
+ diff := now - pload.NotBefore
if diff < 0 {
diff *= -1
}
diff --git a/lib/paseto/payload_test.go b/lib/paseto/payload_test.go
index 81d1c67f..75f18ba4 100644
--- a/lib/paseto/payload_test.go
+++ b/lib/paseto/payload_test.go
@@ -11,11 +11,11 @@ import (
)
func TestPayload_Validate(t *testing.T) {
- now := time.Now().Round(time.Second)
+ now := time.Now().UTC().Unix()
peer := Peer{}
- issued1sAgo := now.Add(-1 * time.Second)
- issued6sAgo := now.Add(-6 * time.Second)
+ issued1sAgo := now - 1
+ issued6sAgo := now - 6
listCase := []struct {
desc string
@@ -24,12 +24,12 @@ func TestPayload_Validate(t *testing.T) {
}{{
desc: `With IssuedAt less than current time`,
pload: &Payload{
- IssuedAt: &issued1sAgo,
+ IssuedAt: issued1sAgo,
},
}, {
desc: `With IssuedAt greater than drift`,
pload: &Payload{
- IssuedAt: &issued6sAgo,
+ IssuedAt: issued6sAgo,
},
expErr: `payload: issued-at is after current time`,
}}
diff --git a/lib/paseto/v2/public_mode.go b/lib/paseto/v2/public_mode.go
index d322a0b1..c10a7a42 100644
--- a/lib/paseto/v2/public_mode.go
+++ b/lib/paseto/v2/public_mode.go
@@ -106,15 +106,15 @@ func (auth *PublicMode) RemovePeer(id string) {
func (auth *PublicMode) Pack(audience, subject string, data []byte, footer map[string]any) (
token string, err error,
) {
- now := time.Now().Round(time.Second)
- expiredAt := now.Add(paseto.DefaultTTL)
+ now := time.Now().UTC().Unix()
+ expiredAt := now + paseto.DefaultTTL
jsonToken := paseto.Payload{
Issuer: auth.our.ID,
Subject: subject,
Audience: audience,
- IssuedAt: &now,
- NotBefore: &now,
- ExpiredAt: &expiredAt,
+ IssuedAt: now,
+ NotBefore: now,
+ ExpiredAt: expiredAt,
Data: base64.StdEncoding.EncodeToString(data),
}