@@ -46,8 +46,9 @@ Token purposes:
4646
4747Claims Validation:
4848 Decoding verifies the token's signature or authentication tag, but does NOT
49- validate time-based claims: expired (exp) and not-yet-valid (nbf) tokens are
50- decoded successfully so their contents can be inspected.` ,
49+ validate time-based claims by default: expired (exp) and not-yet-valid (nbf)
50+ tokens are decoded successfully so their contents can be inspected. Pass
51+ --validate-claims to "paseto decode" to enforce them instead.` ,
5152 Example : ` # Generate a symmetric key and encode a local token
5253 jwt-cli paseto encode local --key "$(openssl rand -hex 32)" --payload '{"user":"alice"}'
5354
@@ -70,7 +71,10 @@ var pasetoDecodeCmd = &cobra.Command{
7071 Short : "Decode a PASETO token" ,
7172 Long : `Decode and verify a PASETO local (symmetric) or public (asymmetric) token.
7273
73- Time-based claims are not validated: an expired token still decodes.` ,
74+ Time-based claims are not validated by default: an expired token still decodes.
75+ Use --validate-claims to reject expired (exp) or not-yet-valid (nbf) tokens, and
76+ --clock-skew to allow tolerance for clock differences. A claim that is absent is
77+ never enforced, and iat is never enforced.` ,
7478 ValidArgs : []string {pasetoPurposeLocal , pasetoPurposePublic },
7579}
7680
@@ -115,18 +119,18 @@ Tip: v4 is the recommended default. Use v3 only when a NIST-approved
115119}
116120
117121// newLocalCodec builds an encoder/decoder for PASETO local (symmetric) tokens.
118- func newLocalCodec (version , keyHex string ) (paseto.EncoderDecoder , error ) {
122+ func newLocalCodec (version , keyHex string , opts ... paseto. Option ) (paseto.EncoderDecoder , error ) {
119123 var (
120124 codec paseto.EncoderDecoder
121125 err error
122126 )
123127 switch version {
124128 case pasetoV4 :
125- codec , err = paseto .NewLocalV4Encoder (keyHex )
129+ codec , err = paseto .NewLocalV4Encoder (keyHex , opts ... )
126130 case pasetoV3 :
127- codec , err = paseto .NewLocalV3Encoder (keyHex )
131+ codec , err = paseto .NewLocalV3Encoder (keyHex , opts ... )
128132 case pasetoV2 :
129- codec , err = paseto .NewLocalV2Encoder (keyHex )
133+ codec , err = paseto .NewLocalV2Encoder (keyHex , opts ... )
130134 default :
131135 return nil , errUnsupportedPasetoVersion (version )
132136 }
@@ -142,7 +146,7 @@ func newLocalCodec(version, keyHex string) (paseto.EncoderDecoder, error) {
142146// When a public key file is supplied it takes precedence, matching the JWT
143147// decode commands; the resulting value can only decode. Supplying a private key
144148// yields a value that can both sign and verify.
145- func newPublicCodec (version , privateKeyFile , publicKeyFile string ) (paseto.EncoderDecoder , error ) {
149+ func newPublicCodec (version , privateKeyFile , publicKeyFile string , opts ... paseto. Option ) (paseto.EncoderDecoder , error ) {
146150 var (
147151 codec paseto.EncoderDecoder
148152 err error
@@ -151,21 +155,21 @@ func newPublicCodec(version, privateKeyFile, publicKeyFile string) (paseto.Encod
151155 switch version {
152156 case pasetoV4 :
153157 if usePublicKey {
154- codec , err = paseto .NewPublicV4DecoderFromPublicKey (publicKeyFile )
158+ codec , err = paseto .NewPublicV4DecoderFromPublicKey (publicKeyFile , opts ... )
155159 } else {
156- codec , err = paseto .NewPublicV4EncoderFromPrivateKey (privateKeyFile )
160+ codec , err = paseto .NewPublicV4EncoderFromPrivateKey (privateKeyFile , opts ... )
157161 }
158162 case pasetoV3 :
159163 if usePublicKey {
160- codec , err = paseto .NewPublicV3DecoderFromPublicKey (publicKeyFile )
164+ codec , err = paseto .NewPublicV3DecoderFromPublicKey (publicKeyFile , opts ... )
161165 } else {
162- codec , err = paseto .NewPublicV3EncoderFromPrivateKey (privateKeyFile )
166+ codec , err = paseto .NewPublicV3EncoderFromPrivateKey (privateKeyFile , opts ... )
163167 }
164168 case pasetoV2 :
165169 if usePublicKey {
166- codec , err = paseto .NewPublicV2DecoderFromPublicKey (publicKeyFile )
170+ codec , err = paseto .NewPublicV2DecoderFromPublicKey (publicKeyFile , opts ... )
167171 } else {
168- codec , err = paseto .NewPublicV2EncoderFromPrivateKey (privateKeyFile )
172+ codec , err = paseto .NewPublicV2EncoderFromPrivateKey (privateKeyFile , opts ... )
169173 }
170174 default :
171175 return nil , errUnsupportedPasetoVersion (version )
@@ -184,3 +188,29 @@ func pasetoVersionFlag(cmd *cobra.Command) string {
184188 }
185189 return version
186190}
191+
192+ // pasetoValidationOption reads the claims-validation flags shared by the paseto
193+ // decode subcommands.
194+ //
195+ // Validation is off by default, so a token can always be inspected regardless
196+ // of its timing claims; --clock-skew only matters once --validate-claims is on.
197+ func pasetoValidationOption (cmd * cobra.Command ) paseto.Option {
198+ validateClaims , _ := cmd .Flags ().GetBool ("validate-claims" )
199+ clockSkew , _ := cmd .Flags ().GetDuration ("clock-skew" )
200+ return paseto .WithValidation (paseto.ValidationOptions {
201+ ValidateClaims : validateClaims ,
202+ ClockSkew : clockSkew ,
203+ })
204+ }
205+
206+ // newLocalDecoder builds a decoder for local tokens, honouring the claims
207+ // validation flags.
208+ func newLocalDecoder (cmd * cobra.Command , version , keyHex string ) (paseto.EncoderDecoder , error ) {
209+ return newLocalCodec (version , keyHex , pasetoValidationOption (cmd ))
210+ }
211+
212+ // newPublicDecoder builds a decoder for public tokens, honouring the claims
213+ // validation flags.
214+ func newPublicDecoder (cmd * cobra.Command , version , privateKeyFile , publicKeyFile string ) (paseto.EncoderDecoder , error ) {
215+ return newPublicCodec (version , privateKeyFile , publicKeyFile , pasetoValidationOption (cmd ))
216+ }
0 commit comments