@carecard/jwt-read 3.9.0 → 3.11.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/.agents/skills/carecard-workspace-standards/SKILL.md +9 -5
- package/.agents/skills/github-pr-create-update/SKILL.md +17 -7
- package/.agents/skills/github-pr-merge-cleanup/SKILL.md +40 -10
- package/.agents/skills/pkg-jwt-read-jwt-middleware-library/SKILL.md +7 -0
- package/.agents/skills/pkg-publish/SKILL.md +4 -0
- package/.agents/skills/software-design-patterns-and-clean-code/SKILL.md +4 -0
- package/lib/jwtLib.js +31 -25
- package/package.json +4 -4
- package/readme.md +8 -0
|
@@ -7,6 +7,10 @@ description: 'Follow the shared SO_CareCardCa/CareCard workspace coding, testing
|
|
|
7
7
|
|
|
8
8
|
Non-negotiable TDD rule: Always write the failing test first, run it to confirm it fails for the intended reason, then implement the code and rerun the test until it passes. Test Driven Development is required for all coding work and must not be skipped. For documentation- or skill-only edits, add or update the relevant validation check before changing the prose.
|
|
9
9
|
|
|
10
|
+
Non-negotiable repository isolation rule: Every repository must run its Husky hooks and tests using only files, code, fixtures, dependencies, and services contained within that repository. Tests and Husky scripts must not import, require, read, execute, or otherwise depend on sibling repositories or paths outside the repository root. app-e2e-tests is the only exception because cross-repository end-to-end testing is its explicit responsibility.
|
|
11
|
+
|
|
12
|
+
Non-negotiable error and warning rule: Never suppress, silence, hide, downgrade, filter, ignore, skip, or bypass errors or warnings from code, tests, tools, compilers, linters, or validation. Fix the root cause, then rerun the affected check and require a clean result. Expected error-path tests may assert errors, but must not conceal unexpected failures.
|
|
13
|
+
|
|
10
14
|
Non-negotiable code organization rule: Functions with the same or equivalent behavior must use the same or clearly corresponding descriptive names across CareCard repositories, and equivalent functionality must live in files with the same names within each repository's established architecture. No backward compatibility names, aliases, or duplicate locations are allowed.
|
|
11
15
|
|
|
12
16
|
## Purpose
|
|
@@ -83,7 +87,7 @@ config.
|
|
|
83
87
|
- Never suppress errors, TypeScript errors, linter warnings, authorization
|
|
84
88
|
failures, RLS failures, build failures, hydration issues, or failing tests.
|
|
85
89
|
Do not add `eslint-disable`, `@ts-ignore`, broad catches, empty catches, or
|
|
86
|
-
similar suppression
|
|
90
|
+
similar suppression. Fix the root cause.
|
|
87
91
|
- Do not add dependencies unless clearly necessary. If one might be needed, ask
|
|
88
92
|
first with the reason, tradeoff, and why existing code cannot solve it.
|
|
89
93
|
- Before finalizing repository work, run the affected repository's relevant
|
|
@@ -212,8 +216,8 @@ build artifacts, logs, or `.DS_Store`.
|
|
|
212
216
|
|
|
213
217
|
Most JavaScript `ms-*` services use CommonJS, Mocha, Supertest, Docker Compose
|
|
214
218
|
database tests, `@carecard/*` packages, and `sub-apps`
|
|
215
|
-
controller/router/model patterns. TypeScript services such as `ms-
|
|
216
|
-
|
|
219
|
+
controller/router/model patterns. TypeScript services such as `ms-messages`
|
|
220
|
+
use Jest or TypeScript tooling and should keep their
|
|
217
221
|
existing TypeScript style.
|
|
218
222
|
|
|
219
223
|
- Keep environment-specific files explicit: `.env.development`, `.env.test`,
|
|
@@ -311,7 +315,7 @@ existing TypeScript style.
|
|
|
311
315
|
|
|
312
316
|
`app-dashboard` is a Next.js App Router TypeScript app using MUI, React Query,
|
|
313
317
|
`next-intl`, and shared CareCard utilities. It consumes `ms-auth`,
|
|
314
|
-
`ms-institutions`, `ms-
|
|
318
|
+
`ms-institutions`, `ms-messages`, and `ms-user-profiles` through service
|
|
315
319
|
modules.
|
|
316
320
|
|
|
317
321
|
- Keep backend URL definitions centralized in `src/services/api.routes.ts`.
|
|
@@ -378,7 +382,7 @@ the authenticated dashboard.
|
|
|
378
382
|
|
|
379
383
|
## Auth Service RLS Contract
|
|
380
384
|
|
|
381
|
-
- `ms-auth` follows the shared PostgreSQL/RLS pattern
|
|
385
|
+
- `ms-auth` follows the shared PostgreSQL/RLS pattern: auth tables live in the `carecard` schema, RLS is enabled and forced on every auth table, and application runtime queries use the unprivileged database role.
|
|
382
386
|
- Auth table policies allow normal JWT or server-auth users to access only
|
|
383
387
|
self-owned rows. Do not add redundant `user_id = <jwt sub>` SQL predicates to
|
|
384
388
|
duplicate self-row checks when RLS owns the authorization decision.
|
|
@@ -7,6 +7,10 @@ description: 'Use only when the user explicitly asks for remote Git or GitHub PR
|
|
|
7
7
|
|
|
8
8
|
Non-negotiable TDD rule: Always write the failing test first, run it to confirm it fails for the intended reason, then implement the code and rerun the test until it passes. Test Driven Development is required for all coding work and must not be skipped. For documentation- or skill-only edits, add or update the relevant validation check before changing the prose.
|
|
9
9
|
|
|
10
|
+
Non-negotiable repository isolation rule: Every repository must run its Husky hooks and tests using only files, code, fixtures, dependencies, and services contained within that repository. Tests and Husky scripts must not import, require, read, execute, or otherwise depend on sibling repositories or paths outside the repository root. app-e2e-tests is the only exception because cross-repository end-to-end testing is its explicit responsibility.
|
|
11
|
+
|
|
12
|
+
Non-negotiable error and warning rule: Never suppress, silence, hide, downgrade, filter, ignore, skip, or bypass errors or warnings from code, tests, tools, compilers, linters, or validation. Fix the root cause, then rerun the affected check and require a clean result. Expected error-path tests may assert errors, but must not conceal unexpected failures.
|
|
13
|
+
|
|
10
14
|
Non-negotiable code organization rule: Functions with the same or equivalent behavior must use the same or clearly corresponding descriptive names across CareCard repositories, and equivalent functionality must live in files with the same names within each repository's established architecture. No backward compatibility names, aliases, or duplicate locations are allowed.
|
|
11
15
|
|
|
12
16
|
## Purpose
|
|
@@ -75,14 +79,20 @@ Do not continue automatically when:
|
|
|
75
79
|
when `origin/development` is absent:
|
|
76
80
|
|
|
77
81
|
```sh
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
base
|
|
82
|
-
|
|
83
|
-
echo "No origin/development or origin/main branch exists."
|
|
84
|
-
exit 1
|
|
82
|
+
remote_base_refs="$(git ls-remote --heads origin development main)"
|
|
83
|
+
remote_query_status=$?
|
|
84
|
+
if [ "$remote_query_status" -ne 0 ]; then
|
|
85
|
+
printf 'Unable to inspect origin base branches (exit %s).\n' "$remote_query_status" >&2
|
|
86
|
+
exit "$remote_query_status"
|
|
85
87
|
fi
|
|
88
|
+
case "$remote_base_refs" in
|
|
89
|
+
*"refs/heads/development") base="development" ;;
|
|
90
|
+
*"refs/heads/main") base="main" ;;
|
|
91
|
+
*)
|
|
92
|
+
printf '%s\n' "No origin/development or origin/main branch exists." >&2
|
|
93
|
+
exit 1
|
|
94
|
+
;;
|
|
95
|
+
esac
|
|
86
96
|
git fetch origin "$base" --prune
|
|
87
97
|
```
|
|
88
98
|
|
|
@@ -7,6 +7,10 @@ description: 'Use only when the user explicitly asks for remote Git or GitHub PR
|
|
|
7
7
|
|
|
8
8
|
Non-negotiable TDD rule: Always write the failing test first, run it to confirm it fails for the intended reason, then implement the code and rerun the test until it passes. Test Driven Development is required for all coding work and must not be skipped. For documentation- or skill-only edits, add or update the relevant validation check before changing the prose.
|
|
9
9
|
|
|
10
|
+
Non-negotiable repository isolation rule: Every repository must run its Husky hooks and tests using only files, code, fixtures, dependencies, and services contained within that repository. Tests and Husky scripts must not import, require, read, execute, or otherwise depend on sibling repositories or paths outside the repository root. app-e2e-tests is the only exception because cross-repository end-to-end testing is its explicit responsibility.
|
|
11
|
+
|
|
12
|
+
Non-negotiable error and warning rule: Never suppress, silence, hide, downgrade, filter, ignore, skip, or bypass errors or warnings from code, tests, tools, compilers, linters, or validation. Fix the root cause, then rerun the affected check and require a clean result. Expected error-path tests may assert errors, but must not conceal unexpected failures.
|
|
13
|
+
|
|
10
14
|
Non-negotiable code organization rule: Functions with the same or equivalent behavior must use the same or clearly corresponding descriptive names across CareCard repositories, and equivalent functionality must live in files with the same names within each repository's established architecture. No backward compatibility names, aliases, or duplicate locations are allowed.
|
|
11
15
|
|
|
12
16
|
## Purpose
|
|
@@ -72,14 +76,20 @@ completion.
|
|
|
72
76
|
|
|
73
77
|
```sh
|
|
74
78
|
gh auth status
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
base
|
|
79
|
-
|
|
80
|
-
echo "No origin/development or origin/main branch exists."
|
|
81
|
-
exit 1
|
|
79
|
+
remote_base_refs="$(git ls-remote --heads origin development main)"
|
|
80
|
+
remote_query_status=$?
|
|
81
|
+
if [ "$remote_query_status" -ne 0 ]; then
|
|
82
|
+
printf 'Unable to inspect origin base branches (exit %s).\n' "$remote_query_status" >&2
|
|
83
|
+
exit "$remote_query_status"
|
|
82
84
|
fi
|
|
85
|
+
case "$remote_base_refs" in
|
|
86
|
+
*"refs/heads/development") base="development" ;;
|
|
87
|
+
*"refs/heads/main") base="main" ;;
|
|
88
|
+
*)
|
|
89
|
+
printf '%s\n' "No origin/development or origin/main branch exists." >&2
|
|
90
|
+
exit 1
|
|
91
|
+
;;
|
|
92
|
+
esac
|
|
83
93
|
target_branch="$(git branch --show-current)"
|
|
84
94
|
test -n "$target_branch"
|
|
85
95
|
test "$target_branch" != "$base"
|
|
@@ -169,7 +179,19 @@ completion.
|
|
|
169
179
|
not protected:
|
|
170
180
|
|
|
171
181
|
```sh
|
|
172
|
-
protected="$(gh api "repos/{owner}/{repo}/branches/$target_branch" --jq '.protected'
|
|
182
|
+
protected="$(gh api "repos/{owner}/{repo}/branches/$target_branch" --jq '.protected')"
|
|
183
|
+
protection_query_status=$?
|
|
184
|
+
if [ "$protection_query_status" -ne 0 ]; then
|
|
185
|
+
printf 'Unable to inspect branch protection (exit %s).\n' "$protection_query_status" >&2
|
|
186
|
+
exit "$protection_query_status"
|
|
187
|
+
fi
|
|
188
|
+
case "$protected" in
|
|
189
|
+
true|false) ;;
|
|
190
|
+
*)
|
|
191
|
+
printf 'Unexpected branch protection value: %s\n' "$protected" >&2
|
|
192
|
+
exit 1
|
|
193
|
+
;;
|
|
194
|
+
esac
|
|
173
195
|
if [ "$protected" = true ]; then
|
|
174
196
|
gh pr merge "$pr_number" --squash --admin
|
|
175
197
|
else
|
|
@@ -181,8 +203,16 @@ completion.
|
|
|
181
203
|
delete it explicitly:
|
|
182
204
|
|
|
183
205
|
```sh
|
|
184
|
-
if [ "$protected" != true ]
|
|
185
|
-
git
|
|
206
|
+
if [ "$protected" != true ]; then
|
|
207
|
+
remote_target_ref="$(git ls-remote --heads origin "$target_branch")"
|
|
208
|
+
remote_query_status=$?
|
|
209
|
+
if [ "$remote_query_status" -ne 0 ]; then
|
|
210
|
+
printf 'Unable to inspect the remote target branch (exit %s).\n' "$remote_query_status" >&2
|
|
211
|
+
exit "$remote_query_status"
|
|
212
|
+
fi
|
|
213
|
+
if [ -n "$remote_target_ref" ]; then
|
|
214
|
+
git push origin --delete "$target_branch"
|
|
215
|
+
fi
|
|
186
216
|
fi
|
|
187
217
|
```
|
|
188
218
|
|
|
@@ -7,6 +7,10 @@ description: 'Use when changing pkg-jwt-read JWT parsing, middleware, visitor to
|
|
|
7
7
|
|
|
8
8
|
Non-negotiable TDD rule: Always write the failing test first, run it to confirm it fails for the intended reason, then implement the code and rerun the test until it passes. Test Driven Development is required for all coding work and must not be skipped. For documentation- or skill-only edits, add or update the relevant validation check before changing the prose.
|
|
9
9
|
|
|
10
|
+
Non-negotiable repository isolation rule: Every repository must run its Husky hooks and tests using only files, code, fixtures, dependencies, and services contained within that repository. Tests and Husky scripts must not import, require, read, execute, or otherwise depend on sibling repositories or paths outside the repository root. app-e2e-tests is the only exception because cross-repository end-to-end testing is its explicit responsibility.
|
|
11
|
+
|
|
12
|
+
Non-negotiable error and warning rule: Never suppress, silence, hide, downgrade, filter, ignore, skip, or bypass errors or warnings from code, tests, tools, compilers, linters, or validation. Fix the root cause, then rerun the affected check and require a clean result. Expected error-path tests may assert errors, but must not conceal unexpected failures.
|
|
13
|
+
|
|
10
14
|
Non-negotiable code organization rule: Functions with the same or equivalent behavior must use the same or clearly corresponding descriptive names across CareCard repositories, and equivalent functionality must live in files with the same names within each repository's established architecture. No backward compatibility names, aliases, or duplicate locations are allowed.
|
|
11
15
|
|
|
12
16
|
## Purpose
|
|
@@ -118,6 +122,9 @@ depend on those folders being present.
|
|
|
118
122
|
- Server-auth request attachment behavior that normalizes introspected claims
|
|
119
123
|
into `req.jwt.payload` with `authMode: "server-auth"` and
|
|
120
124
|
`auth_mode: "server-auth"`.
|
|
125
|
+
- Server-auth email confirmation claims are copied only when present. The
|
|
126
|
+
`emailVerified`, `email_verified`, `emailConfirmed`, and `email_confirmed`
|
|
127
|
+
aliases retain their exact names and values, and omission remains omission.
|
|
121
128
|
- Integration with `@carecard/common-util` for standardized login and
|
|
122
129
|
authorization errors.
|
|
123
130
|
|
|
@@ -7,6 +7,10 @@ description: 'Use when any pkg-* repository has non-Markdown package changes, in
|
|
|
7
7
|
|
|
8
8
|
Non-negotiable TDD rule: Always write the failing test first, run it to confirm it fails for the intended reason, then implement the code and rerun the test until it passes. Test Driven Development is required for all coding work and must not be skipped. For documentation- or skill-only edits, add or update the relevant validation check before changing the prose.
|
|
9
9
|
|
|
10
|
+
Non-negotiable repository isolation rule: Every repository must run its Husky hooks and tests using only files, code, fixtures, dependencies, and services contained within that repository. Tests and Husky scripts must not import, require, read, execute, or otherwise depend on sibling repositories or paths outside the repository root. app-e2e-tests is the only exception because cross-repository end-to-end testing is its explicit responsibility.
|
|
11
|
+
|
|
12
|
+
Non-negotiable error and warning rule: Never suppress, silence, hide, downgrade, filter, ignore, skip, or bypass errors or warnings from code, tests, tools, compilers, linters, or validation. Fix the root cause, then rerun the affected check and require a clean result. Expected error-path tests may assert errors, but must not conceal unexpected failures.
|
|
13
|
+
|
|
10
14
|
Non-negotiable code organization rule: Functions with the same or equivalent behavior must use the same or clearly corresponding descriptive names across CareCard repositories, and equivalent functionality must live in files with the same names within each repository's established architecture. No backward compatibility names, aliases, or duplicate locations are allowed.
|
|
11
15
|
|
|
12
16
|
## Trigger
|
|
@@ -7,6 +7,10 @@ description: 'Use every time before coding, refactoring, debugging, or reviewing
|
|
|
7
7
|
|
|
8
8
|
Non-negotiable TDD rule: Always write the failing test first, run it to confirm it fails for the intended reason, then implement the code and rerun the test until it passes. Test Driven Development is required for all coding work and must not be skipped. For documentation- or skill-only edits, add or update the relevant validation check before changing the prose.
|
|
9
9
|
|
|
10
|
+
Non-negotiable repository isolation rule: Every repository must run its Husky hooks and tests using only files, code, fixtures, dependencies, and services contained within that repository. Tests and Husky scripts must not import, require, read, execute, or otherwise depend on sibling repositories or paths outside the repository root. app-e2e-tests is the only exception because cross-repository end-to-end testing is its explicit responsibility.
|
|
11
|
+
|
|
12
|
+
Non-negotiable error and warning rule: Never suppress, silence, hide, downgrade, filter, ignore, skip, or bypass errors or warnings from code, tests, tools, compilers, linters, or validation. Fix the root cause, then rerun the affected check and require a clean result. Expected error-path tests may assert errors, but must not conceal unexpected failures.
|
|
13
|
+
|
|
10
14
|
Non-negotiable code organization rule: Functions with the same or equivalent behavior must use the same or clearly corresponding descriptive names across CareCard repositories, and equivalent functionality must live in files with the same names within each repository's established architecture. No backward compatibility names, aliases, or duplicate locations are allowed.
|
|
11
15
|
|
|
12
16
|
## Purpose
|
package/lib/jwtLib.js
CHANGED
|
@@ -5,6 +5,7 @@ const { throwLoginRequiredError, throwNotAuthorizedError } = require('@carecard/
|
|
|
5
5
|
|
|
6
6
|
const DEFAULT_USER_AUTHORIZATION_HEADER_NAME = 'X-Authorization-Context';
|
|
7
7
|
const DEFAULT_USER_AUTHORIZATION_MAX_TOKEN_LENGTH = 2048;
|
|
8
|
+
const EMAIL_CONFIRMATION_CLAIM_NAMES = ['emailVerified', 'email_verified', 'emailConfirmed', 'email_confirmed'];
|
|
8
9
|
|
|
9
10
|
function jwtClientId(req) {
|
|
10
11
|
const jwtObj = req?.jwt || this;
|
|
@@ -33,7 +34,15 @@ function doesJwtUserHasRole(req, userRole) {
|
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
function throwError(customErrorFunction) {
|
|
36
|
-
typeof customErrorFunction
|
|
37
|
+
if (typeof customErrorFunction !== 'function') {
|
|
38
|
+
return throwLoginRequiredError();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const customError = customErrorFunction();
|
|
42
|
+
|
|
43
|
+
if (customError instanceof Error) throw customError;
|
|
44
|
+
|
|
45
|
+
throw new Error('Custom authentication error function returned without throwing');
|
|
37
46
|
}
|
|
38
47
|
|
|
39
48
|
function isJwtExpired(req, jwtValiditySeconds) {
|
|
@@ -122,15 +131,11 @@ function validateAndExtractServiceJwtObject(req, publicKey, expectedIssuer, expe
|
|
|
122
131
|
if (jwtString && isJwtSignatureValid) {
|
|
123
132
|
_extractJwtObject(req, jwtString, customErrorFunction);
|
|
124
133
|
} else {
|
|
125
|
-
|
|
126
|
-
if (req) {
|
|
127
|
-
req.jwt = null;
|
|
128
|
-
}
|
|
134
|
+
req.jwt = null;
|
|
129
135
|
}
|
|
130
136
|
|
|
131
137
|
if (!req?.jwt || !_isServiceJwtFor(req.jwt.payload, expectedIssuer, expectedAudience)) {
|
|
132
|
-
|
|
133
|
-
if (req) req.jwt = null;
|
|
138
|
+
req.jwt = null;
|
|
134
139
|
throwError(customErrorFunction);
|
|
135
140
|
}
|
|
136
141
|
|
|
@@ -336,16 +341,14 @@ function validateAndExtractOptionalUserAuthorizationObject(req, options, customE
|
|
|
336
341
|
|
|
337
342
|
const header = readUserAuthorizationHeader(req, config);
|
|
338
343
|
if (!header.present) {
|
|
339
|
-
|
|
340
|
-
if (req) req.userAuthorization = null;
|
|
344
|
+
req.userAuthorization = null;
|
|
341
345
|
return req;
|
|
342
346
|
}
|
|
343
347
|
|
|
344
348
|
if (isUserAuthorizationTokenAllowed(header.token, config)) {
|
|
345
349
|
_extractUserAuthorizationObjectNoThrow(req, header.token);
|
|
346
350
|
} else {
|
|
347
|
-
|
|
348
|
-
if (req) req.userAuthorization = null;
|
|
351
|
+
req.userAuthorization = null;
|
|
349
352
|
throwError(customErrorFunction);
|
|
350
353
|
}
|
|
351
354
|
|
|
@@ -361,10 +364,7 @@ function validateAndExtractOptionalUserAuthorizationObjectNoThrow(req, options)
|
|
|
361
364
|
if (header.present && isUserAuthorizationTokenAllowed(header.token, config)) {
|
|
362
365
|
_extractUserAuthorizationObjectNoThrow(req, header.token);
|
|
363
366
|
} else {
|
|
364
|
-
|
|
365
|
-
if (req) {
|
|
366
|
-
req.userAuthorization = null;
|
|
367
|
-
}
|
|
367
|
+
req.userAuthorization = null;
|
|
368
368
|
}
|
|
369
369
|
|
|
370
370
|
return req;
|
|
@@ -389,8 +389,7 @@ function tryValidateAndExtractJwtObject(req, publicKey) {
|
|
|
389
389
|
|
|
390
390
|
const isJwtSignatureValid = jwtVerifySignedToken(jwtString, publicKey);
|
|
391
391
|
if (!isJwtSignatureValid) {
|
|
392
|
-
|
|
393
|
-
if (req) req.jwt = null;
|
|
392
|
+
req.jwt = null;
|
|
394
393
|
return false;
|
|
395
394
|
}
|
|
396
395
|
|
|
@@ -437,11 +436,22 @@ function attachServerAuthClaims(req, claims, customErrorFunction) {
|
|
|
437
436
|
_attachJwtMethods(req.jwt);
|
|
438
437
|
}
|
|
439
438
|
|
|
439
|
+
// Pattern: Projection - copies only authoritative confirmation aliases and preserves their exact values.
|
|
440
|
+
function pickEmailConfirmationClaims(claims) {
|
|
441
|
+
return Object.fromEntries(
|
|
442
|
+
EMAIL_CONFIRMATION_CLAIM_NAMES.filter(claimName => Object.prototype.hasOwnProperty.call(claims, claimName)).map(claimName => [
|
|
443
|
+
claimName,
|
|
444
|
+
claims[claimName],
|
|
445
|
+
]),
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// Pattern: Mapper - attaches server-auth metadata while preserving authoritative confirmation claims.
|
|
440
450
|
function createServerAuthPayload(claims) {
|
|
441
451
|
return {
|
|
442
452
|
sub: claims.sub || claims.userId || claims.user_id,
|
|
443
453
|
email: claims.email || '',
|
|
444
|
-
|
|
454
|
+
...pickEmailConfirmationClaims(claims),
|
|
445
455
|
roles: Array.isArray(claims.roles) ? claims.roles : [],
|
|
446
456
|
authMode: 'server-auth',
|
|
447
457
|
auth_mode: 'server-auth',
|
|
@@ -557,7 +567,7 @@ function getRequestHeader(req, headerName) {
|
|
|
557
567
|
function isUserAuthorizationTokenAllowed(token, config) {
|
|
558
568
|
if (!token || !config.publicKey || !jwtVerifySignedToken(token, config.publicKey)) return false;
|
|
559
569
|
|
|
560
|
-
const payload =
|
|
570
|
+
const payload = readVerifiedJwtPayload(token);
|
|
561
571
|
if (!payload) return false;
|
|
562
572
|
if (isJwtPayloadIssuedInFuture(payload)) return false;
|
|
563
573
|
if (isJwtPayloadExpired(payload)) return false;
|
|
@@ -570,12 +580,8 @@ function isUserAuthorizationTokenAllowed(token, config) {
|
|
|
570
580
|
}
|
|
571
581
|
|
|
572
582
|
// Pattern: Pure Function - decodes payload defensively after signature and shape checks.
|
|
573
|
-
function
|
|
574
|
-
|
|
575
|
-
return jwtGetHeaderPayload(token)?.payload || null;
|
|
576
|
-
} catch {
|
|
577
|
-
return null;
|
|
578
|
-
}
|
|
583
|
+
function readVerifiedJwtPayload(token) {
|
|
584
|
+
return jwtGetHeaderPayload(token)?.payload || null;
|
|
579
585
|
}
|
|
580
586
|
|
|
581
587
|
// Pattern: Pure Function - supports either one expected audience or a small allowed set.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@carecard/jwt-read",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.11.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/CareCard-ca/pkg-jwt-read.git"
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
"typescript": "6.0.3"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@carecard/auth-util": "3.
|
|
45
|
-
"@carecard/common-util": "3.
|
|
46
|
-
"@carecard/validate": "3.
|
|
44
|
+
"@carecard/auth-util": "3.11.0",
|
|
45
|
+
"@carecard/common-util": "3.11.0",
|
|
46
|
+
"@carecard/validate": "3.11.0"
|
|
47
47
|
},
|
|
48
48
|
"overrides": {
|
|
49
49
|
"diff": "8.0.4",
|
package/readme.md
CHANGED
|
@@ -12,6 +12,10 @@ introspected by `ms-auth`.
|
|
|
12
12
|
|
|
13
13
|
Non-negotiable TDD rule: Always write the failing test first, run it to confirm it fails for the intended reason, then implement the code and rerun the test until it passes. Test Driven Development is required for all coding work and must not be skipped. For documentation- or skill-only edits, add or update the relevant validation check before changing the prose.
|
|
14
14
|
|
|
15
|
+
Non-negotiable repository isolation rule: Every repository must run its Husky hooks and tests using only files, code, fixtures, dependencies, and services contained within that repository. Tests and Husky scripts must not import, require, read, execute, or otherwise depend on sibling repositories or paths outside the repository root. app-e2e-tests is the only exception because cross-repository end-to-end testing is its explicit responsibility.
|
|
16
|
+
|
|
17
|
+
Non-negotiable error and warning rule: Never suppress, silence, hide, downgrade, filter, ignore, skip, or bypass errors or warnings from code, tests, tools, compilers, linters, or validation. Fix the root cause, then rerun the affected check and require a clean result. Expected error-path tests may assert errors, but must not conceal unexpected failures.
|
|
18
|
+
|
|
15
19
|
Non-negotiable code organization rule: Functions with the same or equivalent behavior must use the same or clearly corresponding descriptive names across CareCard repositories, and equivalent functionality must live in files with the same names within each repository's established architecture. No backward compatibility names, aliases, or duplicate locations are allowed.
|
|
16
20
|
|
|
17
21
|
## Features
|
|
@@ -142,6 +146,10 @@ those claims onto `req.jwt.payload` with `authMode: "server-auth"` and
|
|
|
142
146
|
`auth_mode: "server-auth"` so services can keep their existing JWT-backed
|
|
143
147
|
database context and role checks.
|
|
144
148
|
|
|
149
|
+
Server-auth email confirmation claims are copied only when present. The
|
|
150
|
+
`emailVerified`, `email_verified`, `emailConfirmed`, and `email_confirmed`
|
|
151
|
+
aliases retain their exact names and values, and omission remains omission.
|
|
152
|
+
|
|
145
153
|
### Scoped User Authorization Context
|
|
146
154
|
|
|
147
155
|
Use `jwtVerifyUserAuthorization` when a route needs to verify only the compact
|