@travetto/auth-web 7.1.3 → 8.0.0-alpha.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 CHANGED
@@ -52,7 +52,7 @@ export interface Authenticator<T = unknown, C = unknown, P extends Principal = P
52
52
  *
53
53
  * @returns Valid principal if authenticated
54
54
  * @returns undefined if authentication is valid, but incomplete (multi-step)
55
- * @throws AppError if authentication fails
55
+ * @throws Error if authentication fails
56
56
  */
57
57
  authenticate(payload: T, context?: C): Promise<P | undefined> | P | undefined;
58
58
  }
@@ -123,7 +123,7 @@ import type { Jwt, Verifier, SupportedAlgorithms } from 'njwt';
123
123
  import { type AuthContext, AuthenticationError, type AuthToken, type Principal } from '@travetto/auth';
124
124
  import { Injectable, Inject } from '@travetto/di';
125
125
  import { type WebResponse, type WebRequest, type WebAsyncContext, CookieJar } from '@travetto/web';
126
- import { AppError, castTo, TimeUtil } from '@travetto/runtime';
126
+ import { RuntimeError, castTo, TimeUtil } from '@travetto/runtime';
127
127
 
128
128
  import { CommonPrincipalCodecSymbol, type PrincipalCodec } from './types.ts';
129
129
  import type { WebAuthConfig } from './config.ts';
