Skip to content

Commit b56ac64

Browse files
committed
feat: verifyJWT against nbf if present but use iat if not (#45)
* feat: verifyJWT against nbf if present but use iat if not * fix: apply skew in the opposite direction when checking exp * test: make some test inputs more clear * test: use hard coded JWTs to test validFrom teimstamp * style: remove unused constants
1 parent a315380 commit b56ac64

File tree

3 files changed

+46
-46
lines changed

3 files changed

+46
-46
lines changed

src/JWT.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -225,12 +225,13 @@ export async function verifyJWT(
225225
)
226226
const now: number = Math.floor(Date.now() / 1000)
227227
if (signer) {
228-
if (payload.nbf && payload.nbf > now + NBF_SKEW) {
229-
throw new Error(
230-
`JWT not valid yet (issued in the future): nbf: ${
231-
payload.nbf
232-
} > now: ${now}`
233-
)
228+
const nowSkewed = now + NBF_SKEW
229+
if (payload.nbf) {
230+
if (payload.nbf > nowSkewed) {
231+
throw new Error(`JWT not valid before nbf: ${payload.nbf}`)
232+
}
233+
} else if (payload.iat && payload.iat > nowSkewed) {
234+
throw new Error(`JWT not valid yet (issued in the future) iat: ${payload.iat}`)
234235
}
235236
if (payload.exp && payload.exp <= now - NBF_SKEW) {
236237
throw new Error(`JWT has expired: exp: ${payload.exp} < now: ${now}`)

src/__tests__/JWT-test.ts

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -297,14 +297,42 @@ describe('verifyJWT()', () => {
297297
})
298298
})
299299

300-
it('accepts a valid nbf', () => {
301-
return createJWT({ nbf: NOW + NBF_SKEW }, { issuer: did, signer }).then(
302-
jwt =>
303-
verifyJWT(jwt).then(
304-
({ payload }) => expect(payload).toMatchSnapshot(),
305-
error => expect(error).toBeNull()
306-
)
307-
)
300+
describe('validFrom timestamp', () => {
301+
it('passes when nbf is in the past', async () => {
302+
// tslint:disable-next-line: max-line-length
303+
const jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpYXQiOjE0ODUzMjExMzMsIm5iZiI6MTQ4NTI2MTEzMywiaXNzIjoiZGlkOnVwb3J0OjJuUXRpUUc2Q2dtMUdZVEJhYUtBZ3I3NnVZN2lTZXhVa3FYIn0.btzVz7fZsoSEDa7JyWo3cYWL63pkWTKTz8OUzepIesfSFeBozUjX2oq1xOJ2OyzuinnLGwtSqY303VoyALrafA'
304+
expect(verifyJWT(jwt)).resolves.not.toThrow()
305+
})
306+
it('passes when nbf is in the past and iat is in the future', async () => {
307+
// tslint:disable-next-line: max-line-length
308+
const jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpYXQiOjE0ODUzODExMzMsIm5iZiI6MTQ4NTI2MTEzMywiaXNzIjoiZGlkOnVwb3J0OjJuUXRpUUc2Q2dtMUdZVEJhYUtBZ3I3NnVZN2lTZXhVa3FYIn0.ELsPnDC_YTTkT5hxw09UCLSjWVje9mDs1n_mpvlo2Wk5VJONSy-FDAzm5TunzzCeLixU04m6dD4w6Uk3-OVkww'
309+
expect(verifyJWT(jwt)).resolves.not.toThrow()
310+
})
311+
it('fails when nbf is in the future', async () => {
312+
// tslint:disable-next-line: max-line-length
313+
const jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpYXQiOjE0ODUzMjExMzMsIm5iZiI6MTQ4NTM4MTEzMywiaXNzIjoiZGlkOnVwb3J0OjJuUXRpUUc2Q2dtMUdZVEJhYUtBZ3I3NnVZN2lTZXhVa3FYIn0.rcFuhVHtie3Y09pWxBSf1dnjaVh6FFQLHh-83N-uLty3M5ADJ-jVFFkyt_Eupl8Kr735-oPGn_D1Nj9rl4s_Kw'
314+
expect(verifyJWT(jwt)).rejects.toThrow()
315+
})
316+
it('fails when nbf is in the future and iat is in the past', async () => {
317+
// tslint:disable-next-line: max-line-length
318+
const jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpYXQiOjE0ODUyNjExMzMsIm5iZiI6MTQ4NTM4MTEzMywiaXNzIjoiZGlkOnVwb3J0OjJuUXRpUUc2Q2dtMUdZVEJhYUtBZ3I3NnVZN2lTZXhVa3FYIn0.jiVI11IcKNOvnDrJBzojKtNAGaZbEcafcqW-wfP78g6-6RucjYPBi5qvKje35IOvITWvvpXpK48IW-17Srh02w'
319+
expect(verifyJWT(jwt)).rejects.toThrow()
320+
})
321+
it('passes when nbf is missing and iat is in the past', async () => {
322+
// tslint:disable-next-line: max-line-length
323+
const jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpYXQiOjE0ODUyNjExMzMsImlzcyI6ImRpZDp1cG9ydDoyblF0aVFHNkNnbTFHWVRCYWFLQWdyNzZ1WTdpU2V4VWtxWCJ9.1VwGHDm7f9V-1Fa545uAwF9NfU3RI8yqRFW6XAHOg0FBeM7krC_rEf0PwqbKFO8MiIBELBwUhW_fT4oZsuggUA'
324+
expect(verifyJWT(jwt)).resolves.not.toThrow()
325+
})
326+
it('fails when nbf is missing and iat is in the future', async () => {
327+
// tslint:disable-next-line: max-line-length
328+
const jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpYXQiOjE0ODUzODExMzMsImlzcyI6ImRpZDp1cG9ydDoyblF0aVFHNkNnbTFHWVRCYWFLQWdyNzZ1WTdpU2V4VWtxWCJ9.jU0R8qP3aUX_3DiFt9tIONiq_P5OooFc-ypUwpqK4plGyw6WiI0FTGfZvq7pOarKrjmSojE9Sm_3ETfMpdQckg'
329+
expect(verifyJWT(jwt)).rejects.toThrow()
330+
})
331+
it('passes when nbf and iat are both missing', async () => {
332+
// tslint:disable-next-line: max-line-length
333+
const jwt = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpc3MiOiJkaWQ6dXBvcnQ6Mm5RdGlRRzZDZ20xR1lUQmFhS0Fncjc2dVk3aVNleFVrcVgifQ.5kGKU9ljebhTqvfVDu9MH7vGAqRH0GDTbZNGH45YmhUySgBTyI7u-MkkRit72eFvQAqBfzw6wNUbGf9FPC5AtQ'
334+
expect(verifyJWT(jwt)).resolves.not.toThrow()
335+
})
308336
})
309337

310338
it('handles ES256K-R algorithm', () => {
@@ -331,25 +359,12 @@ describe('verifyJWT()', () => {
331359
)
332360
})
333361

334-
it('rejects an nbf in the future', () => {
335-
return createJWT({ nbf: NOW + NBF_SKEW + 1 }, { issuer: did, signer }).then(
336-
jwt =>
337-
verifyJWT(jwt)
338-
.catch(error =>
339-
expect(error.message).toEqual(
340-
'JWT not valid yet (issued in the future): nbf: 1485321434 > now: 1485321133'
341-
)
342-
)
343-
.then(p => expect(p).toBeFalsy())
344-
)
345-
})
346-
347362
it('accepts a valid exp', () => {
348363
return createJWT(
349-
{ exp: NOW - NBF_SKEW + 1 },
350-
{ issuer: did, signer, expiresIn: 1 }
364+
{ exp: NOW },
365+
{ issuer: did, signer }
351366
).then(jwt =>
352-
verifyJWT(jwt).then(({ payload }) => expect(payload).toMatchSnapshot())
367+
verifyJWT(jwt).then(({ payload }) => expect(payload).toBeDefined())
353368
)
354369
})
355370

src/__tests__/__snapshots__/JWT-test.ts.snap

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -81,22 +81,6 @@ Object {
8181
}
8282
`;
8383

84-
exports[`verifyJWT() accepts a valid exp 1`] = `
85-
Object {
86-
"exp": 1485320834,
87-
"iat": 1485321133,
88-
"iss": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX",
89-
}
90-
`;
91-
92-
exports[`verifyJWT() accepts a valid nbf 1`] = `
93-
Object {
94-
"iat": 1485321133,
95-
"iss": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX",
96-
"nbf": 1485321433,
97-
}
98-
`;
99-
10084
exports[`verifyJWT() handles ES256K-R algorithm 1`] = `
10185
Object {
10286
"hello": "world",

0 commit comments

Comments
 (0)