11local v2 = {
2- _VERSION = ' paseto v0.2 .0' ,
2+ _VERSION = ' paseto v0.3 .0' ,
33 _DESCRIPTION = ' PASETO (Platform-Agnostic Security Tokens) for Lua' ,
44 _URL = ' https://github.com/peter-evans/paseto-lua' ,
55 _LICENSE = [[
@@ -29,6 +29,7 @@ local v2 = {
2929
3030local paseto = require " paseto.v2.core"
3131local json = require " cjson"
32+ local date = require " date"
3233
3334local function encode_json (data )
3435 local ok , encoded = pcall (function ()
@@ -50,6 +51,120 @@ local function decode_json(data)
5051 return decoded
5152end
5253
54+ local function required_claim_exists (payload_claims , key )
55+ if payload_claims [key ] == nil then
56+ return false , " Missing required claim '" .. key .. " '"
57+ end
58+ return true
59+ end
60+
61+ local function claim_matches_expected_value (payload_claims , key , value )
62+ local exists , err = required_claim_exists (payload_claims , key )
63+ if exists == false then
64+ return false , err
65+ end
66+ if payload_claims [key ] ~= value then
67+ return false , " Claim '" .. key .. " ' does not match the expected value"
68+ end
69+ return true
70+ end
71+
72+ local function claim_exp_is_valid (payload_claims )
73+ local key = " exp"
74+ local exists , err = required_claim_exists (payload_claims , key )
75+ if exists == false then
76+ return false , err
77+ end
78+ if date (payload_claims [key ]) < date (os.time ()) then
79+ return false , " Token has expired"
80+ end
81+ return true
82+ end
83+
84+ local function claim_iat_is_valid (payload_claims )
85+ local key = " iat"
86+ local exists , err = required_claim_exists (payload_claims , key )
87+ if exists == false then
88+ return false , err
89+ end
90+ if date (payload_claims [key ]) > date (os.time ()) then
91+ return false , " Token was issued in the future"
92+ end
93+ return true
94+ end
95+
96+ local function claim_nbf_is_valid (payload_claims )
97+ local key = " nbf"
98+ local exists , err = required_claim_exists (payload_claims , key )
99+ if exists == false then
100+ return false , err
101+ end
102+ if date (payload_claims [key ]) > date (os.time ()) then
103+ return false , " Token cannot be used yet"
104+ end
105+ return true
106+ end
107+
108+ local registered_claims = {
109+ ForAudience = function (payload_claims , value )
110+ return claim_matches_expected_value (payload_claims , " aud" , value )
111+ end ,
112+ IdentifiedBy = function (payload_claims , value )
113+ return claim_matches_expected_value (payload_claims , " jti" , value )
114+ end ,
115+ IssuedBy = function (payload_claims , value )
116+ return claim_matches_expected_value (payload_claims , " iss" , value )
117+ end ,
118+ Subject = function (payload_claims , value )
119+ return claim_matches_expected_value (payload_claims , " sub" , value )
120+ end ,
121+ NotExpired = function (payload_claims )
122+ return claim_exp_is_valid (payload_claims )
123+ end ,
124+ ValidAt = function (payload_claims )
125+ local valid , err
126+ valid , err = claim_iat_is_valid (payload_claims )
127+ if valid == false then
128+ return false , err
129+ end
130+ valid , err = claim_nbf_is_valid (payload_claims )
131+ if valid == false then
132+ return false , err
133+ end
134+ valid , err = claim_exp_is_valid (payload_claims )
135+ if valid == false then
136+ return false , err
137+ end
138+ end ,
139+ ContainsClaim = function (payload_claims , value )
140+ local exists , err = required_claim_exists (payload_claims , value )
141+ if exists == false then
142+ return false , err
143+ end
144+ return true
145+ end
146+ }
147+
148+ local function validate_claims (payload_claims , claim_rules )
149+ if type (claim_rules ) ~= " table" then
150+ return false , " Invalid claim rules format"
151+ end
152+ for key , value in pairs (claim_rules ) do
153+ if registered_claims [key ] ~= nil then
154+ local valid , err = registered_claims [key ](payload_claims , value )
155+ if valid == false then
156+ return false , err
157+ end
158+ else
159+ local matches , err = claim_matches_expected_value (payload_claims , key , value )
160+ if matches == false then
161+ return false , err
162+ end
163+ end
164+ end
165+ return true
166+ end
167+
53168-- API --
54169
55170v2 .SYMMETRIC_KEY_BYTES = paseto .SYMMETRIC_KEY_BYTES
@@ -101,8 +216,8 @@ function v2.encrypt(key, payload_claims, footer_claims)
101216 return paseto .encrypt (key , payload , footer )
102217end
103218
104- function v2 .decrypt (key , token , footer )
105- local err , decrypted , payload_claims
219+ function v2 .decrypt (key , token , claim_rules , footer )
220+ local err , decrypted , payload_claims , valid
106221 decrypted , err = paseto .decrypt (key , token , footer )
107222 if decrypted == nil then
108223 return nil , err
@@ -111,6 +226,12 @@ function v2.decrypt(key, token, footer)
111226 if payload_claims == nil then
112227 return nil , err
113228 end
229+ if claim_rules ~= nil then
230+ valid , err = validate_claims (payload_claims , claim_rules )
231+ if valid == false then
232+ return nil , err
233+ end
234+ end
114235 return payload_claims
115236end
116237
@@ -131,8 +252,8 @@ function v2.sign(secret_key, payload_claims, footer_claims)
131252 return paseto .sign (secret_key , payload , footer )
132253end
133254
134- function v2 .verify (public_key , token , footer )
135- local err , verified_claims , payload_claims
255+ function v2 .verify (public_key , token , claim_rules , footer )
256+ local err , verified_claims , payload_claims , valid
136257 verified_claims , err = paseto .verify (public_key , token , footer )
137258 if verified_claims == nil then
138259 return nil , err
@@ -141,6 +262,12 @@ function v2.verify(public_key, token, footer)
141262 if payload_claims == nil then
142263 return nil , err
143264 end
265+ if claim_rules ~= nil then
266+ valid , err = validate_claims (payload_claims , claim_rules )
267+ if valid == false then
268+ return nil , err
269+ end
270+ end
144271 return payload_claims
145272end
146273
0 commit comments