Skip to content

Commit b650ab0

Browse files
committed
feat: Set iat timestamp by default instead of nbf (#43)
* refactor: change createJWT to set iat by default instead of nbf * test: add tests for iat behavior in createJWT * feat: do not set iat if value in payload is null * fix: set payload.iat to undefined instead of null to omit from JWT * fix code style for division * fix code style BREAKING CHANGE: expiresIn option passed to createJWT now calculates exp from nbf instead of iat.
1 parent 1b5a3c0 commit b650ab0

File tree

3 files changed

+57
-21
lines changed

3 files changed

+57
-21
lines changed

src/JWT.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ interface JWTPayload {
4343
iss?: string
4444
sub?: string
4545
aud?: string
46+
iat?: number
4647
nbf?: number
4748
type?: string
4849
exp?: number
@@ -152,19 +153,19 @@ export function decodeJWT(jwt: string): JWTDecoded {
152153
*/
153154
// export async function createJWT(payload, { issuer, signer, alg, expiresIn }) {
154155
export async function createJWT(
155-
payload: object,
156+
payload: any,
156157
{ issuer, signer, alg, expiresIn }: JWTOptions
157158
): Promise<string> {
158159
if (!signer) throw new Error('No Signer functionality has been configured')
159160
if (!issuer) throw new Error('No issuing DID has been configured')
160161
const header: JWTHeader = { typ: 'JWT', alg: alg || defaultAlg }
161162
const timestamps: Partial<JWTPayload> = {
162-
nbf: Math.floor(Date.now() / 1000),
163+
iat: Math.floor(Date.now() / 1000),
163164
exp: undefined
164165
}
165-
if (expiresIn) {
166+
if (expiresIn && payload.nbf) {
166167
if (typeof expiresIn === 'number') {
167-
timestamps.exp = timestamps.nbf + Math.floor(expiresIn)
168+
timestamps.exp = payload.nbf + Math.floor(expiresIn)
168169
} else {
169170
throw new Error('JWT expiresIn is not a number')
170171
}

src/__tests__/JWT-test.ts

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,14 +107,48 @@ describe('createJWT()', () => {
107107

108108
it('creates a JWT with expiry in 10000 seconds', () => {
109109
return createJWT(
110-
{ requested: ['name', 'phone'] },
110+
{ requested: ['name', 'phone'], nbf: Math.floor(new Date().getTime() / 1000) },
111111
{ issuer: did, signer, expiresIn: 10000 }
112112
).then(jwt => {
113113
const { payload } = decodeJWT(jwt)
114114
return expect(payload.exp).toEqual(payload.nbf + 10000)
115115
})
116116
})
117117

118+
it('ignores expiresIn if nbf is not set', async () => {
119+
const { payload } = decodeJWT(await createJWT(
120+
{ requested: ['name', 'phone'] },
121+
{ issuer: did, signer, expiresIn: 10000 }
122+
))
123+
return expect(payload.exp).toBeUndefined()
124+
})
125+
126+
it('sets iat to the current time by default', async () => {
127+
const timestamp = Math.floor(Date.now() / 1000)
128+
const { payload } = decodeJWT(await createJWT(
129+
{ requested: ['name', 'phone'] },
130+
{ issuer: did, signer }
131+
))
132+
return expect(payload.iat).toEqual(timestamp)
133+
})
134+
135+
it('sets iat to the value passed in payload', async () => {
136+
const timestamp = 2000000
137+
const { payload } = decodeJWT(await createJWT(
138+
{ requested: ['name', 'phone'], iat: timestamp },
139+
{ issuer: did, signer }
140+
))
141+
return expect(payload.iat).toEqual(timestamp)
142+
})
143+
144+
it('does not set iat if value in payload is undefined', async () => {
145+
const { payload } = decodeJWT(await createJWT(
146+
{ requested: ['name', 'phone'], iat: undefined },
147+
{ issuer: did, signer }
148+
))
149+
return expect(payload.iat).toBeUndefined()
150+
})
151+
118152
it('throws an error if unsupported algorithm is passed in', () => {
119153
return createJWT(
120154
{ requested: ['name', 'phone'] },
@@ -152,7 +186,7 @@ describe('createJWT()', () => {
152186

153187
it('creates a JWT with expiry in 10000 seconds', () => {
154188
return createJWT(
155-
{ requested: ['name', 'phone'] },
189+
{ requested: ['name', 'phone'], nbf: Math.floor(new Date().getTime() / 1000) },
156190
{ alg, issuer: did, signer, expiresIn: 10000 }
157191
).then(jwt => {
158192
const { payload } = decodeJWT(jwt)

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

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,95 +2,96 @@
22

33
exports[`createJWT() ES256K creates a JWT with correct format 1`] = `
44
Object {
5-
"data": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJuYmYiOjE0ODUzMjExMzMsInJlcXVlc3RlZCI6WyJuYW1lIiwicGhvbmUiXSwiaXNzIjoiZGlkOnVwb3J0OjJuUXRpUUc2Q2dtMUdZVEJhYUtBZ3I3NnVZN2lTZXhVa3FYIn0",
5+
"data": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpYXQiOjE0ODUzMjExMzMsInJlcXVlc3RlZCI6WyJuYW1lIiwicGhvbmUiXSwiaXNzIjoiZGlkOnVwb3J0OjJuUXRpUUc2Q2dtMUdZVEJhYUtBZ3I3NnVZN2lTZXhVa3FYIn0",
66
"header": Object {
77
"alg": "ES256K",
88
"typ": "JWT",
99
},
1010
"payload": Object {
11+
"iat": 1485321133,
1112
"iss": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX",
12-
"nbf": 1485321133,
1313
"requested": Array [
1414
"name",
1515
"phone",
1616
],
1717
},
18-
"signature": "a0u5aiRRsxTj0-bVN_pfCl95izb2bDuCsMiODbwH_wrFBH6IcLCQRclByepu0Yu__0CWyw-TQfYuxxdx-wExYw",
18+
"signature": "4zZKylwG3_1WPPd0HEpeOt1uUplyXhIGQ7G26wx0T1fnwovYcXQUA-FY3Cp13iA0XwMT8kIlxwsuMFCYMdw1sw",
1919
}
2020
`;
2121

2222
exports[`createJWT() ES256K creates a JWT with correct legacy format 1`] = `
2323
Object {
24-
"data": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJuYmYiOjE0ODUzMjExMzMsInJlcXVlc3RlZCI6WyJuYW1lIiwicGhvbmUiXSwiaXNzIjoiMm5RdGlRRzZDZ20xR1lUQmFhS0Fncjc2dVk3aVNleFVrcVgifQ",
24+
"data": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpYXQiOjE0ODUzMjExMzMsInJlcXVlc3RlZCI6WyJuYW1lIiwicGhvbmUiXSwiaXNzIjoiMm5RdGlRRzZDZ20xR1lUQmFhS0Fncjc2dVk3aVNleFVrcVgifQ",
2525
"header": Object {
2626
"alg": "ES256K",
2727
"typ": "JWT",
2828
},
2929
"payload": Object {
30+
"iat": 1485321133,
3031
"iss": "2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX",
31-
"nbf": 1485321133,
3232
"requested": Array [
3333
"name",
3434
"phone",
3535
],
3636
},
37-
"signature": "YPk7tICPNhJwm251UAqLR9iskfKKVGloiAks1ndtdZv2SzRk2X9jN2LOxusJQUNoLlH1TkP0yiJb2nU4Rqrjag",
37+
"signature": "D1Tx-R9g-pyGAb4C486fx_1Scwf74JcoUC2xYRJ6cZFW9zwBs_NZEZg3bptrMfmNRao_2A2cbCncRKPpV7TycQ",
3838
}
3939
`;
4040

4141
exports[`createJWT() Ed25519 creates a JWT with correct format 1`] = `
4242
Object {
43-
"data": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFZDI1NTE5In0.eyJuYmYiOjE0ODUzMjExMzMsInJlcXVlc3RlZCI6WyJuYW1lIiwicGhvbmUiXSwiaXNzIjoiZGlkOm5hY2w6QnZyQjhpSkF6XzFqZnExbVJ4aUVLZnI5cWNuTGZxNURPR3JCZjJFUlVIVSJ9",
43+
"data": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFZDI1NTE5In0.eyJpYXQiOjE0ODUzMjExMzMsInJlcXVlc3RlZCI6WyJuYW1lIiwicGhvbmUiXSwiaXNzIjoiZGlkOm5hY2w6QnZyQjhpSkF6XzFqZnExbVJ4aUVLZnI5cWNuTGZxNURPR3JCZjJFUlVIVSJ9",
4444
"header": Object {
4545
"alg": "Ed25519",
4646
"typ": "JWT",
4747
},
4848
"payload": Object {
49+
"iat": 1485321133,
4950
"iss": "did:nacl:BvrB8iJAz_1jfq1mRxiEKfr9qcnLfq5DOGrBf2ERUHU",
50-
"nbf": 1485321133,
5151
"requested": Array [
5252
"name",
5353
"phone",
5454
],
5555
},
56-
"signature": "TVkTb7Copwq40dj9a8iorOi0yk_akAAW0VcsUk-XpzxGJiWMas8nXDwnxUvyPBSQLNGHu3teI0HSRBbzAiZAAg",
56+
"signature": "ZoPf01SxW2n5zngunI942FpviEMP6jBZZb9NJ27M_K7AcmjPeeLH8bm2lv0INmJ2u98JVSzELF8YLWQvPYB1Bw",
5757
}
5858
`;
5959

6060
exports[`verifyJWT() accepts a valid MNID audience 1`] = `
6161
Object {
6262
"aud": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqY",
63+
"iat": 1485321133,
6364
"iss": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX",
64-
"nbf": 1485321133,
6565
}
6666
`;
6767

6868
exports[`verifyJWT() accepts a valid audience 1`] = `
6969
Object {
7070
"aud": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqY",
71+
"iat": 1485321133,
7172
"iss": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX",
72-
"nbf": 1485321133,
7373
}
7474
`;
7575

7676
exports[`verifyJWT() accepts a valid audience using callback_url 1`] = `
7777
Object {
7878
"aud": "http://pututu.uport.me/unique",
79+
"iat": 1485321133,
7980
"iss": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX",
80-
"nbf": 1485321133,
8181
}
8282
`;
8383

8484
exports[`verifyJWT() accepts a valid exp 1`] = `
8585
Object {
8686
"exp": 1485320834,
87+
"iat": 1485321133,
8788
"iss": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX",
88-
"nbf": 1485321133,
8989
}
9090
`;
9191

9292
exports[`verifyJWT() accepts a valid nbf 1`] = `
9393
Object {
94+
"iat": 1485321133,
9495
"iss": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX",
9596
"nbf": 1485321433,
9697
}
@@ -99,16 +100,16 @@ Object {
99100
exports[`verifyJWT() handles ES256K-R algorithm 1`] = `
100101
Object {
101102
"hello": "world",
103+
"iat": 1485321133,
102104
"iss": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX",
103-
"nbf": 1485321133,
104105
}
105106
`;
106107

107108
exports[`verifyJWT() handles ES256K-R algorithm with ethereum address 1`] = `
108109
Object {
109110
"hello": "world",
111+
"iat": 1485321133,
110112
"iss": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqY",
111-
"nbf": 1485321133,
112113
}
113114
`;
114115

0 commit comments

Comments
 (0)