@toa.io/extensions.exposition 1.0.0-alpha.149 → 1.0.0-alpha.150

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.
Files changed (96) hide show
  1. package/components/identity.bans/operations/tsconfig.tsbuildinfo +1 -1
  2. package/components/identity.basic/operations/tsconfig.tsbuildinfo +1 -1
  3. package/components/identity.federation/manifest.toa.yaml +22 -25
  4. package/components/identity.federation/operations/authenticate.d.ts +6 -4
  5. package/components/identity.federation/operations/authenticate.js +18 -8
  6. package/components/identity.federation/operations/authenticate.js.map +1 -1
  7. package/components/identity.federation/operations/decode.d.ts +3 -2
  8. package/components/identity.federation/operations/decode.js +9 -29
  9. package/components/identity.federation/operations/decode.js.map +1 -1
  10. package/components/identity.federation/operations/incept.d.ts +3 -2
  11. package/components/identity.federation/operations/incept.js +15 -5
  12. package/components/identity.federation/operations/incept.js.map +1 -1
  13. package/components/identity.federation/operations/lib/Configuration.d.ts +39 -0
  14. package/components/identity.federation/operations/lib/Configuration.js +3 -0
  15. package/components/identity.federation/operations/lib/Configuration.js.map +1 -0
  16. package/components/identity.federation/operations/lib/Ctx.d.ts +7 -0
  17. package/components/identity.federation/operations/lib/Ctx.js +3 -0
  18. package/components/identity.federation/operations/lib/Ctx.js.map +1 -0
  19. package/components/identity.federation/operations/lib/Payload.d.ts +5 -0
  20. package/components/identity.federation/operations/lib/Payload.js +3 -0
  21. package/components/identity.federation/operations/lib/Payload.js.map +1 -0
  22. package/components/identity.federation/operations/lib/decode.d.ts +3 -0
  23. package/components/identity.federation/operations/lib/decode.js +59 -0
  24. package/components/identity.federation/operations/lib/decode.js.map +1 -0
  25. package/components/identity.federation/operations/lib/discovery.d.ts +4 -0
  26. package/components/identity.federation/operations/lib/{assertions-as-values.js → discovery.js} +23 -21
  27. package/components/identity.federation/operations/lib/discovery.js.map +1 -0
  28. package/components/identity.federation/operations/lib/errors.d.ts +11 -0
  29. package/components/identity.federation/operations/lib/errors.js +15 -0
  30. package/components/identity.federation/operations/lib/errors.js.map +1 -0
  31. package/components/identity.federation/operations/lib/exchange.d.ts +3 -0
  32. package/components/identity.federation/operations/lib/exchange.js +107 -0
  33. package/components/identity.federation/operations/lib/exchange.js.map +1 -0
  34. package/components/identity.federation/operations/lib/index.d.ts +3 -0
  35. package/components/identity.federation/operations/lib/index.js +8 -0
  36. package/components/identity.federation/operations/lib/index.js.map +1 -0
  37. package/components/identity.federation/operations/tsconfig.tsbuildinfo +1 -1
  38. package/components/identity.federation/operations/types/Scheme.d.ts +1 -0
  39. package/components/identity.federation/operations/types/Scheme.js +3 -0
  40. package/components/identity.federation/operations/types/Scheme.js.map +1 -0
  41. package/components/identity.federation/operations/types/configuration.d.ts +9 -4
  42. package/components/identity.federation/operations/types/context.d.ts +2 -18
  43. package/components/identity.federation/operations/types/index.d.ts +1 -0
  44. package/components/identity.federation/operations/types/index.js +1 -0
  45. package/components/identity.federation/operations/types/index.js.map +1 -1
  46. package/components/identity.federation/source/authenticate.ts +27 -11
  47. package/components/identity.federation/source/decode.ts +9 -7
  48. package/components/identity.federation/source/incept.ts +19 -7
  49. package/components/identity.federation/source/lib/Configuration.ts +39 -0
  50. package/components/identity.federation/source/lib/Ctx.ts +8 -0
  51. package/components/identity.federation/source/lib/Payload.ts +6 -0
  52. package/components/identity.federation/source/lib/decode.ts +48 -0
  53. package/components/identity.federation/source/lib/discovery.ts +30 -0
  54. package/components/identity.federation/source/lib/errors.ts +12 -0
  55. package/components/identity.federation/source/lib/exchange.ts +116 -0
  56. package/components/identity.federation/source/lib/index.ts +3 -0
  57. package/components/identity.federation/source/types/Scheme.ts +1 -0
  58. package/components/identity.federation/source/types/configuration.ts +9 -4
  59. package/components/identity.federation/source/types/context.ts +3 -20
  60. package/components/identity.federation/source/types/index.ts +1 -0
  61. package/components/identity.keys/operations/tsconfig.tsbuildinfo +1 -1
  62. package/components/identity.otp/operations/tsconfig.tsbuildinfo +1 -1
  63. package/components/identity.passkeys/operations/tsconfig.tsbuildinfo +1 -1
  64. package/components/identity.roles/operations/tsconfig.tsbuildinfo +1 -1
  65. package/components/identity.tokens/operations/tsconfig.tsbuildinfo +1 -1
  66. package/documentation/identity.md +41 -2
  67. package/features/auth.claims.feature +0 -1
  68. package/features/authorities.federation.feature +0 -1
  69. package/features/identity.federation.feature +53 -34
  70. package/features/map.feature +1 -2
  71. package/features/steps/{IdP.ts → IDP.ts} +141 -23
  72. package/package.json +10 -12
  73. package/source/HTTP/Server.ts +3 -2
  74. package/source/directives/auth/Authorization.ts +1 -0
  75. package/source/directives/auth/schemes.ts +1 -0
  76. package/source/directives/auth/types.ts +1 -1
  77. package/transpiled/HTTP/Server.js +3 -2
  78. package/transpiled/HTTP/Server.js.map +1 -1
  79. package/transpiled/directives/auth/Authorization.js +1 -0
  80. package/transpiled/directives/auth/Authorization.js.map +1 -1
  81. package/transpiled/directives/auth/schemes.js +1 -0
  82. package/transpiled/directives/auth/schemes.js.map +1 -1
  83. package/transpiled/directives/auth/types.d.ts +1 -1
  84. package/transpiled/tsconfig.tsbuildinfo +1 -1
  85. package/components/identity.federation/operations/lib/assertions-as-values.d.ts +0 -4
  86. package/components/identity.federation/operations/lib/assertions-as-values.js.map +0 -1
  87. package/components/identity.federation/operations/lib/get.d.ts +0 -1
  88. package/components/identity.federation/operations/lib/get.js +0 -64
  89. package/components/identity.federation/operations/lib/get.js.map +0 -1
  90. package/components/identity.federation/operations/lib/jwt.d.ts +0 -20
  91. package/components/identity.federation/operations/lib/jwt.js +0 -152
  92. package/components/identity.federation/operations/lib/jwt.js.map +0 -1
  93. package/components/identity.federation/source/lib/assertions-as-values.ts +0 -22
  94. package/components/identity.federation/source/lib/get.ts +0 -82
  95. package/components/identity.federation/source/lib/jwt.test.ts +0 -179
  96. package/components/identity.federation/source/lib/jwt.ts +0 -198
