Skip to content

Commit fc7e14e

Browse files
committed
test: add token expiry validator tests
1 parent 80b2991 commit fc7e14e

3 files changed

Lines changed: 90 additions & 0 deletions

File tree

src/constants/error.constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ export const ErrorCode = {
1515
JWT_ERROR: 'TOKEN_ERROR',
1616
INSUFFICIENT_BALANCE: 'insufficient_balance',
1717
NOT_A_CREATOR: 'not_a_creator',
18+
TOKEN_EXPIRY_TAMPERED: 'token_expiry_tampered',
19+
MISSING_IAT: 'missing_iat',
1820
} as const;
1921

2022
export type ErrorCodeType = (typeof ErrorCode)[keyof typeof ErrorCode];
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { validateTokenExpiry } from '../utils/token-expiry.validator';
2+
3+
describe('validateTokenExpiry', () => {
4+
it('accepts a token where exp === iat + ttl', () => {
5+
const payload = {
6+
iat: 1000,
7+
exp: 1060,
8+
ttlSeconds: 60,
9+
};
10+
11+
const result = validateTokenExpiry(payload);
12+
13+
expect(result.valid).toBe(true);
14+
});
15+
16+
it('rejects a token where exp > iat + ttl with token_expiry_tampered', () => {
17+
const payload = {
18+
iat: 1000,
19+
exp: 1100,
20+
ttlSeconds: 60,
21+
};
22+
23+
const result = validateTokenExpiry(payload);
24+
25+
expect(result.valid).toBe(false);
26+
expect(result.code).toBe('token_expiry_tampered');
27+
});
28+
29+
it('rejects a token where exp < iat + ttl with token_expiry_tampered', () => {
30+
const payload = {
31+
iat: 1000,
32+
exp: 1050,
33+
ttlSeconds: 60,
34+
};
35+
36+
const result = validateTokenExpiry(payload);
37+
38+
expect(result.valid).toBe(false);
39+
expect(result.code).toBe('token_expiry_tampered');
40+
});
41+
42+
it('rejects a token with no iat claim with missing_iat', () => {
43+
const payload = {
44+
exp: 1100,
45+
ttlSeconds: 60,
46+
};
47+
48+
const result = validateTokenExpiry(payload);
49+
50+
expect(result.valid).toBe(false);
51+
expect(result.code).toBe('missing_iat');
52+
});
53+
});
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Token expiry validator.
3+
*
4+
* Computes the expected expiry as iat + ttlSeconds and validates that
5+
* the token's exp claim matches. Returns specific error codes for
6+
* tampered expiry or missing iat claim.
7+
*/
8+
export interface TokenExpiryValidationResult {
9+
valid: boolean;
10+
code?: string;
11+
}
12+
13+
export function validateTokenExpiry(
14+
payload: { iat?: number; exp: number; ttlSeconds: number }
15+
): TokenExpiryValidationResult {
16+
if (payload.iat === undefined) {
17+
return { valid: false, code: 'missing_iat' };
18+
}
19+
20+
const expectedExp = payload.iat + payload.ttlSeconds;
21+
22+
if (payload.exp === expectedExp) {
23+
return { valid: true };
24+
}
25+
26+
if (payload.exp > expectedExp) {
27+
return { valid: false, code: 'token_expiry_tampered' };
28+
}
29+
30+
if (payload.exp < expectedExp) {
31+
return { valid: false, code: 'token_expiry_tampered' };
32+
}
33+
34+
return { valid: false };
35+
}

0 commit comments

Comments
 (0)