@@ -186,13 +186,13 @@ export class JWTPrincipalCodec implements PrincipalCodec {
186
186
  async create(value: Principal, keyId: string = 'default'): Promise<string> {
187
187
  const entry = this.config.keyMap[keyId];
188
188
  if (!entry) {
189
- throw new AppError('Requested unknown key for signing');
189
+ throw new RuntimeError('Requested unknown key for signing');
190
190
  }
191
191
  // Weird issue with their ES module support
192
192
  const { default: { create } } = await import('njwt');
193
193
  const jwt = create({}, '-')
194
194
  .setExpiration(value.expiresAt!)
195
- .setIssuedAt(TimeUtil.asSeconds(value.issuedAt!))
195
+ .setIssuedAt(TimeUtil.duration((value.issuedAt ?? new Date()).getTime(), 's'))
196
196
  .setClaim('core', castTo({ ...value }))
197
197
  .setIssuer(value.issuer!)
198
198
  .setJti(value.sessionId!)
@@ -225,7 +225,7 @@ A trivial/sample custom [PrincipalCodec](https://github.com/travetto/travetto/tr
225
225
  import type { Principal } from '@travetto/auth';
226
226
  import type { PrincipalCodec } from '@travetto/auth-web';
227
227
  import { Injectable } from '@travetto/di';
228
- import { BinaryUtil } from '@travetto/runtime';
228
+ import { BinaryMetadataUtil } from '@travetto/runtime';
229
229
  import type { WebResponse, WebRequest } from '@travetto/web';
230
230
 
231
231
  @Injectable()
@@ -234,7 +234,7 @@ export class CustomCodec implements PrincipalCodec {
234
234
 
235
235
  decode(request: WebRequest): Promise<Principal | undefined> | Principal | undefined {
236
236
  const [userId, sig] = request.headers.get('USER_ID')?.split(':') ?? [];
237
- if (userId && sig === BinaryUtil.hash(userId + this.secret)) {
237
+ if (userId && sig === BinaryMetadataUtil.hash(userId + this.secret)) {
238
238
  let principal: Principal | undefined;
239
239
  // Lookup user from db, remote system, etc.,
240
240
  return principal;
@@ -243,7 +243,7 @@ export class CustomCodec implements PrincipalCodec {
243
243
  }
244
244
  encode(response: WebResponse, data: Principal | undefined): WebResponse {
245
245
  if (data) {
246
- response.headers.set('USER_ID', `${data.id}:${BinaryUtil.hash(data.id + this.secret)}`);
246
+ response.headers.set('USER_ID', `${data.id}:${BinaryMetadataUtil.hash(data.id + this.secret)}`);
247
247
  }
248
248
  return response;
249
249
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/auth-web",
3
- "version": "7.1.3",
3
+ "version": "8.0.0-alpha.0",
4
4
  "type": "module",
5
5
  "description": "Web authentication integration support for the Travetto framework",
6
6
  "keywords": [
@@ -27,13 +27,13 @@
27
27
  "directory": "module/auth-web"
28
28
  },
29
29
  "dependencies": {
30
- "@travetto/auth": "^7.1.3",
31
- "@travetto/config": "^7.1.3",
32
- "@travetto/web": "^7.1.3",
30
+ "@travetto/auth": "^8.0.0-alpha.0",
31
+ "@travetto/config": "^8.0.0-alpha.0",
32
+ "@travetto/web": "^8.0.0-alpha.0",
33
33
  "njwt": "^2.0.1"
34
34
  },
35
35
  "peerDependencies": {
36
- "@travetto/test": "^7.1.3"
36
+ "@travetto/test": "^8.0.0-alpha.0"
37
37
  },
38
38
  "peerDependenciesMeta": {
39
39
  "@travetto/test": {
package/src/codec.ts CHANGED
@@ -3,7 +3,7 @@ import type { Jwt, Verifier, SupportedAlgorithms } from 'njwt';
3
3
  import { type AuthContext, AuthenticationError, type AuthToken, type Principal } from '@travetto/auth';
4
4
  import { Injectable, Inject } from '@travetto/di';
5
5
  import { type WebResponse, type WebRequest, type WebAsyncContext, CookieJar } from '@travetto/web';
6
- import { AppError, castTo, TimeUtil } from '@travetto/runtime';
6
+ import { RuntimeError, castTo, TimeUtil } from '@travetto/runtime';
7
7
 
8
8
  import { CommonPrincipalCodecSymbol, type PrincipalCodec } from './types.ts';
9
9
  import type { WebAuthConfig } from './config.ts';
@@ -66,13 +66,13 @@ export class JWTPrincipalCodec implements PrincipalCodec {
66
66
  async create(value: Principal, keyId: string = 'default'): Promise<string> {
67
67
  const entry = this.config.keyMap[keyId];
68
68
  if (!entry) {
69
- throw new AppError('Requested unknown key for signing');
69
+ throw new RuntimeError('Requested unknown key for signing');
70
70
  }
71
71
  // Weird issue with their ES module support
72
72
  const { default: { create } } = await import('njwt');
73
73
  const jwt = create({}, '-')
74
74
  .setExpiration(value.expiresAt!)
75
- .setIssuedAt(TimeUtil.asSeconds(value.issuedAt!))
75
+ .setIssuedAt(TimeUtil.duration((value.issuedAt ?? new Date()).getTime(), 's'))
76
76
  .setClaim('core', castTo({ ...value }))
77
77
  .setIssuer(value.issuer!)
78
78
  .setJti(value.sessionId!)
package/src/config.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Config } from '@travetto/config';
2
- import { Runtime, AppError, BinaryUtil } from '@travetto/runtime';
2
+ import { Runtime, RuntimeError, BinaryMetadataUtil } from '@travetto/runtime';
3
3
  import { Ignore, Secret } from '@travetto/schema';
4
4
 
5
5
  type KeyEntry = { key: string, id: string };
@@ -19,11 +19,11 @@ export class WebAuthConfig {
19
19
 
20
20
  postConstruct(): void {
21
21
  if (!this.signingKey && Runtime.production) {
22
- throw new AppError('The default signing key is only valid for development use, please specify a config value at web.auth.signingKey');
22
+ throw new RuntimeError('The default signing key is only valid for development use, please specify a config value at web.auth.signingKey');
23
23
  }
24
24
  this.signingKey ??= 'dummy';
25
25
 
26
- const all = [this.signingKey].flat().map(key => ({ key, id: BinaryUtil.hash(key, 8) }));
26
+ const all = [this.signingKey].flat().map(key => ({ key, id: BinaryMetadataUtil.hash(key, { length: 8 }) }));
27
27
  this.keyMap = Object.fromEntries(all.map(entry => [entry.id, entry]));
28
28
  this.keyMap.default = all[0];
29
29
  }
@@ -1,4 +1,4 @@
1
- import { AppError, Util } from '@travetto/runtime';
1
+ import { RuntimeError, Util } from '@travetto/runtime';
2
2
  import type { WebInterceptor, WebInterceptorCategory, WebChainedContext, WebResponse, WebInterceptorContext } from '@travetto/web';
3
3
  import { Injectable, Inject } from '@travetto/di';
4
4
  import { Config } from '@travetto/config';
@@ -72,7 +72,7 @@ export class AuthVerifyInterceptor implements WebInterceptor<WebAuthVerifyConfig
72
72
  if (!principal) {
73
73
  throw new AuthenticationError('User is unauthenticated');
74
74
  } else if (!config.matcher(new Set(principal.permissions))) {
75
- throw new AppError('Access denied', { category: 'permissions' });
75
+ throw new RuntimeError('Access denied', { category: 'permissions' });
76
76
  }
77
77
  break;
78
78
  }
@@ -89,16 +89,20 @@ export abstract class AuthWebServerSuite extends BaseWebSuite {
89
89
  @Inject()
90
90
  config: WebAuthConfig;
91
91
 
92
- getCookie(headers: WebHeaders): Cookie | undefined {
93
- return new CookieJar().importSetCookieHeader(headers.getSetCookie()).getAll()[0];
92
+ async getCookie(headers: WebHeaders): Promise<Cookie | undefined> {
93
+ const jar = new CookieJar();
94
+ await jar.importSetCookieHeader(headers.getSetCookie());
95
+ return jar.getAll()[0];
94
96
  }
95
97
 
96
- getCookieHeader(headers: WebHeaders): string | undefined {
97
- return new CookieJar().importSetCookieHeader(headers.getSetCookie()).exportCookieHeader();
98
+ async getCookieHeader(headers: WebHeaders): Promise<string | undefined> {
99
+ const jar = new CookieJar();
100
+ await jar.importSetCookieHeader(headers.getSetCookie());
101
+ return jar.exportCookieHeader();
98
102
  }
99
103
 
100
- getCookieExpires(headers: WebHeaders): Date | undefined {
101
- const v = this.getCookie(headers)?.expires;
104
+ async getCookieExpires(headers: WebHeaders): Promise<Date | undefined> {
105
+ const v = (await this.getCookie(headers))?.expires;
102
106
  return v ? new Date(v) : undefined;
103
107
  }
104
108
 
@@ -151,7 +155,7 @@ export abstract class AuthWebServerSuite extends BaseWebSuite {
151
155
  }
152
156
  }, false);
153
157
  assert(statusCode === 201);
154
- const cookie = this.getCookieHeader(headers);
158
+ const cookie = await this.getCookieHeader(headers);
155
159
  assert(cookie);
156
160
 
157
161
  const { context: { httpStatusCode: lastStatus } } = await this.request({
@@ -222,7 +226,7 @@ export abstract class AuthWebServerSuite extends BaseWebSuite {
222
226
  }
223
227
  }, false);
224
228
  assert(statusCode === 201);
225
- const cookie = this.getCookieHeader(headers);
229
+ const cookie = await this.getCookieHeader(headers);
226
230
  assert(cookie);
227
231
 
228
232
  const { body, context: { httpStatusCode: lastStatus } } = await this.request({
@@ -250,17 +254,17 @@ export abstract class AuthWebServerSuite extends BaseWebSuite {
250
254
  assert(statusCode === 201);
251
255
 
252
256
  const start = Date.now();
253
- const cookie = this.getCookieHeader(headers);
257
+ const cookie = await this.getCookieHeader(headers);
254
258
  assert(cookie);
255
259
 
256
- const expires = this.getCookieExpires(headers);
260
+ const expires = await this.getCookieExpires(headers);
257
261
  assert(expires);
258
262
 
259
263
  const { headers: selfHeaders, context: { httpStatusCode: lastStatus } } = await this.request({
260
264
  context: { httpMethod: 'GET', path: '/test/auth/self' },
261
265
  headers: { cookie }
262
266
  }, false);
263
- assert(this.getCookie(selfHeaders) === undefined);
267
+ assert(await this.getCookie(selfHeaders) === undefined);
264
268
  assert(lastStatus === 200);
265
269
 
266
270
  const used = (Date.now() - start);
@@ -272,9 +276,9 @@ export abstract class AuthWebServerSuite extends BaseWebSuite {
272
276
  headers: { cookie }
273
277
  }, false);
274
278
  assert(lastStatus2 === 200);
275
- assert(this.getCookie(selfHeadersRenew));
279
+ assert(await this.getCookie(selfHeadersRenew));
276
280
 
277
- const expiresRenew = this.getCookieExpires(selfHeadersRenew);
281
+ const expiresRenew = await this.getCookieExpires(selfHeadersRenew);
278
282
  assert(expiresRenew);
279
283
 
280
284
  const delta = expiresRenew.getTime() - expires.getTime();