@@ -1,64 +0,0 @@
1
- "use strict";
2
- /* eslint-disable max-depth */
3
- var __importDefault = (this && this.__importDefault) || function (mod) {
4
- return (mod && mod.__esModule) ? mod : { "default": mod };
5
- };
6
- Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.get = void 0;
8
- const node_stream_1 = require("node:stream");
9
- const consumers_1 = require("node:stream/consumers");
10
- const ttlcache_1 = __importDefault(require("@isaacs/ttlcache"));
11
- const http_cache_semantics_1 = __importDefault(require("http-cache-semantics"));
12
- const cache = new ttlcache_1.default();
13
- async function get(url, init) {
14
- const headers = toRecord(init?.headers);
15
- const request = { url, method: 'GET', headers };
16
- const cached = cache.get(url);
17
- if (cached?.policy.satisfiesWithoutRevalidation(request) === true) {
18
- const headers = toHeaders(cached.policy.responseHeaders());
19
- return new Response(cached.body, { headers });
20
- }
21
- const response = await fetch(url, init);
22
- const policy = new http_cache_semantics_1.default(request, { status: response.status, headers: toRecord(response.headers) });
23
- const ttl = policy.timeToLive();
24
- if (policy.storable() && ttl > 0) {
25
- const body = await toBuffer(response.body);
26
- cache.set(url, { policy, body }, { ttl });
27
- return new Response(body, { headers: response.headers });
28
- }
29
- else
30
- return response;
31
- }
32
- exports.get = get;
33
- function toRecord(headers) {
34
- if (!(headers instanceof Headers))
35
- headers = toHeaders(headers);
36
- return Object.fromEntries(headers.entries());
37
- }
38
- function toHeaders(values) {
39
- const headers = new Headers();
40
- if (values === undefined)
41
- return headers;
42
- if (Array.isArray(values))
43
- for (const [name, value] of values)
44
- headers.append(name, value);
45
- else
46
- for (const name in values) {
47
- const value = values[name];
48
- if (value === undefined)
49
- continue;
50
- if (Array.isArray(value))
51
- for (const v of value)
52
- headers.append(name, v);
53
- else
54
- headers.append(name, value);
55
- }
56
- return headers;
57
- }
58
- async function toBuffer(body) {
59
- if (body === null)
60
- return null;
61
- const buf = await (0, consumers_1.buffer)(node_stream_1.Readable.fromWeb(body));
62
- return Buffer.from(buf);
63
- }
64
- //# sourceMappingURL=get.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"get.js","sourceRoot":"","sources":["../../source/lib/get.ts"],"names":[],"mappings":"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"}
@@ -1,20 +0,0 @@
1
- import type { JwtHeader, IdToken, Trust } from '../types';
2
- import type { Stash } from '@toa.io/types';
3
- export declare function decodeJwt(token: string): {
4
- header: unknown;
5
- payload: unknown;
6
- rawHeader: string;
7
- rawPayload: string;
8
- signature: string;
9
- };
10
- export declare function validateJwtHeader(header: unknown): asserts header is JwtHeader;
11
- export declare function validateJwtPayload(payload: unknown, trusted: Trust[], header: JwtHeader): asserts payload is IdToken;
12
- export declare function validateSignature({ header: { kid, alg }, payload: { iss }, rawHeader, rawPayload, signature, trusted }: {
13
- readonly header: JwtHeader;
14
- rawHeader: string;
15
- readonly payload: IdToken;
16
- rawPayload: string;
17
- signature: string;
18
- trusted?: Trust[];
19
- }): Promise<void>;
20
- export declare function decode(token: string, trusted: Trust[] | undefined, stash: Stash): Promise<IdToken>;
@@ -1,152 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
- var __importDefault = (this && this.__importDefault) || function (mod) {
26
- return (mod && mod.__esModule) ? mod : { "default": mod };
27
- };
28
- Object.defineProperty(exports, "__esModule", { value: true });
29
- exports.decode = exports.validateSignature = exports.validateJwtPayload = exports.validateJwtHeader = exports.decodeJwt = void 0;
30
- const node_crypto_1 = __importDefault(require("node:crypto"));
31
- const assert = __importStar(require("node:assert"));
32
- const get_1 = require("./get");
33
- function decodeJwt(token) {
34
- const [rawHeader, rawPayload, signature] = token.split('.', 3);
35
- const header = JSON.parse(Buffer.from(rawHeader, 'base64url').toString());
36
- const payload = JSON.parse(Buffer.from(rawPayload, 'base64url').toString());
37
- return { header, payload, rawHeader, rawPayload, signature };
38
- }
39
- exports.decodeJwt = decodeJwt;
40
- function validateJwtHeader(header) {
41
- assert.ok(header !== null && typeof header === 'object', 'Header is not an object');
42
- assert.ok('alg' in header, 'Header is missing alg');
43
- assert.ok(typeof header.alg === 'string', 'Header alg is not a string');
44
- assert.match(header.alg, /^RS256|HS\d{3}$/, `Unknown algorithm ${header.alg}`);
45
- assert.ok(!('kid' in header) || typeof header.kid === 'string', 'kid must be a string if present');
46
- }
47
- exports.validateJwtHeader = validateJwtHeader;
48
- function validateJwtPayload(payload, trusted, header) {
49
- assert.ok(trusted.length > 0, 'No trusted issuers provided');
50
- // the full list of validations is
51
- // at https://openid.net/specs/openid-connect-core-1_0.html#IDTokenValidation
52
- assert.ok(payload !== null && typeof payload === 'object', 'Payload is not an object');
53
- assert.ok('iss' in payload, 'Payload is missing iss');
54
- assert.ok(typeof payload.iss === 'string', 'Payload iss is not a string');
55
- assert.ok('aud' in payload, 'Payload is missing aud');
56
- assert.ok(typeof payload.aud === 'string' ||
57
- (Array.isArray(payload.aud) && payload.aud.every((e) => typeof e === 'string')), 'Payload aud is not a string nor an array of strings');
58
- const issuer = trusted.find((config) => config.iss === payload.iss);
59
- assert.ok(issuer, `Unknown issuer: ${payload.iss}`);
60
- if (Array.isArray(issuer.aud)) {
61
- const tokenAud = payload.aud;
62
- if (typeof tokenAud === 'string')
63
- assert.ok(issuer.aud.some((a) => a === tokenAud), `Unknown audience: ${tokenAud}`);
64
- else
65
- assert.ok(issuer.aud.some((a) => tokenAud.includes(a)), `Unknown audiences: ${tokenAud.join(', ')}`);
66
- }
67
- if (header.alg.startsWith('HS')) {
68
- const secrets = issuer.secrets;
69
- assert.ok(secrets, `We don't have known secrets for ${payload.iss}`);
70
- const keys = secrets[header.alg];
71
- assert.ok(keys, `No known secrets for ${header.alg}`);
72
- if (typeof header.kid === 'string')
73
- assert.ok(header.kid in keys, `No secret ${header.kid} provided for ${header.alg}`);
74
- }
75
- assert.ok('sub' in payload, 'Payload is missing sub');
76
- assert.ok(typeof payload.sub === 'string', 'Payload sub is not a string');
77
- assert.ok('exp' in payload, 'Payload is missing exp');
78
- assert.ok(typeof payload.exp === 'number', 'Payload exp is not a number');
79
- assert.ok(Date.now() < payload.exp * 1000, 'Token is expired');
80
- assert.ok('iat' in payload, 'Payload is missing iat');
81
- assert.ok(typeof payload.iat === 'number', 'Payload iat is not a number');
82
- assert.ok(Date.now() >= payload.iat * 1000, 'Token was issued in the future');
83
- assert.ok(payload.exp >= payload.iat, 'Payload exp is before iat');
84
- if ('nbf' in payload) {
85
- assert.ok(typeof payload.nbf === 'number', 'Payload nbf is not a number');
86
- assert.ok(Date.now() >= payload.nbf * 1000, 'Token is not valid yet');
87
- }
88
- if ('jti' in payload)
89
- assert.ok(typeof payload.jti === 'string', 'Payload jti is not a string');
90
- }
91
- exports.validateJwtPayload = validateJwtPayload;
92
- async function validateSignature({ header: { kid, alg }, payload: { iss }, rawHeader, rawPayload, signature, trusted = [] }) {
93
- if (alg.startsWith('HS')) {
94
- // symmetric algorithm, issuer is validated at this point
95
- const secrets = trusted.find((c) => c.iss === iss).secrets[alg];
96
- const secret = kid !== undefined ? secrets[kid] : Object.values(secrets)[0];
97
- const algorithm = alg.replace(/^HS(\d{3})$/, 'sha$1'); // HS256 -> sha256
98
- const hmac = node_crypto_1.default.createHmac(algorithm, secret);
99
- hmac.update(rawHeader);
100
- hmac.update('.');
101
- hmac.update(rawPayload);
102
- assert.strictEqual(signature, hmac.digest('base64url'), 'Signature does not match');
103
- return;
104
- }
105
- // Getting issuer public keys
106
- const oidcRequest = await (0, get_1.get)(new URL('/.well-known/openid-configuration', iss).href);
107
- assert.ok(oidcRequest.ok, `Failed to fetch OpenID configuration: ${oidcRequest.statusText}`);
108
- const { jwks_uri: jwksUri } = (await oidcRequest.json());
109
- const jwkRequest = await (0, get_1.get)(jwksUri);
110
- assert.ok(jwkRequest.ok, `Failed to fetch issuer keys: ${jwkRequest.statusText}`);
111
- const { keys } = (await jwkRequest.json());
112
- // getting the corresponding signing key
113
- const signingKeys = keys.filter((k) => k.use === 'sig' && k.alg === alg);
114
- assert.ok(signingKeys.length > 0, 'No acceptable signing keys found');
115
- assert.ok(kid !== undefined || signingKeys.length === 1, 'Signing key selection is not deterministic');
116
- const signingKey = kid === undefined ? keys[0] : signingKeys.find((k) => k.kid === kid);
117
- assert.ok(signingKey, 'Signing key was not found in issuer keys');
118
- const verifyFunction = node_crypto_1.default.createVerify('RSA-SHA256');
119
- verifyFunction.write(rawHeader);
120
- verifyFunction.write('.');
121
- verifyFunction.write(rawPayload);
122
- verifyFunction.end();
123
- const signatureValid = verifyFunction.verify({ format: 'jwk', key: signingKey }, signature, 'base64url');
124
- assert.ok(signatureValid, 'Failed to validate signature');
125
- }
126
- exports.validateSignature = validateSignature;
127
- async function validateJti(token, stash) {
128
- const key = `identity:federation:jti:${token.jti}`;
129
- const used = await stash.exists(key);
130
- assert.ok(used === 0, 'Token has already been used');
131
- const ttl = token.exp - Math.floor(Date.now() / 1000);
132
- await stash.set(key, '1', 'EX', ttl);
133
- }
134
- async function decode(token, trusted, stash) {
135
- assert.ok(trusted !== undefined, 'No trusted issuers provided');
136
- const { header, payload, rawHeader, rawPayload, signature } = decodeJwt(token);
137
- validateJwtHeader(header);
138
- validateJwtPayload(payload, trusted, header);
139
- if (payload.jti !== undefined)
140
- await validateJti(payload, stash);
141
- await validateSignature({
142
- header,
143
- rawHeader,
144
- payload,
145
- rawPayload,
146
- signature,
147
- trusted
148
- });
149
- return payload;
150
- }
151
- exports.decode = decode;
152
- //# sourceMappingURL=jwt.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../source/lib/jwt.ts"],"names":[],"mappings":"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"}
@@ -1,22 +0,0 @@
1
- import * as assert from 'node:assert'
2
- import { console } from 'openspan'
3
-
4
- /**
5
- * Wrapping function that returns assertion errors as function return value
6
- */
7
- export function assertionsAsValues<T extends (...args: any[]) => Promise<any>> (
8
- fn: T) {
9
- return async (...args: Parameters<T>): Promise<ReturnType<T> | Error> => {
10
- try {
11
- return await fn(...args)
12
- } catch (err) {
13
- if (err instanceof assert.AssertionError) {
14
- console.error('OIDC Authentication exception', { message: err.message })
15
-
16
- return err
17
- }
18
-
19
- throw err
20
- }
21
- }
22
- }
@@ -1,82 +0,0 @@
1
- /* eslint-disable max-depth */
2
-
3
- import { Readable } from 'node:stream'
4
- import { buffer } from 'node:stream/consumers'
5
-
6
- import Cache from '@isaacs/ttlcache'
7
- import Policy from 'http-cache-semantics'
8
- import type { ReadableStream } from 'node:stream/web'
9
-
10
- const cache = new Cache<string, Entry>()
11
-
12
- export async function get (url: string, init?: RequestInit): Promise<Response> {
13
- const headers = toRecord(init?.headers)
14
- const request = { url, method: 'GET', headers }
15
- const cached = cache.get(url)
16
-
17
- if (cached?.policy.satisfiesWithoutRevalidation(request) === true) {
18
- const headers = toHeaders(cached.policy.responseHeaders())
19
-
20
- return new Response(cached.body, { headers })
21
- }
22
-
23
- const response = await fetch(url, init)
24
- const policy = new Policy(request, { status: response.status, headers: toRecord(response.headers) })
25
- const ttl = policy.timeToLive()
26
-
27
- if (policy.storable() && ttl > 0) {
28
- const body = await toBuffer(response.body as ReadableStream)
29
-
30
- cache.set(url, { policy, body }, { ttl })
31
-
32
- return new Response(body, { headers: response.headers })
33
- } else
34
- return response
35
- }
36
-
37
- function toRecord (headers: RequestInit['headers']): Record<string, string> {
38
- if (!(headers instanceof Headers))
39
- headers = toHeaders(headers)
40
-
41
- return Object.fromEntries(headers.entries())
42
- }
43
-
44
- function toHeaders (values?: Array<[string, string]> | Record<string, string | string[] | undefined>): Headers {
45
- const headers = new Headers()
46
-
47
- if (values === undefined)
48
- return headers
49
-
50
- if (Array.isArray(values))
51
- for (const [name, value] of values)
52
- headers.append(name, value)
53
- else
54
- for (const name in values) {
55
- const value = values[name]
56
-
57
- if (value === undefined)
58
- continue
59
-
60
- if (Array.isArray(value))
61
- for (const v of value)
62
- headers.append(name, v)
63
- else
64
- headers.append(name, value)
65
- }
66
-
67
- return headers
68
- }
69
-
70
- async function toBuffer (body: ReadableStream<Uint8Array> | null): Promise<Buffer | null> {
71
- if (body === null)
72
- return null
73
-
74
- const buf = await buffer(Readable.fromWeb(body as ReadableStream))
75
-
76
- return Buffer.from(buf)
77
- }
78
-
79
- interface Entry {
80
- policy: Policy
81
- body: Buffer | null
82
- }
@@ -1,179 +0,0 @@
1
- import * as http from 'node:http'
2
-
3
- /* eslint-disable @typescript-eslint/consistent-type-assertions */
4
- import { once } from 'node:events'
5
- import { validateSignature, decodeJwt, validateJwtPayload } from './jwt'
6
- import { get } from './get'
7
- import type { AddressInfo } from 'node:net'
8
- import type { IdToken, JwtHeader, Trust } from '../types'
9
-
10
- describe('jwt', () => {
11
- describe('validateJwtPayload', () => {
12
- const jwtHeader: JwtHeader = { alg: 'HS256', kid: 'k1' }
13
-
14
- const trusted: Trust[] = [{
15
- iss: 'test-iss',
16
- aud: ['test-aud1', 'test-aud2'],
17
- secrets: { [jwtHeader.alg]: { [jwtHeader.kid!]: 'test-secrete' } }
18
- }]
19
-
20
- const validJwtPayload: IdToken = {
21
- iss: trusted[0].iss,
22
- sub: 'test-sub',
23
- iat: Date.now() / 1000,
24
- exp: Date.now() / 1000 + 2000,
25
- aud: trusted[0].aud![1]
26
- }
27
-
28
- describe('aud', () => {
29
- test('throws without it', () => {
30
- const { aud, ...noAudPayload } = validJwtPayload
31
-
32
- expect(() => validateJwtPayload(noAudPayload, trusted, jwtHeader)).toThrow('Payload is missing aud')
33
- })
34
-
35
- test('passes with a single string', () => {
36
- expect(validJwtPayload.aud).toEqual(expect.any(String))
37
- expect(() => validateJwtPayload(validJwtPayload, trusted, jwtHeader)).not.toThrow()
38
- })
39
-
40
- test('passes with an array', () => {
41
- const arrayAudPayload = { ...validJwtPayload, aud: trusted[0].aud }
42
-
43
- expect(arrayAudPayload.aud).toEqual(expect.any(Array))
44
- expect(() => validateJwtPayload(arrayAudPayload, trusted, jwtHeader)).not.toThrow()
45
- })
46
-
47
- test('throws with an array that does not intersects', () => {
48
- const arrayAudPayload = { ...validJwtPayload, aud: ['boo', 'foo'] }
49
-
50
- expect(arrayAudPayload.aud).toEqual(expect.any(Array))
51
- expect(() => validateJwtPayload(arrayAudPayload, trusted, jwtHeader))
52
- .toThrow('Unknown audiences: boo, foo')
53
- })
54
- })
55
- })
56
-
57
- test('decode', () => {
58
- const { header, payload } = decodeJwt('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzb21lIjoicGF5bG9hZCJ9.4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg')
59
-
60
- expect(header).toMatchObject({ alg: 'HS256' })
61
- expect(payload).toEqual({ some: 'payload' })
62
- })
63
-
64
- test('symmetric pass', async () => {
65
- // example from
66
- // https://pyjwt.readthedocs.io/en/latest/usage.html#encoding-decoding-tokens-with-hs256
67
-
68
- await expect(validateSignature({
69
- header: { alg: 'HS256', kid: 'k2' },
70
- payload: { iss: 'test-issuer', aud: 'test', sub: '0', exp: 0, iat: 0 },
71
- rawHeader: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9',
72
- rawPayload: 'eyJzb21lIjoicGF5bG9hZCJ9',
73
- signature: '4twFt5NiznN84AWoo1d7KO1T_yoc0Z6XOpOVswacPZg',
74
- trusted: [
75
- {
76
- iss: 'test-issuer',
77
- secrets: {
78
- HS256: {
79
- k1: 'old-secret',
80
- k2: 'secret'
81
- }
82
- }
83
- }
84
- ]
85
- } as Parameters<typeof validateSignature>[0])).resolves.toBeUndefined()
86
- })
87
-
88
- test('symmetric fail', async () => {
89
- await expect(validateSignature({
90
- header: { alg: 'HS256' },
91
- payload: { iss: 'test-issuer', aud: 'test', sub: '0', exp: 0, iat: 0 },
92
- rawHeader: 'header',
93
- rawPayload: 'payload',
94
- signature: 'signature',
95
- trusted: [
96
- {
97
- iss: 'test-issuer',
98
- secrets: {
99
- HS256: {
100
- theKey: 'secret'
101
- }
102
- }
103
- }
104
- ]
105
- } as Parameters<typeof validateSignature>[0])).rejects.toThrow('Signature does not match')
106
- })
107
-
108
- describe('cache', () => {
109
- let server: http.Server
110
- // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
111
- const handler = jest.fn<void, [http.IncomingMessage, http.ServerResponse]>()
112
- let endpoint: string
113
-
114
- beforeAll(async () => {
115
- server = http.createServer(handler)
116
-
117
- server.listen(0, 'localhost')
118
- await once(server, 'listening')
119
-
120
- const { port } = server.address() as AddressInfo
121
-
122
- endpoint = `http://localhost:${port}`
123
- })
124
-
125
- afterEach(() => {
126
- handler.mockReset()
127
- })
128
-
129
- afterAll(async () => {
130
- server.close()
131
- await once(server, 'close')
132
- })
133
-
134
- test('fetches only once', async () => {
135
- handler.mockImplementationOnce((req, res) => {
136
- res.writeHead(200, { 'content-type': 'application/json', 'cache-control': 'public, max-age=3600' })
137
- res.end(JSON.stringify({ foo: 'bar' }))
138
- }).mockImplementationOnce((req, res) => {
139
- res.writeHead(500)
140
- res.end()
141
- })
142
-
143
- const firstRequest = await get(endpoint)
144
-
145
- expect(firstRequest.ok).toBe(true)
146
-
147
- const json = await firstRequest.json()
148
-
149
- expect(json).toEqual({ foo: 'bar' })
150
-
151
- const secondRequest = await get(endpoint)
152
-
153
- expect(secondRequest.ok).toBe(true)
154
- await expect(secondRequest.json()).resolves.toEqual({ foo: 'bar' })
155
-
156
- expect(handler).toHaveBeenCalledTimes(1)
157
- })
158
-
159
- test('respects caching headers', async () => {
160
- handler.mockImplementation((req, res) => {
161
- res.writeHead(200, { 'content-type': 'application/json', 'cache-control': 'no-cache' })
162
- res.end(JSON.stringify({ foo: 'bar' }))
163
- })
164
-
165
- const firstRequest = await get(endpoint + '/no-cache')
166
-
167
- expect(firstRequest.headers.get('cache-control')).toBe('no-cache')
168
- expect(firstRequest.ok).toBe(true)
169
- await expect(firstRequest.json()).resolves.toEqual({ foo: 'bar' })
170
-
171
- const secondRequest = await get(endpoint + '/no-cache')
172
-
173
- expect(secondRequest.ok).toBe(true)
174
- await expect(secondRequest.json()).resolves.toEqual({ foo: 'bar' })
175
-
176
- expect(handler).toHaveBeenCalledTimes(2)
177
- })
178
- })
179
- })