@travetto/auth-web 7.0.0-rc.2 → 7.0.0-rc.4
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 +15 -15
- package/package.json +5 -5
- package/src/codec.ts +13 -13
- package/src/config.ts +3 -3
- package/src/interceptors/context.ts +1 -1
- package/src/interceptors/verify.ts +4 -4
package/README.md
CHANGED
|
@@ -149,23 +149,23 @@ export class JWTPrincipalCodec implements PrincipalCodec {
|
|
|
149
149
|
postConstruct(): void {
|
|
150
150
|
this.#verifier = createVerifier()
|
|
151
151
|
.setSigningAlgorithm(this.#algorithm)
|
|
152
|
-
.withKeyResolver((
|
|
153
|
-
const
|
|
154
|
-
return
|
|
152
|
+
.withKeyResolver((keyId, callback) => {
|
|
153
|
+
const entry = this.config.keyMap[keyId];
|
|
154
|
+
return callback(entry ? null : new AuthenticationError('Invalid'), entry.key);
|
|
155
155
|
});
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
async verify(token: string): Promise<Principal> {
|
|
159
159
|
try {
|
|
160
|
-
const jwt: Jwt & { body: { core: Principal } } = await new Promise((
|
|
161
|
-
this.#verifier.verify(token, (
|
|
160
|
+
const jwt: Jwt & { body: { core: Principal } } = await new Promise((resolve, reject) =>
|
|
161
|
+
this.#verifier.verify(token, (error, verified) => error ? reject(error) : resolve(castTo(verified)))
|
|
162
162
|
);
|
|
163
163
|
return jwt.body.core;
|
|
164
|
-
} catch (
|
|
165
|
-
if (
|
|
166
|
-
throw new AuthenticationError(
|
|
164
|
+
} catch (error) {
|
|
165
|
+
if (error instanceof Error && error.name.startsWith('Jwt')) {
|
|
166
|
+
throw new AuthenticationError(error.message, { category: 'permissions' });
|
|
167
167
|
}
|
|
168
|
-
throw
|
|
168
|
+
throw error;
|
|
169
169
|
}
|
|
170
170
|
}
|
|
171
171
|
|
|
@@ -182,8 +182,8 @@ export class JWTPrincipalCodec implements PrincipalCodec {
|
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
async create(value: Principal, keyId: string = 'default'): Promise<string> {
|
|
185
|
-
const
|
|
186
|
-
if (!
|
|
185
|
+
const entry = this.config.keyMap[keyId];
|
|
186
|
+
if (!entry) {
|
|
187
187
|
throw new AppError('Requested unknown key for signing');
|
|
188
188
|
}
|
|
189
189
|
const jwt = create({}, '-')
|
|
@@ -193,8 +193,8 @@ export class JWTPrincipalCodec implements PrincipalCodec {
|
|
|
193
193
|
.setIssuer(value.issuer!)
|
|
194
194
|
.setJti(value.sessionId!)
|
|
195
195
|
.setSubject(value.id)
|
|
196
|
-
.setHeader('kid',
|
|
197
|
-
.setSigningKey(
|
|
196
|
+
.setHeader('kid', entry.id)
|
|
197
|
+
.setSigningKey(entry.key)
|
|
198
198
|
.setSigningAlgorithm(this.#algorithm);
|
|
199
199
|
return jwt.toString();
|
|
200
200
|
}
|
|
@@ -231,9 +231,9 @@ export class CustomCodec implements PrincipalCodec {
|
|
|
231
231
|
decode(request: WebRequest): Promise<Principal | undefined> | Principal | undefined {
|
|
232
232
|
const [userId, sig] = request.headers.get('USER_ID')?.split(':') ?? [];
|
|
233
233
|
if (userId && sig === BinaryUtil.hash(userId + this.secret)) {
|
|
234
|
-
let
|
|
234
|
+
let principal: Principal | undefined;
|
|
235
235
|
// Lookup user from db, remote system, etc.,
|
|
236
|
-
return
|
|
236
|
+
return principal;
|
|
237
237
|
}
|
|
238
238
|
return;
|
|
239
239
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/auth-web",
|
|
3
|
-
"version": "7.0.0-rc.
|
|
3
|
+
"version": "7.0.0-rc.4",
|
|
4
4
|
"description": "Web authentication integration support for the Travetto framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"authentication",
|
|
@@ -26,13 +26,13 @@
|
|
|
26
26
|
"directory": "module/auth-web"
|
|
27
27
|
},
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@travetto/auth": "^7.0.0-rc.
|
|
30
|
-
"@travetto/config": "^7.0.0-rc.
|
|
31
|
-
"@travetto/web": "^7.0.0-rc.
|
|
29
|
+
"@travetto/auth": "^7.0.0-rc.3",
|
|
30
|
+
"@travetto/config": "^7.0.0-rc.3",
|
|
31
|
+
"@travetto/web": "^7.0.0-rc.4",
|
|
32
32
|
"njwt": "^2.0.1"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@travetto/test": "^7.0.0-rc.
|
|
35
|
+
"@travetto/test": "^7.0.0-rc.3"
|
|
36
36
|
},
|
|
37
37
|
"peerDependenciesMeta": {
|
|
38
38
|
"@travetto/test": {
|
package/src/codec.ts
CHANGED
|
@@ -29,23 +29,23 @@ export class JWTPrincipalCodec implements PrincipalCodec {
|
|
|
29
29
|
postConstruct(): void {
|
|
30
30
|
this.#verifier = createVerifier()
|
|
31
31
|
.setSigningAlgorithm(this.#algorithm)
|
|
32
|
-
.withKeyResolver((
|
|
33
|
-
const
|
|
34
|
-
return
|
|
32
|
+
.withKeyResolver((keyId, callback) => {
|
|
33
|
+
const entry = this.config.keyMap[keyId];
|
|
34
|
+
return callback(entry ? null : new AuthenticationError('Invalid'), entry.key);
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
async verify(token: string): Promise<Principal> {
|
|
39
39
|
try {
|
|
40
|
-
const jwt: Jwt & { body: { core: Principal } } = await new Promise((
|
|
41
|
-
this.#verifier.verify(token, (
|
|
40
|
+
const jwt: Jwt & { body: { core: Principal } } = await new Promise((resolve, reject) =>
|
|
41
|
+
this.#verifier.verify(token, (error, verified) => error ? reject(error) : resolve(castTo(verified)))
|
|
42
42
|
);
|
|
43
43
|
return jwt.body.core;
|
|
44
|
-
} catch (
|
|
45
|
-
if (
|
|
46
|
-
throw new AuthenticationError(
|
|
44
|
+
} catch (error) {
|
|
45
|
+
if (error instanceof Error && error.name.startsWith('Jwt')) {
|
|
46
|
+
throw new AuthenticationError(error.message, { category: 'permissions' });
|
|
47
47
|
}
|
|
48
|
-
throw
|
|
48
|
+
throw error;
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
51
|
|
|
@@ -62,8 +62,8 @@ export class JWTPrincipalCodec implements PrincipalCodec {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
async create(value: Principal, keyId: string = 'default'): Promise<string> {
|
|
65
|
-
const
|
|
66
|
-
if (!
|
|
65
|
+
const entry = this.config.keyMap[keyId];
|
|
66
|
+
if (!entry) {
|
|
67
67
|
throw new AppError('Requested unknown key for signing');
|
|
68
68
|
}
|
|
69
69
|
const jwt = create({}, '-')
|
|
@@ -73,8 +73,8 @@ export class JWTPrincipalCodec implements PrincipalCodec {
|
|
|
73
73
|
.setIssuer(value.issuer!)
|
|
74
74
|
.setJti(value.sessionId!)
|
|
75
75
|
.setSubject(value.id)
|
|
76
|
-
.setHeader('kid',
|
|
77
|
-
.setSigningKey(
|
|
76
|
+
.setHeader('kid', entry.id)
|
|
77
|
+
.setSigningKey(entry.key)
|
|
78
78
|
.setSigningAlgorithm(this.#algorithm);
|
|
79
79
|
return jwt.toString();
|
|
80
80
|
}
|
package/src/config.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Config } from '@travetto/config';
|
|
|
2
2
|
import { Runtime, AppError, BinaryUtil } from '@travetto/runtime';
|
|
3
3
|
import { Ignore, Secret } from '@travetto/schema';
|
|
4
4
|
|
|
5
|
-
type
|
|
5
|
+
type KeyEntry = { key: string, id: string };
|
|
6
6
|
|
|
7
7
|
@Config('web.auth')
|
|
8
8
|
export class WebAuthConfig {
|
|
@@ -15,7 +15,7 @@ export class WebAuthConfig {
|
|
|
15
15
|
@Secret()
|
|
16
16
|
signingKey?: string | string[];
|
|
17
17
|
@Ignore()
|
|
18
|
-
keyMap: Record<string,
|
|
18
|
+
keyMap: Record<string, KeyEntry> & { default?: KeyEntry } = {};
|
|
19
19
|
|
|
20
20
|
postConstruct(): void {
|
|
21
21
|
if (!this.signingKey && Runtime.production) {
|
|
@@ -24,7 +24,7 @@ export class WebAuthConfig {
|
|
|
24
24
|
this.signingKey ??= 'dummy';
|
|
25
25
|
|
|
26
26
|
const all = [this.signingKey].flat().map(key => ({ key, id: BinaryUtil.hash(key, 8) }));
|
|
27
|
-
this.keyMap = Object.fromEntries(all.map(
|
|
27
|
+
this.keyMap = Object.fromEntries(all.map(entry => [entry.id, entry]));
|
|
28
28
|
this.keyMap.default = all[0];
|
|
29
29
|
}
|
|
30
30
|
}
|
|
@@ -7,7 +7,7 @@ import { Required } from '@travetto/schema';
|
|
|
7
7
|
import { CommonPrincipalCodecSymbol, PrincipalCodec } from '../types.ts';
|
|
8
8
|
import { WebAuthConfig } from '../config.ts';
|
|
9
9
|
|
|
10
|
-
const toDate = (
|
|
10
|
+
const toDate = (value: string | Date | undefined): Date | undefined => (typeof value === 'string') ? new Date(value) : value;
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Auth Context interceptor
|
|
@@ -7,9 +7,9 @@ import { AuthenticationError, AuthContext } from '@travetto/auth';
|
|
|
7
7
|
|
|
8
8
|
import { AuthContextInterceptor } from './context.ts';
|
|
9
9
|
|
|
10
|
-
function matchPermissionSet(rule: string[],
|
|
11
|
-
for (const
|
|
12
|
-
if (!
|
|
10
|
+
function matchPermissionSet(rule: string[], permissions: Set<string>): boolean {
|
|
11
|
+
for (const permission of rule) {
|
|
12
|
+
if (!permissions.has(permission)) {
|
|
13
13
|
return false;
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -54,7 +54,7 @@ export class AuthVerifyInterceptor implements WebInterceptor<WebAuthVerifyConfig
|
|
|
54
54
|
|
|
55
55
|
finalizeConfig({ config }: WebInterceptorContext<WebAuthVerifyConfig>): WebAuthVerifyConfig {
|
|
56
56
|
config.matcher = Util.allowDeny<string[], [Set<string>]>(config.permissions ?? [],
|
|
57
|
-
|
|
57
|
+
item => item.split('|'),
|
|
58
58
|
matchPermissionSet,
|
|
59
59
|
);
|
|
60
60
|
return config;
|