Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Set iat timestamp by default instead of nbf #43

Merged
merged 6 commits into from
Aug 13, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions src/JWT.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ interface JWTPayload {
iss?: string
sub?: string
aud?: string
iat?: number
nbf?: number
type?: string
exp?: number
Expand Down Expand Up @@ -152,19 +153,19 @@ export function decodeJWT(jwt: string): JWTDecoded {
*/
// export async function createJWT(payload, { issuer, signer, alg, expiresIn }) {
export async function createJWT(
payload: object,
payload: any,
{ issuer, signer, alg, expiresIn }: JWTOptions
): Promise<string> {
if (!signer) throw new Error('No Signer functionality has been configured')
if (!issuer) throw new Error('No issuing DID has been configured')
const header: JWTHeader = { typ: 'JWT', alg: alg || defaultAlg }
const timestamps: Partial<JWTPayload> = {
nbf: Math.floor(Date.now() / 1000),
iat: Math.floor(Date.now() / 1000),
exp: undefined
}
if (expiresIn) {
if (expiresIn && payload.nbf) {
if (typeof expiresIn === 'number') {
timestamps.exp = timestamps.nbf + Math.floor(expiresIn)
timestamps.exp = payload.nbf + Math.floor(expiresIn)
} else {
throw new Error('JWT expiresIn is not a number')
}
Expand Down
38 changes: 36 additions & 2 deletions src/__tests__/JWT-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,48 @@ describe('createJWT()', () => {

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

it('ignores expiresIn if nbf is not set', async () => {
const { payload } = decodeJWT(await createJWT(
{ requested: ['name', 'phone'] },
{ issuer: did, signer, expiresIn: 10000 }
))
return expect(payload.exp).toBeUndefined()
})

it('sets iat to the current time by default', async () => {
const timestamp = Math.floor(Date.now() / 1000)
const { payload } = decodeJWT(await createJWT(
{ requested: ['name', 'phone'] },
{ issuer: did, signer }
))
return expect(payload.iat).toEqual(timestamp)
})

it('sets iat to the value passed in payload', async () => {
const timestamp = 2000000
const { payload } = decodeJWT(await createJWT(
{ requested: ['name', 'phone'], iat: timestamp },
{ issuer: did, signer }
))
return expect(payload.iat).toEqual(timestamp)
})

it('does not set iat if value in payload is undefined', async () => {
const { payload } = decodeJWT(await createJWT(
{ requested: ['name', 'phone'], iat: undefined },
{ issuer: did, signer }
))
return expect(payload.iat).toBeUndefined()
})

it('throws an error if unsupported algorithm is passed in', () => {
return createJWT(
{ requested: ['name', 'phone'] },
Expand Down Expand Up @@ -152,7 +186,7 @@ describe('createJWT()', () => {

it('creates a JWT with expiry in 10000 seconds', () => {
return createJWT(
{ requested: ['name', 'phone'] },
{ requested: ['name', 'phone'], nbf: Math.floor(new Date().getTime() / 1000) },
{ alg, issuer: did, signer, expiresIn: 10000 }
).then(jwt => {
const { payload } = decodeJWT(jwt)
Expand Down
31 changes: 16 additions & 15 deletions src/__tests__/__snapshots__/JWT-test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -2,95 +2,96 @@

exports[`createJWT() ES256K creates a JWT with correct format 1`] = `
Object {
"data": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJuYmYiOjE0ODUzMjExMzMsInJlcXVlc3RlZCI6WyJuYW1lIiwicGhvbmUiXSwiaXNzIjoiZGlkOnVwb3J0OjJuUXRpUUc2Q2dtMUdZVEJhYUtBZ3I3NnVZN2lTZXhVa3FYIn0",
"data": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpYXQiOjE0ODUzMjExMzMsInJlcXVlc3RlZCI6WyJuYW1lIiwicGhvbmUiXSwiaXNzIjoiZGlkOnVwb3J0OjJuUXRpUUc2Q2dtMUdZVEJhYUtBZ3I3NnVZN2lTZXhVa3FYIn0",
"header": Object {
"alg": "ES256K",
"typ": "JWT",
},
"payload": Object {
"iat": 1485321133,
"iss": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX",
"nbf": 1485321133,
"requested": Array [
"name",
"phone",
],
},
"signature": "a0u5aiRRsxTj0-bVN_pfCl95izb2bDuCsMiODbwH_wrFBH6IcLCQRclByepu0Yu__0CWyw-TQfYuxxdx-wExYw",
"signature": "4zZKylwG3_1WPPd0HEpeOt1uUplyXhIGQ7G26wx0T1fnwovYcXQUA-FY3Cp13iA0XwMT8kIlxwsuMFCYMdw1sw",
}
`;

exports[`createJWT() ES256K creates a JWT with correct legacy format 1`] = `
Object {
"data": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJuYmYiOjE0ODUzMjExMzMsInJlcXVlc3RlZCI6WyJuYW1lIiwicGhvbmUiXSwiaXNzIjoiMm5RdGlRRzZDZ20xR1lUQmFhS0Fncjc2dVk3aVNleFVrcVgifQ",
"data": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJpYXQiOjE0ODUzMjExMzMsInJlcXVlc3RlZCI6WyJuYW1lIiwicGhvbmUiXSwiaXNzIjoiMm5RdGlRRzZDZ20xR1lUQmFhS0Fncjc2dVk3aVNleFVrcVgifQ",
"header": Object {
"alg": "ES256K",
"typ": "JWT",
},
"payload": Object {
"iat": 1485321133,
"iss": "2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX",
"nbf": 1485321133,
"requested": Array [
"name",
"phone",
],
},
"signature": "YPk7tICPNhJwm251UAqLR9iskfKKVGloiAks1ndtdZv2SzRk2X9jN2LOxusJQUNoLlH1TkP0yiJb2nU4Rqrjag",
"signature": "D1Tx-R9g-pyGAb4C486fx_1Scwf74JcoUC2xYRJ6cZFW9zwBs_NZEZg3bptrMfmNRao_2A2cbCncRKPpV7TycQ",
}
`;

exports[`createJWT() Ed25519 creates a JWT with correct format 1`] = `
Object {
"data": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFZDI1NTE5In0.eyJuYmYiOjE0ODUzMjExMzMsInJlcXVlc3RlZCI6WyJuYW1lIiwicGhvbmUiXSwiaXNzIjoiZGlkOm5hY2w6QnZyQjhpSkF6XzFqZnExbVJ4aUVLZnI5cWNuTGZxNURPR3JCZjJFUlVIVSJ9",
"data": "eyJ0eXAiOiJKV1QiLCJhbGciOiJFZDI1NTE5In0.eyJpYXQiOjE0ODUzMjExMzMsInJlcXVlc3RlZCI6WyJuYW1lIiwicGhvbmUiXSwiaXNzIjoiZGlkOm5hY2w6QnZyQjhpSkF6XzFqZnExbVJ4aUVLZnI5cWNuTGZxNURPR3JCZjJFUlVIVSJ9",
"header": Object {
"alg": "Ed25519",
"typ": "JWT",
},
"payload": Object {
"iat": 1485321133,
"iss": "did:nacl:BvrB8iJAz_1jfq1mRxiEKfr9qcnLfq5DOGrBf2ERUHU",
"nbf": 1485321133,
"requested": Array [
"name",
"phone",
],
},
"signature": "TVkTb7Copwq40dj9a8iorOi0yk_akAAW0VcsUk-XpzxGJiWMas8nXDwnxUvyPBSQLNGHu3teI0HSRBbzAiZAAg",
"signature": "ZoPf01SxW2n5zngunI942FpviEMP6jBZZb9NJ27M_K7AcmjPeeLH8bm2lv0INmJ2u98JVSzELF8YLWQvPYB1Bw",
}
`;

exports[`verifyJWT() accepts a valid MNID audience 1`] = `
Object {
"aud": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqY",
"iat": 1485321133,
"iss": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX",
"nbf": 1485321133,
}
`;

exports[`verifyJWT() accepts a valid audience 1`] = `
Object {
"aud": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqY",
"iat": 1485321133,
"iss": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX",
"nbf": 1485321133,
}
`;

exports[`verifyJWT() accepts a valid audience using callback_url 1`] = `
Object {
"aud": "http://pututu.uport.me/unique",
"iat": 1485321133,
"iss": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX",
"nbf": 1485321133,
}
`;

exports[`verifyJWT() accepts a valid exp 1`] = `
Object {
"exp": 1485320834,
"iat": 1485321133,
"iss": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX",
"nbf": 1485321133,
}
`;

exports[`verifyJWT() accepts a valid nbf 1`] = `
Object {
"iat": 1485321133,
"iss": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX",
"nbf": 1485321433,
}
Expand All @@ -99,16 +100,16 @@ Object {
exports[`verifyJWT() handles ES256K-R algorithm 1`] = `
Object {
"hello": "world",
"iat": 1485321133,
"iss": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqX",
"nbf": 1485321133,
}
`;

exports[`verifyJWT() handles ES256K-R algorithm with ethereum address 1`] = `
Object {
"hello": "world",
"iat": 1485321133,
"iss": "did:uport:2nQtiQG6Cgm1GYTBaaKAgr76uY7iSexUkqY",
"nbf": 1485321133,
}
`;

Expand Down