@geekmidas/auth 0.0.5 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +343 -214
- package/dist/{cacheTokenStorage-Ca05vf3T.mjs → cacheTokenStorage-16NE8Cd9.mjs} +3 -3
- package/dist/cacheTokenStorage-16NE8Cd9.mjs.map +1 -0
- package/dist/{cacheTokenStorage-BzBRJfd-.d.mts → cacheTokenStorage-B7sOoysu.d.cts} +8 -6
- package/dist/cacheTokenStorage-B7sOoysu.d.cts.map +1 -0
- package/dist/{cacheTokenStorage-CvptztkW.cjs → cacheTokenStorage-CEpMniTi.cjs} +3 -3
- package/dist/cacheTokenStorage-CEpMniTi.cjs.map +1 -0
- package/dist/{cacheTokenStorage-yNUpDD8W.d.cts → cacheTokenStorage-_tq4Kmhc.d.mts} +8 -6
- package/dist/cacheTokenStorage-_tq4Kmhc.d.mts.map +1 -0
- package/dist/cacheTokenStorage.cjs +1 -1
- package/dist/cacheTokenStorage.d.cts +1 -1
- package/dist/cacheTokenStorage.d.mts +1 -1
- package/dist/cacheTokenStorage.mjs +1 -1
- package/dist/{client-DaiUm0UZ.cjs → client-BPl_mMvb.cjs} +14 -8
- package/dist/client-BPl_mMvb.cjs.map +1 -0
- package/dist/{client-DjNZS6vZ.mjs → client-eidYNJSH.mjs} +14 -8
- package/dist/client-eidYNJSH.mjs.map +1 -0
- package/dist/client.cjs +2 -2
- package/dist/client.d.cts +1 -1
- package/dist/client.d.mts +1 -1
- package/dist/client.mjs +2 -2
- package/dist/hono/jwt.cjs +1 -1
- package/dist/hono/jwt.cjs.map +1 -1
- package/dist/hono/jwt.d.cts +2 -1
- package/dist/hono/jwt.d.cts.map +1 -0
- package/dist/hono/jwt.d.mts +2 -1
- package/dist/hono/jwt.d.mts.map +1 -0
- package/dist/hono/jwt.mjs +1 -1
- package/dist/hono/jwt.mjs.map +1 -1
- package/dist/hono/oidc.cjs +1 -1
- package/dist/hono/oidc.cjs.map +1 -1
- package/dist/hono/oidc.d.cts +3 -2
- package/dist/hono/oidc.d.cts.map +1 -0
- package/dist/hono/oidc.d.mts +3 -2
- package/dist/hono/oidc.d.mts.map +1 -0
- package/dist/hono/oidc.mjs +1 -1
- package/dist/hono/oidc.mjs.map +1 -1
- package/dist/index.cjs +3 -3
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/index.mjs +3 -3
- package/dist/{jwt-DF9kFbmh.d.cts → jwt-3eIuY2dg.d.cts} +2 -1
- package/dist/jwt-3eIuY2dg.d.cts.map +1 -0
- package/dist/jwt-Bo_eACEi.cjs.map +1 -1
- package/dist/{jwt-DH8CJ2xC.d.mts → jwt-BqLlRkw-.d.mts} +2 -1
- package/dist/jwt-BqLlRkw-.d.mts.map +1 -0
- package/dist/jwt-D88cPJyT.mjs.map +1 -1
- package/dist/jwt.d.cts +1 -1
- package/dist/jwt.d.mts +1 -1
- package/dist/lambda/jwt.cjs +2 -2
- package/dist/lambda/jwt.cjs.map +1 -1
- package/dist/lambda/jwt.d.cts +2 -1
- package/dist/lambda/jwt.d.cts.map +1 -0
- package/dist/lambda/jwt.d.mts +2 -1
- package/dist/lambda/jwt.d.mts.map +1 -0
- package/dist/lambda/jwt.mjs +2 -2
- package/dist/lambda/jwt.mjs.map +1 -1
- package/dist/lambda/oidc.cjs +2 -2
- package/dist/lambda/oidc.cjs.map +1 -1
- package/dist/lambda/oidc.d.cts +3 -2
- package/dist/lambda/oidc.d.cts.map +1 -0
- package/dist/lambda/oidc.d.mts +3 -2
- package/dist/lambda/oidc.d.mts.map +1 -0
- package/dist/lambda/oidc.mjs +2 -2
- package/dist/lambda/oidc.mjs.map +1 -1
- package/dist/oidc-C0KyYaAK.cjs.map +1 -1
- package/dist/{oidc-CKOGLxjV.d.mts → oidc-ChA17wLB.d.cts} +3 -2
- package/dist/oidc-ChA17wLB.d.cts.map +1 -0
- package/dist/{oidc-DDLIB5gb.d.cts → oidc-DTRgBBl6.d.mts} +3 -2
- package/dist/oidc-DTRgBBl6.d.mts.map +1 -0
- package/dist/oidc-KA30gMlx.mjs.map +1 -1
- package/dist/oidc.d.cts +2 -2
- package/dist/oidc.d.mts +2 -2
- package/dist/server.cjs +2 -2
- package/dist/server.d.cts +2 -2
- package/dist/server.d.mts +2 -2
- package/dist/server.mjs +2 -2
- package/dist/{tokenManager--Q93eNYr.d.mts → tokenManager-CL3yE06D.d.cts} +2 -1
- package/dist/tokenManager-CL3yE06D.d.cts.map +1 -0
- package/dist/{tokenManager-BVXxfHRa.mjs → tokenManager-Ci2Tgxp8.mjs} +5 -3
- package/dist/tokenManager-Ci2Tgxp8.mjs.map +1 -0
- package/dist/{tokenManager-EPmwgai2.cjs → tokenManager-CvEMgxOp.cjs} +5 -3
- package/dist/tokenManager-CvEMgxOp.cjs.map +1 -0
- package/dist/{tokenManager-H6-lWEah.d.cts → tokenManager-RrwjL0y-.d.mts} +2 -1
- package/dist/tokenManager-RrwjL0y-.d.mts.map +1 -0
- package/dist/tokenManager.cjs +1 -1
- package/dist/tokenManager.d.cts +1 -1
- package/dist/tokenManager.d.mts +1 -1
- package/dist/tokenManager.mjs +1 -1
- package/package.json +10 -5
- package/src/__tests__/cacheTokenStorage.spec.ts +148 -148
- package/src/__tests__/client.spec.ts +339 -339
- package/src/__tests__/hono-jwt.spec.ts +219 -219
- package/src/__tests__/hono-oidc.spec.ts +560 -560
- package/src/__tests__/jwt.spec.ts +150 -127
- package/src/__tests__/lambda-jwt.spec.ts +205 -205
- package/src/__tests__/lambda-oidc.spec.ts +580 -579
- package/src/__tests__/oidc.spec.ts +365 -365
- package/src/__tests__/tokenManager.spec.ts +254 -254
- package/src/cacheTokenStorage.ts +32 -32
- package/src/client.ts +199 -190
- package/src/hono/jwt.ts +111 -111
- package/src/hono/oidc.ts +131 -131
- package/src/index.ts +2 -2
- package/src/jwt.ts +57 -57
- package/src/lambda/jwt.ts +170 -170
- package/src/lambda/oidc.ts +165 -165
- package/src/oidc.ts +121 -121
- package/src/server.ts +6 -7
- package/src/tokenManager.ts +89 -87
- package/tsconfig.json +10 -0
- package/dist/cacheTokenStorage-Ca05vf3T.mjs.map +0 -1
- package/dist/cacheTokenStorage-CvptztkW.cjs.map +0 -1
- package/dist/client-DaiUm0UZ.cjs.map +0 -1
- package/dist/client-DjNZS6vZ.mjs.map +0 -1
- package/dist/tokenManager-BVXxfHRa.mjs.map +0 -1
- package/dist/tokenManager-EPmwgai2.cjs.map +0 -1
|
@@ -1,174 +1,197 @@
|
|
|
1
1
|
import * as jose from 'jose';
|
|
2
2
|
import { describe, expect, it } from 'vitest';
|
|
3
|
-
import {
|
|
3
|
+
import { decodeJwt, JwtVerifier } from '../jwt';
|
|
4
4
|
|
|
5
5
|
const TEST_SECRET = 'super-secret-key-for-testing-only-32chars';
|
|
6
6
|
|
|
7
7
|
async function createTestToken(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
claims: Record<string, unknown> = {},
|
|
9
|
+
options: {
|
|
10
|
+
secret?: string;
|
|
11
|
+
expiresIn?: string;
|
|
12
|
+
issuer?: string;
|
|
13
|
+
audience?: string;
|
|
14
|
+
} = {},
|
|
15
15
|
) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
16
|
+
const secret = new TextEncoder().encode(options.secret ?? TEST_SECRET);
|
|
17
|
+
const jwt = new jose.SignJWT({ sub: 'user-123', ...claims })
|
|
18
|
+
.setProtectedHeader({ alg: 'HS256' })
|
|
19
|
+
.setIssuedAt();
|
|
20
|
+
|
|
21
|
+
if (options.expiresIn) {
|
|
22
|
+
jwt.setExpirationTime(options.expiresIn);
|
|
23
|
+
} else {
|
|
24
|
+
jwt.setExpirationTime('1h');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (options.issuer) {
|
|
28
|
+
jwt.setIssuer(options.issuer);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (options.audience) {
|
|
32
|
+
jwt.setAudience(options.audience);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return await jwt.sign(secret);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
describe('JwtVerifier', () => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
describe('with secret', () => {
|
|
40
|
+
it('should verify a valid token', async () => {
|
|
41
|
+
const verifier = new JwtVerifier({ secret: TEST_SECRET });
|
|
42
|
+
const token = await createTestToken();
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
const claims = await verifier.verify(token);
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
expect(claims.sub).toBe('user-123');
|
|
47
|
+
});
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
it('should throw for invalid token', async () => {
|
|
50
|
+
const verifier = new JwtVerifier({ secret: TEST_SECRET });
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
await expect(verifier.verify('invalid-token')).rejects.toThrow();
|
|
53
|
+
});
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
55
|
+
it('should throw for wrong secret', async () => {
|
|
56
|
+
const verifier = new JwtVerifier({ secret: TEST_SECRET });
|
|
57
|
+
const token = await createTestToken(
|
|
58
|
+
{},
|
|
59
|
+
{ secret: 'wrong-secret-key-32-chars-long!!' },
|
|
60
|
+
);
|
|
61
61
|
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
await expect(verifier.verify(token)).rejects.toThrow();
|
|
63
|
+
});
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
65
|
+
it('should throw for expired token', async () => {
|
|
66
|
+
const verifier = new JwtVerifier({ secret: TEST_SECRET });
|
|
67
|
+
const token = await createTestToken({}, { expiresIn: '-1h' });
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
await expect(verifier.verify(token)).rejects.toThrow();
|
|
70
|
+
});
|
|
71
71
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
72
|
+
it('should validate issuer when configured', async () => {
|
|
73
|
+
const verifier = new JwtVerifier({
|
|
74
|
+
secret: TEST_SECRET,
|
|
75
|
+
issuer: 'my-app',
|
|
76
|
+
});
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
const validToken = await createTestToken({}, { issuer: 'my-app' });
|
|
79
|
+
const invalidToken = await createTestToken({}, { issuer: 'other-app' });
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
81
|
+
await expect(verifier.verify(validToken)).resolves.toBeDefined();
|
|
82
|
+
await expect(verifier.verify(invalidToken)).rejects.toThrow();
|
|
83
|
+
});
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
85
|
+
it('should validate audience when configured', async () => {
|
|
86
|
+
const verifier = new JwtVerifier({
|
|
87
|
+
secret: TEST_SECRET,
|
|
88
|
+
audience: 'my-api',
|
|
89
|
+
});
|
|
90
90
|
|
|
91
|
-
|
|
92
|
-
|
|
91
|
+
const validToken = await createTestToken({}, { audience: 'my-api' });
|
|
92
|
+
const invalidToken = await createTestToken({}, { audience: 'other-api' });
|
|
93
93
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
94
|
+
await expect(verifier.verify(validToken)).resolves.toBeDefined();
|
|
95
|
+
await expect(verifier.verify(invalidToken)).rejects.toThrow();
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
98
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
99
|
+
describe('verifyOrNull', () => {
|
|
100
|
+
it('should return claims for valid token', async () => {
|
|
101
|
+
const verifier = new JwtVerifier({ secret: TEST_SECRET });
|
|
102
|
+
const token = await createTestToken();
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
const claims = await verifier.verifyOrNull(token);
|
|
105
105
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
expect(claims).not.toBeNull();
|
|
107
|
+
expect(claims?.sub).toBe('user-123');
|
|
108
|
+
});
|
|
109
109
|
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
it('should return null for invalid token', async () => {
|
|
111
|
+
const verifier = new JwtVerifier({ secret: TEST_SECRET });
|
|
112
112
|
|
|
113
|
-
|
|
113
|
+
const claims = await verifier.verifyOrNull('invalid-token');
|
|
114
114
|
|
|
115
|
-
|
|
116
|
-
|
|
115
|
+
expect(claims).toBeNull();
|
|
116
|
+
});
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
118
|
+
it('should return null for expired token', async () => {
|
|
119
|
+
const verifier = new JwtVerifier({ secret: TEST_SECRET });
|
|
120
|
+
const token = await createTestToken({}, { expiresIn: '-1h' });
|
|
121
121
|
|
|
122
|
-
|
|
122
|
+
const claims = await verifier.verifyOrNull(token);
|
|
123
123
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
124
|
+
expect(claims).toBeNull();
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
127
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
128
|
+
describe('custom claims', () => {
|
|
129
|
+
interface CustomClaims {
|
|
130
|
+
sub?: string;
|
|
131
|
+
role: string;
|
|
132
|
+
permissions: string[];
|
|
133
|
+
}
|
|
134
134
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
135
|
+
it('should return typed claims', async () => {
|
|
136
|
+
const verifier = new JwtVerifier<CustomClaims>({ secret: TEST_SECRET });
|
|
137
|
+
const token = await createTestToken({
|
|
138
|
+
role: 'admin',
|
|
139
|
+
permissions: ['read', 'write'],
|
|
140
|
+
});
|
|
141
141
|
|
|
142
|
-
|
|
142
|
+
const claims = await verifier.verify(token);
|
|
143
143
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
144
|
+
expect(claims.role).toBe('admin');
|
|
145
|
+
expect(claims.permissions).toEqual(['read', 'write']);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
describe('clearCache', () => {
|
|
151
|
+
it('should clear the JWKS cache', () => {
|
|
152
|
+
const verifier = new JwtVerifier({ secret: TEST_SECRET });
|
|
153
|
+
|
|
154
|
+
// Call clearCache - should not throw
|
|
155
|
+
verifier.clearCache();
|
|
156
|
+
|
|
157
|
+
// Verify the method exists and can be called
|
|
158
|
+
expect(verifier.clearCache).toBeDefined();
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it('should allow re-verification after clearing cache', async () => {
|
|
162
|
+
const verifier = new JwtVerifier({ secret: TEST_SECRET });
|
|
163
|
+
const token = await createTestToken();
|
|
164
|
+
|
|
165
|
+
const claims1 = await verifier.verify(token);
|
|
166
|
+
verifier.clearCache();
|
|
167
|
+
const claims2 = await verifier.verify(token);
|
|
168
|
+
|
|
169
|
+
expect(claims1.sub).toBe(claims2.sub);
|
|
170
|
+
});
|
|
148
171
|
});
|
|
149
172
|
|
|
150
173
|
describe('decodeJwt', () => {
|
|
151
|
-
|
|
152
|
-
|
|
174
|
+
it('should decode token without verification', async () => {
|
|
175
|
+
const token = await createTestToken({ custom: 'data' });
|
|
153
176
|
|
|
154
|
-
|
|
177
|
+
const claims = decodeJwt(token);
|
|
155
178
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
179
|
+
expect(claims.sub).toBe('user-123');
|
|
180
|
+
expect(claims).toHaveProperty('custom', 'data');
|
|
181
|
+
});
|
|
159
182
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
183
|
+
it('should decode token even with wrong secret', async () => {
|
|
184
|
+
const token = await createTestToken(
|
|
185
|
+
{},
|
|
186
|
+
{ secret: 'any-secret-32-characters-long!!' },
|
|
187
|
+
);
|
|
165
188
|
|
|
166
|
-
|
|
189
|
+
const claims = decodeJwt(token);
|
|
167
190
|
|
|
168
|
-
|
|
169
|
-
|
|
191
|
+
expect(claims.sub).toBe('user-123');
|
|
192
|
+
});
|
|
170
193
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
194
|
+
it('should throw for malformed token', () => {
|
|
195
|
+
expect(() => decodeJwt('not.a.valid.jwt')).toThrow();
|
|
196
|
+
});
|
|
174
197
|
});
|