1
+ 'use strict' ;
2
+
3
+ const jwt = require ( '../' ) ;
4
+ const expect = require ( 'chai' ) . expect ;
5
+ const sinon = require ( 'sinon' ) ;
6
+ const util = require ( 'util' ) ;
7
+
8
+ function base64UrlEncode ( str ) {
9
+ return Buffer . from ( str ) . toString ( 'base64' )
10
+ . replace ( / = / g, "" )
11
+ . replace ( / \+ / g, "-" )
12
+ . replace ( / \/ / g, "_" )
13
+ ;
14
+ }
15
+
16
+ function signWithNoBefore ( payload , notBefore ) {
17
+ const options = { algorithm : 'none' } ;
18
+ if ( notBefore !== undefined ) {
19
+ options . notBefore = notBefore ;
20
+ }
21
+ return jwt . sign ( payload , undefined , options ) ;
22
+ }
23
+
24
+ const noneAlgorithmHeader = 'eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0' ;
25
+
26
+ describe ( 'not before' , function ( ) {
27
+ describe ( '`jwt.sign` notBefore option validation' , function ( ) {
28
+ [
29
+ true ,
30
+ false ,
31
+ null ,
32
+ - 1.1 ,
33
+ 1.1 ,
34
+ - Infinity ,
35
+ Infinity ,
36
+ NaN ,
37
+ // TODO empty string currently fails
38
+ // '',
39
+ ' ' ,
40
+ 'invalid' ,
41
+ [ ] ,
42
+ [ 'foo' ] ,
43
+ { } ,
44
+ { foo : 'bar' } ,
45
+ ] . forEach ( ( notBefore ) => {
46
+ it ( `should error with with value ${ util . inspect ( notBefore ) } ` , function ( ) {
47
+ expect ( ( ) => signWithNoBefore ( { } , notBefore ) ) . to . throw (
48
+ '"notBefore" should be a number of seconds or string representing a timespan'
49
+ ) ;
50
+ } ) ;
51
+ } ) ;
52
+
53
+ // undefined needs special treatment because {} is not the same as {notBefore: undefined}
54
+ it ( 'should error with with value undefined' , function ( ) {
55
+ expect ( ( ) => jwt . sign ( { } , undefined , { notBefore : undefined , algorithm : 'none' } ) ) . to . throw (
56
+ '"notBefore" should be a number of seconds or string representing a timespan'
57
+ ) ;
58
+ } ) ;
59
+
60
+ it ( 'should error when "nbf" is in payload' , function ( ) {
61
+ expect ( ( ) => signWithNoBefore ( { nbf : 100 } , 100 ) ) . to . throw (
62
+ 'Bad "options.notBefore" option the payload already has an "nbf" property.'
63
+ ) ;
64
+ } ) ;
65
+
66
+ it ( 'should error with a string payload' , function ( ) {
67
+ expect ( ( ) => signWithNoBefore ( 'a string payload' , 100 ) ) . to . throw (
68
+ 'invalid notBefore option for string payload'
69
+ ) ;
70
+ } ) ;
71
+
72
+ it ( 'should error with a Buffer payload' , function ( ) {
73
+ expect ( ( ) => signWithNoBefore ( new Buffer ( 'a Buffer payload' ) , 100 ) ) . to . throw (
74
+ 'invalid notBefore option for object payload'
75
+ ) ;
76
+ } ) ;
77
+ } ) ;
78
+
79
+ describe ( '`jwt.sign` nbf claim validation' , function ( ) {
80
+ [
81
+ true ,
82
+ false ,
83
+ null ,
84
+ undefined ,
85
+ // TODO should these fail in validation?
86
+ // -Infinity,
87
+ // Infinity,
88
+ // NaN,
89
+ '' ,
90
+ ' ' ,
91
+ 'invalid' ,
92
+ [ ] ,
93
+ [ 'foo' ] ,
94
+ { } ,
95
+ { foo : 'bar' } ,
96
+ ] . forEach ( ( nbf ) => {
97
+ it ( `should error with with value ${ util . inspect ( nbf ) } ` , function ( ) {
98
+ expect ( ( ) => signWithNoBefore ( { nbf} ) ) . to . throw (
99
+ '"nbf" should be a number of seconds'
100
+ ) ;
101
+ } ) ;
102
+ } ) ;
103
+ } ) ;
104
+
105
+ describe ( 'nbf in payload validation' , function ( ) {
106
+ [
107
+ true ,
108
+ false ,
109
+ null ,
110
+ - Infinity ,
111
+ Infinity ,
112
+ NaN ,
113
+ '' ,
114
+ ' ' ,
115
+ 'invalid' ,
116
+ [ ] ,
117
+ [ 'foo' ] ,
118
+ { } ,
119
+ { foo : 'bar' } ,
120
+ ] . forEach ( ( nbf ) => {
121
+ it ( `should error with with value ${ util . inspect ( nbf ) } ` , function ( ) {
122
+ const encodedPayload = base64UrlEncode ( JSON . stringify ( { nbf} ) ) ;
123
+ const token = `${ noneAlgorithmHeader } .${ encodedPayload } .` ;
124
+ expect ( ( ) => jwt . verify ( token , undefined ) ) . to . throw (
125
+ jwt . JsonWebTokenError ,
126
+ 'invalid nbf value'
127
+ ) ;
128
+ } ) ;
129
+ } )
130
+ } ) ;
131
+
132
+ describe ( 'when signing and verifying a token with notBefore option' , function ( ) {
133
+ let fakeClock ;
134
+ beforeEach ( function ( ) {
135
+ fakeClock = sinon . useFakeTimers ( { now : 60000 } ) ;
136
+ } ) ;
137
+
138
+ afterEach ( function ( ) {
139
+ fakeClock . uninstall ( ) ;
140
+ } ) ;
141
+
142
+
143
+ it ( 'should set correct "nbf" with negative number of seconds' , function ( ) {
144
+ const token = signWithNoBefore ( { } , - 10 ) ;
145
+ const decoded = jwt . decode ( token ) ;
146
+
147
+ const verified = jwt . verify ( token , undefined ) ;
148
+ expect ( decoded ) . to . deep . equal ( verified ) ;
149
+ expect ( decoded . nbf ) . to . equal ( 50 ) ;
150
+ } ) ;
151
+
152
+ it ( 'should set correct "nbf" with positive number of seconds' , function ( ) {
153
+ const token = signWithNoBefore ( { } , 10 ) ;
154
+
155
+ fakeClock . tick ( 10000 ) ;
156
+ const decoded = jwt . decode ( token ) ;
157
+
158
+ const verified = jwt . verify ( token , undefined ) ;
159
+ expect ( decoded ) . to . deep . equal ( verified ) ;
160
+ expect ( decoded . nbf ) . to . equal ( 70 ) ;
161
+ } ) ;
162
+
163
+ it ( 'should set correct "nbf" with zero seconds' , function ( ) {
164
+ const token = signWithNoBefore ( { } , 0 ) ;
165
+
166
+ const decoded = jwt . decode ( token ) ;
167
+
168
+ const verified = jwt . verify ( token , undefined ) ;
169
+ expect ( decoded ) . to . deep . equal ( verified ) ;
170
+ expect ( decoded . nbf ) . to . equal ( 60 ) ;
171
+ } ) ;
172
+
173
+ it ( 'should set correct "nbf" with negative string timespan' , function ( ) {
174
+ const token = signWithNoBefore ( { } , '-10 s' ) ;
175
+
176
+ const decoded = jwt . decode ( token ) ;
177
+
178
+ const verified = jwt . verify ( token , undefined ) ;
179
+ expect ( decoded ) . to . deep . equal ( verified ) ;
180
+ expect ( decoded . nbf ) . to . equal ( 50 ) ;
181
+ } ) ;
182
+
183
+
184
+ it ( 'should set correct "nbf" with positive string timespan' , function ( ) {
185
+ const token = signWithNoBefore ( { } , '10 s' ) ;
186
+
187
+ fakeClock . tick ( 10000 ) ;
188
+ const decoded = jwt . decode ( token ) ;
189
+
190
+ const verified = jwt . verify ( token , undefined ) ;
191
+ expect ( decoded ) . to . deep . equal ( verified ) ;
192
+ expect ( decoded . nbf ) . to . equal ( 70 ) ;
193
+ } ) ;
194
+
195
+ it ( 'should set correct "nbf" with zero string timespan' , function ( ) {
196
+ const token = signWithNoBefore ( { } , '0 s' ) ;
197
+
198
+ const decoded = jwt . decode ( token ) ;
199
+
200
+ const verified = jwt . verify ( token , undefined ) ;
201
+ expect ( decoded ) . to . deep . equal ( verified ) ;
202
+ expect ( decoded . nbf ) . to . equal ( 60 ) ;
203
+ } ) ;
204
+
205
+ it ( 'should set correct "nbf" when "iat" is passed' , function ( ) {
206
+ const token = signWithNoBefore ( { iat : 40 } , - 10 ) ;
207
+
208
+ const decoded = jwt . decode ( token ) ;
209
+
210
+ const verified = jwt . verify ( token , undefined ) ;
211
+ expect ( decoded ) . to . deep . equal ( verified ) ;
212
+ expect ( decoded . nbf ) . to . equal ( 30 ) ;
213
+ } ) ;
214
+
215
+ it ( 'should verify "nbf" using "clockTimestamp"' , function ( ) {
216
+ const token = signWithNoBefore ( { } , 10 ) ;
217
+
218
+ const verified = jwt . verify ( token , undefined , { clockTimestamp : 70 } ) ;
219
+ expect ( verified . iat ) . to . equal ( 60 ) ;
220
+ expect ( verified . nbf ) . to . equal ( 70 ) ;
221
+ } ) ;
222
+
223
+ it ( 'should verify "nbf" using "clockTolerance"' , function ( ) {
224
+ const token = signWithNoBefore ( { } , 5 ) ;
225
+
226
+ const verified = jwt . verify ( token , undefined , { clockTolerance : 6 } ) ;
227
+ expect ( verified . iat ) . to . equal ( 60 ) ;
228
+ expect ( verified . nbf ) . to . equal ( 65 ) ;
229
+ } ) ;
230
+
231
+ it ( 'should ignore a not active token when "ignoreNotBefore" is true' , function ( ) {
232
+ const token = signWithNoBefore ( { } , '10 s' ) ;
233
+
234
+ const verified = jwt . verify ( token , undefined , { ignoreNotBefore : true } ) ;
235
+ expect ( verified . iat ) . to . equal ( 60 ) ;
236
+ expect ( verified . nbf ) . to . equal ( 70 ) ;
237
+ } ) ;
238
+
239
+ it ( 'should error on verify if "nbf" is after current time' , function ( ) {
240
+ const token = signWithNoBefore ( { nbf : 61 } ) ;
241
+
242
+ expect ( ( ) => jwt . verify ( token , undefined ) ) . to . throw (
243
+ jwt . NotBeforeError ,
244
+ 'jwt not active'
245
+ ) ;
246
+ } ) ;
247
+
248
+ it ( 'should error on verify if "nbf" is after current time using clockTolerance' , function ( ) {
249
+ const token = signWithNoBefore ( { } , 5 ) ;
250
+
251
+ expect ( ( ) => jwt . verify ( token , undefined , { clockTolerance : 4 } ) ) . to . throw (
252
+ jwt . NotBeforeError ,
253
+ 'jwt not active'
254
+ ) ;
255
+ } ) ;
256
+ } ) ;
257
+ } ) ;
0 commit comments