oidc-spa 8.6.19 → 8.7.1
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/backend.d.ts +3 -20
- package/backend.js +50 -242
- package/backend.js.map +1 -1
- package/core/OidcMetadata.d.ts +2 -2
- package/core/OidcMetadata.js.map +1 -1
- package/core/createOidc.d.ts +2 -4
- package/core/createOidc.js +49 -3
- package/core/createOidc.js.map +1 -1
- package/core/dpop.d.ts +20 -0
- package/core/dpop.js +389 -0
- package/core/dpop.js.map +1 -0
- package/core/earlyInit.js +2 -0
- package/core/earlyInit.js.map +1 -1
- package/core/oidcClientTsUserToTokens.d.ts +1 -0
- package/core/oidcClientTsUserToTokens.js +15 -5
- package/core/oidcClientTsUserToTokens.js.map +1 -1
- package/core/tokenExfiltrationDefense.js +49 -6
- package/core/tokenExfiltrationDefense.js.map +1 -1
- package/esm/angular.d.ts +2 -0
- package/esm/angular.mjs.map +1 -1
- package/esm/backend.d.ts +3 -20
- package/esm/backend.mjs +50 -242
- package/esm/backend.mjs.map +1 -1
- package/esm/core/OidcMetadata.d.ts +2 -2
- package/esm/core/OidcMetadata.mjs.map +1 -1
- package/esm/core/createOidc.d.ts +2 -4
- package/esm/core/createOidc.mjs +49 -3
- package/esm/core/createOidc.mjs.map +1 -1
- package/esm/core/dpop.d.ts +20 -0
- package/esm/core/dpop.mjs +384 -0
- package/esm/core/dpop.mjs.map +1 -0
- package/esm/core/earlyInit.mjs +2 -0
- package/esm/core/earlyInit.mjs.map +1 -1
- package/esm/core/oidcClientTsUserToTokens.d.ts +1 -0
- package/esm/core/oidcClientTsUserToTokens.mjs +15 -5
- package/esm/core/oidcClientTsUserToTokens.mjs.map +1 -1
- package/esm/core/tokenExfiltrationDefense.mjs +49 -6
- package/esm/core/tokenExfiltrationDefense.mjs.map +1 -1
- package/esm/react-spa/createOidcSpaApi.mjs +2 -1
- package/esm/react-spa/createOidcSpaApi.mjs.map +1 -1
- package/esm/react-spa/types.d.ts +2 -0
- package/esm/server/createOidcSpaUtils.d.ts +5 -0
- package/esm/server/createOidcSpaUtils.mjs +639 -0
- package/esm/server/createOidcSpaUtils.mjs.map +1 -0
- package/esm/server/index.d.ts +2 -0
- package/esm/server/index.mjs +3 -0
- package/esm/server/index.mjs.map +1 -0
- package/esm/server/types.d.ts +79 -0
- package/esm/server/types.mjs +2 -0
- package/esm/server/types.mjs.map +1 -0
- package/esm/server/utilsBuilder.d.ts +10 -0
- package/esm/server/utilsBuilder.mjs +13 -0
- package/esm/server/utilsBuilder.mjs.map +1 -0
- package/esm/tanstack-start/react/accessTokenValidation_rfc9068.d.ts +1 -1
- package/esm/tanstack-start/react/accessTokenValidation_rfc9068.mjs +102 -94
- package/esm/tanstack-start/react/accessTokenValidation_rfc9068.mjs.map +1 -1
- package/esm/tanstack-start/react/createOidcSpaApi.d.ts +2 -2
- package/esm/tanstack-start/react/createOidcSpaApi.mjs +60 -51
- package/esm/tanstack-start/react/createOidcSpaApi.mjs.map +1 -1
- package/esm/tanstack-start/react/index.d.ts +1 -1
- package/esm/tanstack-start/react/index.mjs +2 -2
- package/esm/tanstack-start/react/index.mjs.map +1 -1
- package/esm/tanstack-start/react/types.d.ts +36 -11
- package/esm/tanstack-start/react/{apiBuilder.d.ts → utilsBuilder.d.ts} +9 -9
- package/esm/tanstack-start/react/{apiBuilder.mjs → utilsBuilder.mjs} +6 -6
- package/esm/tanstack-start/react/utilsBuilder.mjs.map +1 -0
- package/esm/tools/generateES256DPoPProof.d.ts +8 -0
- package/esm/tools/generateES256DPoPProof.mjs +48 -0
- package/esm/tools/generateES256DPoPProof.mjs.map +1 -0
- package/esm/tools/getServerDateNow.d.ts +5 -0
- package/esm/tools/getServerDateNow.mjs +7 -0
- package/esm/tools/getServerDateNow.mjs.map +1 -0
- package/esm/vendor/{backend → server}/evt.mjs +84 -140
- package/esm/vendor/{backend → server}/jose.mjs +5 -27
- package/esm/vendor/{backend → server}/tsafe.d.ts +1 -0
- package/esm/vendor/{backend → server}/tsafe.mjs +6 -0
- package/esm/vendor/{backend → server}/zod.mjs +196 -50
- package/package.json +6 -1
- package/react-spa/createOidcSpaApi.js +2 -1
- package/react-spa/createOidcSpaApi.js.map +1 -1
- package/react-spa/types.d.ts +2 -0
- package/server/createOidcSpaUtils.d.ts +5 -0
- package/server/createOidcSpaUtils.js +642 -0
- package/server/createOidcSpaUtils.js.map +1 -0
- package/server/index.d.ts +2 -0
- package/server/index.js +6 -0
- package/server/index.js.map +1 -0
- package/server/types.d.ts +79 -0
- package/server/types.js +3 -0
- package/server/types.js.map +1 -0
- package/server/utilsBuilder.d.ts +10 -0
- package/server/utilsBuilder.js +16 -0
- package/server/utilsBuilder.js.map +1 -0
- package/src/angular.ts +3 -0
- package/src/backend.ts +63 -364
- package/src/core/OidcMetadata.ts +4 -2
- package/src/core/createOidc.ts +62 -6
- package/src/core/dpop.ts +583 -0
- package/src/core/earlyInit.ts +3 -0
- package/src/core/oidcClientTsUserToTokens.ts +18 -4
- package/src/core/tokenExfiltrationDefense.ts +60 -5
- package/src/react-spa/createOidcSpaApi.ts +2 -1
- package/src/react-spa/types.tsx +3 -0
- package/src/server/createOidcSpaUtils.ts +848 -0
- package/src/server/index.ts +4 -0
- package/src/server/types.tsx +99 -0
- package/src/server/utilsBuilder.ts +41 -0
- package/src/tanstack-start/react/accessTokenValidation_rfc9068.ts +134 -124
- package/src/tanstack-start/react/createOidcSpaApi.ts +73 -69
- package/src/tanstack-start/react/index.ts +2 -2
- package/src/tanstack-start/react/types.tsx +44 -12
- package/src/tanstack-start/react/{apiBuilder.ts → utilsBuilder.ts} +14 -14
- package/src/tools/generateES256DPoPProof.ts +74 -0
- package/src/tools/getServerDateNow.ts +11 -0
- package/src/vendor/{backend → server}/tsafe.ts +1 -0
- package/tools/generateES256DPoPProof.d.ts +8 -0
- package/tools/generateES256DPoPProof.js +51 -0
- package/tools/generateES256DPoPProof.js.map +1 -0
- package/tools/getServerDateNow.d.ts +5 -0
- package/tools/getServerDateNow.js +10 -0
- package/tools/getServerDateNow.js.map +1 -0
- package/vendor/server/evt.js +3 -0
- package/vendor/server/jose.js +3 -0
- package/vendor/{backend → server}/tsafe.d.ts +1 -0
- package/vendor/server/tsafe.js +2 -0
- package/vendor/server/zod.js +3 -0
- package/esm/tanstack-start/react/apiBuilder.mjs.map +0 -1
- package/vendor/backend/evt.js +0 -3
- package/vendor/backend/jose.js +0 -3
- package/vendor/backend/tsafe.js +0 -2
- package/vendor/backend/zod.js +0 -3
- /package/esm/vendor/{backend → server}/evt.d.ts +0 -0
- /package/esm/vendor/{backend → server}/jose.d.ts +0 -0
- /package/esm/vendor/{backend → server}/zod.d.ts +0 -0
- /package/src/vendor/{backend → server}/evt.ts +0 -0
- /package/src/vendor/{backend → server}/jose.ts +0 -0
- /package/src/vendor/{backend → server}/zod.ts +0 -0
- /package/vendor/{backend → server}/evt.d.ts +0 -0
- /package/vendor/{backend → server}/jose.d.ts +0 -0
- /package/vendor/{backend → server}/zod.d.ts +0 -0
package/backend.d.ts
CHANGED
|
@@ -1,24 +1,6 @@
|
|
|
1
1
|
import type { ZodSchemaLike } from "./tools/ZodSchemaLike";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* https://datatracker.ietf.org/doc/html/rfc9068
|
|
5
|
-
*
|
|
6
|
-
* These tokens are intended for consumption by resource servers.
|
|
7
|
-
*/
|
|
8
|
-
export type DecodedAccessToken_RFC9068 = {
|
|
9
|
-
iss: string;
|
|
10
|
-
sub: string;
|
|
11
|
-
aud: string | string[];
|
|
12
|
-
exp: number;
|
|
13
|
-
iat: number;
|
|
14
|
-
client_id?: string;
|
|
15
|
-
scope?: string;
|
|
16
|
-
jti?: string;
|
|
17
|
-
nbf?: number;
|
|
18
|
-
auth_time?: number;
|
|
19
|
-
cnf?: Record<string, unknown>;
|
|
20
|
-
[key: string]: unknown;
|
|
21
|
-
};
|
|
2
|
+
import { DecodedAccessToken_RFC9068 } from "./server/types";
|
|
3
|
+
export type { DecodedAccessToken_RFC9068 };
|
|
22
4
|
export type ParamsOfCreateOidcBackend<DecodedAccessToken> = {
|
|
23
5
|
issuerUri: string;
|
|
24
6
|
decodedAccessTokenSchema?: ZodSchemaLike<DecodedAccessToken_RFC9068, DecodedAccessToken>;
|
|
@@ -45,4 +27,5 @@ export declare namespace ResultOfAccessTokenVerify {
|
|
|
45
27
|
decodedAccessToken_original?: never;
|
|
46
28
|
};
|
|
47
29
|
}
|
|
30
|
+
/** @deprecated: Use "oidc-spa/server" instead */
|
|
48
31
|
export declare function createOidcBackend<DecodedAccessToken extends Record<string, unknown> = DecodedAccessToken_RFC9068>(params: ParamsOfCreateOidcBackend<DecodedAccessToken>): Promise<OidcBackend<DecodedAccessToken>>;
|
package/backend.js
CHANGED
|
@@ -1,262 +1,70 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createOidcBackend = createOidcBackend;
|
|
4
|
-
const tsafe_1 = require("./vendor/
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
const evt_1 = require("./vendor/backend/evt");
|
|
8
|
-
const zDecodedAccessToken_RFC9068 = (() => {
|
|
9
|
-
const zTargetType = zod_1.z
|
|
10
|
-
.object({
|
|
11
|
-
iss: zod_1.z.string(),
|
|
12
|
-
sub: zod_1.z.string(),
|
|
13
|
-
aud: zod_1.z.union([zod_1.z.string(), zod_1.z.array(zod_1.z.string())]),
|
|
14
|
-
exp: zod_1.z.number(),
|
|
15
|
-
iat: zod_1.z.number(),
|
|
16
|
-
client_id: zod_1.z.string().optional(),
|
|
17
|
-
scope: zod_1.z.string().optional(),
|
|
18
|
-
jti: zod_1.z.string().optional(),
|
|
19
|
-
nbf: zod_1.z.number().optional(),
|
|
20
|
-
auth_time: zod_1.z.number().optional(),
|
|
21
|
-
cnf: zod_1.z.record(zod_1.z.unknown()).optional()
|
|
22
|
-
})
|
|
23
|
-
.catchall(zod_1.z.unknown());
|
|
24
|
-
tsafe_1.assert;
|
|
25
|
-
return (0, tsafe_1.id)(zTargetType);
|
|
26
|
-
})();
|
|
4
|
+
const tsafe_1 = require("./vendor/server/tsafe");
|
|
5
|
+
const server_1 = require("./server");
|
|
6
|
+
/** @deprecated: Use "oidc-spa/server" instead */
|
|
27
7
|
async function createOidcBackend(params) {
|
|
28
8
|
const { issuerUri, decodedAccessTokenSchema } = params;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
catch (error) {
|
|
38
|
-
if (count === 9) {
|
|
39
|
-
console.warn(`Failed to refresh public key and signing algorithm after ${count + 1} attempts`);
|
|
40
|
-
return undefined;
|
|
41
|
-
}
|
|
42
|
-
const delayMs = 1000 * Math.pow(2, count);
|
|
43
|
-
console.warn(`Failed to refresh public key and signing algorithm: ${String(error)}, retrying in ${delayMs}ms`);
|
|
44
|
-
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
45
|
-
return callee(count + 1);
|
|
46
|
-
}
|
|
47
|
-
return wrap;
|
|
48
|
-
})(0);
|
|
49
|
-
if (publicSigningKeys_new === undefined) {
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
publicSigningKeys = publicSigningKeys_new;
|
|
9
|
+
const { bootstrapAuth, validateAndDecodeAccessToken } = decodedAccessTokenSchema === undefined
|
|
10
|
+
? server_1.oidcSpa.createUtils()
|
|
11
|
+
: server_1.oidcSpa.withExpectedDecodedAccessTokenShape({ decodedAccessTokenSchema }).createUtils();
|
|
12
|
+
await bootstrapAuth({
|
|
13
|
+
implementation: "real",
|
|
14
|
+
issuerUri,
|
|
15
|
+
expectedAudience: undefined
|
|
53
16
|
});
|
|
54
17
|
return {
|
|
55
18
|
verifyAndDecodeAccessToken: async ({ accessToken }) => {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
return {
|
|
65
|
-
isValid: false,
|
|
66
|
-
errorCase: "invalid signature",
|
|
67
|
-
errorMessage: "Failed to decode the JWT header"
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
const { kid: kidFromHeader, alg: algFromHeader } = header;
|
|
71
|
-
if (typeof kidFromHeader !== "string" || kidFromHeader.length === 0) {
|
|
72
|
-
return {
|
|
73
|
-
isValid: false,
|
|
74
|
-
errorCase: "invalid signature",
|
|
75
|
-
errorMessage: "The decoded JWT header does not have a kid property"
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
if (typeof algFromHeader !== "string") {
|
|
79
|
-
return {
|
|
80
|
-
isValid: false,
|
|
81
|
-
errorCase: "invalid signature",
|
|
82
|
-
errorMessage: "The decoded JWT header does not specify an algorithm"
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
const supportedAlgs = [
|
|
86
|
-
"RS256",
|
|
87
|
-
"RS384",
|
|
88
|
-
"RS512",
|
|
89
|
-
"ES256",
|
|
90
|
-
"ES384",
|
|
91
|
-
"ES512",
|
|
92
|
-
"PS256",
|
|
93
|
-
"PS384",
|
|
94
|
-
"PS512"
|
|
95
|
-
];
|
|
96
|
-
if (!(0, tsafe_1.isAmong)(supportedAlgs, algFromHeader)) {
|
|
97
|
-
return {
|
|
98
|
-
isValid: false,
|
|
99
|
-
errorCase: "invalid signature",
|
|
100
|
-
errorMessage: `Unsupported or too weak algorithm ${algFromHeader}`
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
kid = kidFromHeader;
|
|
104
|
-
alg = algFromHeader;
|
|
105
|
-
}
|
|
106
|
-
if (!publicSigningKeys.kidSet.has(kid)) {
|
|
107
|
-
return {
|
|
108
|
-
isValid: false,
|
|
109
|
-
errorCase: "invalid signature",
|
|
110
|
-
errorMessage: `No public signing key found with kid ${kid}`
|
|
111
|
-
};
|
|
112
|
-
}
|
|
113
|
-
let payload;
|
|
114
|
-
try {
|
|
115
|
-
const verification = await (0, jose_1.jwtVerify)(accessToken, publicSigningKeys.keyResolver, {
|
|
116
|
-
algorithms: [alg]
|
|
117
|
-
});
|
|
118
|
-
payload = verification.payload;
|
|
119
|
-
}
|
|
120
|
-
catch (error) {
|
|
121
|
-
if (error instanceof jose_1.errors.JWTExpired) {
|
|
122
|
-
return (0, tsafe_1.id)({
|
|
123
|
-
isValid: false,
|
|
124
|
-
errorCase: "expired",
|
|
125
|
-
errorMessage: error.message
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
evtInvalidSignature.post();
|
|
129
|
-
return (0, tsafe_1.id)({
|
|
130
|
-
isValid: false,
|
|
131
|
-
errorCase: "invalid signature",
|
|
132
|
-
errorMessage: error instanceof Error ? error.message : String(error)
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
const decodedAccessToken_unknown = payload;
|
|
136
|
-
try {
|
|
137
|
-
zDecodedAccessToken_RFC9068.parse(decodedAccessToken_unknown);
|
|
138
|
-
}
|
|
139
|
-
catch (error) {
|
|
140
|
-
return (0, tsafe_1.id)({
|
|
141
|
-
isValid: false,
|
|
142
|
-
errorCase: "does not respect schema",
|
|
143
|
-
errorMessage: [
|
|
144
|
-
`The decoded access token does not satisfies`,
|
|
145
|
-
`the shape mandated by RFC9068: ${String(error)}`
|
|
146
|
-
].join(" ")
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
(0, tsafe_1.assert)((0, tsafe_1.is)(decodedAccessToken_unknown));
|
|
150
|
-
const decodedAccessToken_original = decodedAccessToken_unknown;
|
|
151
|
-
let decodedAccessToken;
|
|
152
|
-
if (decodedAccessTokenSchema === undefined) {
|
|
153
|
-
decodedAccessToken = decodedAccessToken_original;
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
try {
|
|
157
|
-
decodedAccessToken = decodedAccessTokenSchema.parse(decodedAccessToken_original);
|
|
19
|
+
const { isSuccess, errorCause, debugErrorMessage, decodedAccessToken, decodedAccessToken_original } = await validateAndDecodeAccessToken({
|
|
20
|
+
request: {
|
|
21
|
+
method: "GET",
|
|
22
|
+
url: "https://dummy.com",
|
|
23
|
+
headers: {
|
|
24
|
+
Authorization: `Bearer ${accessToken}`,
|
|
25
|
+
DPoP: undefined
|
|
26
|
+
}
|
|
158
27
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
28
|
+
});
|
|
29
|
+
if (!isSuccess) {
|
|
30
|
+
switch (errorCause) {
|
|
31
|
+
case "missing Authorization header":
|
|
32
|
+
(0, tsafe_1.assert)(false, "29330204");
|
|
33
|
+
case "validation error":
|
|
34
|
+
if (debugErrorMessage.includes("shape") ||
|
|
35
|
+
debugErrorMessage.includes("schema")) {
|
|
36
|
+
return {
|
|
37
|
+
isValid: false,
|
|
38
|
+
errorCase: "does not respect schema",
|
|
39
|
+
errorMessage: debugErrorMessage
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
isValid: false,
|
|
44
|
+
errorCase: "invalid signature",
|
|
45
|
+
errorMessage: debugErrorMessage
|
|
46
|
+
};
|
|
47
|
+
case "validation error - access token expired":
|
|
48
|
+
return {
|
|
49
|
+
isValid: false,
|
|
50
|
+
errorCase: "expired",
|
|
51
|
+
errorMessage: debugErrorMessage
|
|
52
|
+
};
|
|
53
|
+
case "validation error - invalid signature":
|
|
54
|
+
return {
|
|
55
|
+
isValid: false,
|
|
56
|
+
errorCase: "invalid signature",
|
|
57
|
+
errorMessage: debugErrorMessage
|
|
58
|
+
};
|
|
165
59
|
}
|
|
166
60
|
}
|
|
167
61
|
return (0, tsafe_1.id)({
|
|
168
62
|
isValid: true,
|
|
63
|
+
// @ts-expect-error
|
|
169
64
|
decodedAccessToken,
|
|
170
65
|
decodedAccessToken_original
|
|
171
66
|
});
|
|
172
67
|
}
|
|
173
68
|
};
|
|
174
69
|
}
|
|
175
|
-
async function fetchPublicSigningKeys(params) {
|
|
176
|
-
const { issuerUri } = params;
|
|
177
|
-
const { jwks_uri } = await (async () => {
|
|
178
|
-
const url = `${issuerUri.replace(/\/$/, "")}/.well-known/openid-configuration`;
|
|
179
|
-
const response = await fetch(url);
|
|
180
|
-
if (!response.ok) {
|
|
181
|
-
throw new Error(`Failed to fetch openid configuration of the issuerUri: ${issuerUri} (${url}): ${response.statusText}`);
|
|
182
|
-
}
|
|
183
|
-
let data;
|
|
184
|
-
try {
|
|
185
|
-
data = await response.json();
|
|
186
|
-
}
|
|
187
|
-
catch (error) {
|
|
188
|
-
throw new Error(`Failed to parse json from ${url}: ${String(error)}`);
|
|
189
|
-
}
|
|
190
|
-
{
|
|
191
|
-
const zWellKnownConfiguration = zod_1.z.object({
|
|
192
|
-
jwks_uri: zod_1.z.string()
|
|
193
|
-
});
|
|
194
|
-
(0, tsafe_1.assert)();
|
|
195
|
-
try {
|
|
196
|
-
zWellKnownConfiguration.parse(data);
|
|
197
|
-
}
|
|
198
|
-
catch {
|
|
199
|
-
throw new Error(`${url} does not have a jwks_uri property`);
|
|
200
|
-
}
|
|
201
|
-
(0, tsafe_1.assert)((0, tsafe_1.is)(data));
|
|
202
|
-
}
|
|
203
|
-
const { jwks_uri } = data;
|
|
204
|
-
return { jwks_uri };
|
|
205
|
-
})();
|
|
206
|
-
const { jwks } = await (async () => {
|
|
207
|
-
const response = await fetch(jwks_uri);
|
|
208
|
-
if (!response.ok) {
|
|
209
|
-
throw new Error(`Failed to fetch public key and algorithm from ${jwks_uri}: ${response.statusText}`);
|
|
210
|
-
}
|
|
211
|
-
let jwks;
|
|
212
|
-
try {
|
|
213
|
-
jwks = await response.json();
|
|
214
|
-
}
|
|
215
|
-
catch (error) {
|
|
216
|
-
throw new Error(`Failed to parse json from ${jwks_uri}: ${String(error)}`);
|
|
217
|
-
}
|
|
218
|
-
{
|
|
219
|
-
const zJwks = zod_1.z.object({
|
|
220
|
-
keys: zod_1.z.array(zod_1.z.object({
|
|
221
|
-
kid: zod_1.z.string(),
|
|
222
|
-
kty: zod_1.z.string(),
|
|
223
|
-
use: zod_1.z.string().optional(),
|
|
224
|
-
alg: zod_1.z.string().optional()
|
|
225
|
-
}))
|
|
226
|
-
});
|
|
227
|
-
(0, tsafe_1.assert)();
|
|
228
|
-
try {
|
|
229
|
-
zJwks.parse(jwks);
|
|
230
|
-
}
|
|
231
|
-
catch {
|
|
232
|
-
throw new Error(`${jwks_uri} does not have the expected shape`);
|
|
233
|
-
}
|
|
234
|
-
(0, tsafe_1.assert)((0, tsafe_1.is)(jwks));
|
|
235
|
-
}
|
|
236
|
-
return { jwks };
|
|
237
|
-
})();
|
|
238
|
-
//const signatureKeys = jwks.keys.filter((key): key is JWKS["keys"][number] & { kid: string } => {
|
|
239
|
-
const signatureKeys = jwks.keys.filter(key => {
|
|
240
|
-
if (typeof key.kid !== "string" || key.kid.length === 0) {
|
|
241
|
-
return false;
|
|
242
|
-
}
|
|
243
|
-
if (key.use !== undefined && key.use !== "sig") {
|
|
244
|
-
return false;
|
|
245
|
-
}
|
|
246
|
-
const supportedKty = ["RSA", "EC"];
|
|
247
|
-
if (!supportedKty.includes(key.kty)) {
|
|
248
|
-
return false;
|
|
249
|
-
}
|
|
250
|
-
return true;
|
|
251
|
-
});
|
|
252
|
-
(0, tsafe_1.assert)(signatureKeys.length !== 0, `No public signing key found at ${jwks_uri}, ${JSON.stringify(jwks, null, 2)}`);
|
|
253
|
-
const kidSet = new Set(signatureKeys.map(({ kid }) => kid));
|
|
254
|
-
const keyResolver = (0, jose_1.createLocalJWKSet)({
|
|
255
|
-
keys: signatureKeys
|
|
256
|
-
});
|
|
257
|
-
return {
|
|
258
|
-
keyResolver,
|
|
259
|
-
kidSet
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
70
|
//# sourceMappingURL=backend.js.map
|
package/backend.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backend.js","sourceRoot":"","sources":["./src/backend.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"backend.js","sourceRoot":"","sources":["./src/backend.ts"],"names":[],"mappings":";;AA4CA,8CAgFC;AA5HD,iDAAmD;AAGnD,qCAAmC;AAwCnC,iDAAiD;AAC1C,KAAK,UAAU,iBAAiB,CAErC,MAAqD;IACnD,MAAM,EAAE,SAAS,EAAE,wBAAwB,EAAE,GAAG,MAAM,CAAC;IAEvD,MAAM,EAAE,aAAa,EAAE,4BAA4B,EAAE,GACjD,wBAAwB,KAAK,SAAS;QAClC,CAAC,CAAC,gBAAO,CAAC,WAAW,EAAE;QACvB,CAAC,CAAC,gBAAO,CAAC,mCAAmC,CAAC,EAAE,wBAAwB,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IAElG,MAAM,aAAa,CAAC;QAChB,cAAc,EAAE,MAAM;QACtB,SAAS;QACT,gBAAgB,EAAE,SAAS;KAC9B,CAAC,CAAC;IAEH,OAAO;QACH,0BAA0B,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,EAAE,EAAE;YAClD,MAAM,EACF,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,kBAAkB,EAClB,2BAA2B,EAC9B,GAAG,MAAM,4BAA4B,CAAC;gBACnC,OAAO,EAAE;oBACL,MAAM,EAAE,KAAK;oBACb,GAAG,EAAE,mBAAmB;oBACxB,OAAO,EAAE;wBACL,aAAa,EAAE,UAAU,WAAW,EAAE;wBACtC,IAAI,EAAE,SAAS;qBAClB;iBACJ;aACJ,CAAC,CAAC;YAEH,IAAI,CAAC,SAAS,EAAE,CAAC;gBACb,QAAQ,UAAU,EAAE,CAAC;oBACjB,KAAK,8BAA8B;wBAC/B,IAAA,cAAM,EAAC,KAAK,EAAE,UAAU,CAAC,CAAC;oBAC9B,KAAK,kBAAkB;wBACnB,IACI,iBAAiB,CAAC,QAAQ,CAAC,OAAO,CAAC;4BACnC,iBAAiB,CAAC,QAAQ,CAAC,QAAQ,CAAC,EACtC,CAAC;4BACC,OAAO;gCACH,OAAO,EAAE,KAAK;gCACd,SAAS,EAAE,yBAAyB;gCACpC,YAAY,EAAE,iBAAiB;6BAClC,CAAC;wBACN,CAAC;wBAED,OAAO;4BACH,OAAO,EAAE,KAAK;4BACd,SAAS,EAAE,mBAAmB;4BAC9B,YAAY,EAAE,iBAAiB;yBAClC,CAAC;oBAEN,KAAK,yCAAyC;wBAC1C,OAAO;4BACH,OAAO,EAAE,KAAK;4BACd,SAAS,EAAE,SAAS;4BACpB,YAAY,EAAE,iBAAiB;yBAClC,CAAC;oBACN,KAAK,sCAAsC;wBACvC,OAAO;4BACH,OAAO,EAAE,KAAK;4BACd,SAAS,EAAE,mBAAmB;4BAC9B,YAAY,EAAE,iBAAiB;yBAClC,CAAC;gBACV,CAAC;YACL,CAAC;YAED,OAAO,IAAA,UAAE,EAAsD;gBAC3D,OAAO,EAAE,IAAI;gBACb,mBAAmB;gBACnB,kBAAkB;gBAClB,2BAA2B;aAC9B,CAAC,CAAC;QACP,CAAC;KACJ,CAAC;AACN,CAAC"}
|
package/core/OidcMetadata.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { type OidcMetadata as OidcClientTsOidcMetadata } from "../vendor/frontend/oidc-client-ts";
|
|
2
1
|
/**
|
|
3
2
|
* OpenID Providers have metadata describing their configuration.
|
|
4
3
|
*
|
|
@@ -264,8 +263,9 @@ export type OidcMetadata = {
|
|
|
264
263
|
* @see https://datatracker.ietf.org/doc/html/rfc8414
|
|
265
264
|
*/
|
|
266
265
|
code_challenge_methods_supported: string[];
|
|
266
|
+
dpop_signing_alg_values_supported: string[];
|
|
267
267
|
};
|
|
268
268
|
export declare const WELL_KNOWN_PATH = "/.well-known/openid-configuration";
|
|
269
269
|
export declare function fetchOidcMetadata(params: {
|
|
270
270
|
issuerUri: string;
|
|
271
|
-
}): Promise<Partial<
|
|
271
|
+
}): Promise<Partial<OidcMetadata> | undefined>;
|
package/core/OidcMetadata.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OidcMetadata.js","sourceRoot":"","sources":["../src/core/OidcMetadata.ts"],"names":[],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"OidcMetadata.js","sourceRoot":"","sources":["../src/core/OidcMetadata.ts"],"names":[],"mappings":";;;AA6SA,8CA8CC;AA1VD,kDAA4D;AAC5D,kEAAkE;AA+QlE,eAAiG,CAAC;AAErF,QAAA,eAAe,GAAG,mCAAmC,CAAC;AAEnE,SAAS,oBAAoB,CAAC,MAA6B;IACvD,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC;IAE7B,OAAO,iCAAiC,SAAS,EAAE,CAAC;AACxD,CAAC;AAED,SAAS,kBAAkB,CAAC,MAA6B;IACrD,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC;IAE7B,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;IAE1E,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACjB,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAA0B,CAAC;AACtD,CAAC;AAED,SAAS,iBAAiB,CAAC,MAAkE;IACzF,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,MAAM,CAAC;IAE3C,cAAc,CAAC,OAAO,CAAC,oBAAoB,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAC;AAC9F,CAAC;AAEM,KAAK,UAAU,iBAAiB,CAAC,MAA6B;IACjE,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC;IAE7B,UAAU,EAAE,CAAC;QACT,MAAM,YAAY,GAAG,kBAAkB,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;QAEvD,IAAI,YAAY,KAAK,SAAS,EAAE,CAAC;YAC7B,MAAM,UAAU,CAAC;QACrB,CAAC;QAED,OAAO,YAAY,CAAC;IACxB,CAAC;IAED,IAAI,YAAmC,CAAC;IAExC,IAAI,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,SAAS,GAAG,uBAAe,EAAE,EAAE;YAC3D,OAAO,EAAE;gBACL,MAAM,EAAE,4CAA4C;aACvD;SACJ,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,EAAE,CAAC;QACtB,CAAC;QAED,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAElC,CAAC;YACG,MAAM,EAAE,sBAAsB,EAAE,GAAG,GAAG,CAAC;YAEvC,IAAI,OAAO,sBAAsB,KAAK,QAAQ,EAAE,CAAC;gBAC7C,MAAM,IAAI,KAAK,EAAE,CAAC;YACtB,CAAC;QACL,CAAC;QAED,YAAY,GAAG,GAAG,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,IAAI,CAAC,IAAA,wCAAoB,GAAE,EAAE,CAAC;QAC1B,iBAAiB,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,OAAO,YAAY,CAAC;AACxB,CAAC"}
|
package/core/createOidc.d.ts
CHANGED
|
@@ -65,10 +65,6 @@ export type ParamsOfCreateOidc<DecodedIdToken extends Record<string, unknown> =
|
|
|
65
65
|
* */
|
|
66
66
|
idleSessionLifetimeInSeconds?: number;
|
|
67
67
|
/**
|
|
68
|
-
* Usage discouraged, this parameter exists because we don't want to assume
|
|
69
|
-
* too much about your usecase but I can't think of a scenario where you would
|
|
70
|
-
* want anything other than the current page.
|
|
71
|
-
*
|
|
72
68
|
* Default: { redirectTo: "current page" }
|
|
73
69
|
*/
|
|
74
70
|
autoLogoutParams?: Parameters<Oidc.LoggedIn<any>["logout"]>[0];
|
|
@@ -170,6 +166,8 @@ export type ParamsOfCreateOidc<DecodedIdToken extends Record<string, unknown> =
|
|
|
170
166
|
* API and no iframe capabilities.
|
|
171
167
|
*/
|
|
172
168
|
postLoginRedirectUrl?: string;
|
|
169
|
+
/** See: https://docs.oidc-spa.dev/v/v8/features/dpop */
|
|
170
|
+
dpop?: "disabled" | "enabled" | "auto";
|
|
173
171
|
};
|
|
174
172
|
/** @see: https://docs.oidc-spa.dev/v/v8/usage */
|
|
175
173
|
export declare function createOidc<DecodedIdToken extends Record<string, unknown> = Oidc.Tokens.DecodedIdToken_OidcCoreSpec, AutoLogin extends boolean = false>(params: ParamsOfCreateOidc<DecodedIdToken, AutoLogin>): Promise<AutoLogin extends true ? Oidc.LoggedIn<DecodedIdToken> : Oidc<DecodedIdToken>>;
|
package/core/createOidc.js
CHANGED
|
@@ -72,9 +72,10 @@ const homeAndRedirectUri_1 = require("./homeAndRedirectUri");
|
|
|
72
72
|
const ensureNonBlankPaint_1 = require("../tools/ensureNonBlankPaint");
|
|
73
73
|
const StateDataCookie_1 = require("./StateDataCookie");
|
|
74
74
|
const tokenPlaceholderSubstitution_1 = require("./tokenPlaceholderSubstitution");
|
|
75
|
+
const dpop_1 = require("./dpop");
|
|
75
76
|
const loadWebcryptoLinerShim_1 = require("../tools/loadWebcryptoLinerShim");
|
|
76
77
|
// NOTE: Replaced at build time
|
|
77
|
-
const VERSION = "8.
|
|
78
|
+
const VERSION = "8.7.1";
|
|
78
79
|
const globalContext = {
|
|
79
80
|
prOidcByConfigId: new Map(),
|
|
80
81
|
hasLogoutBeenCalled: (0, id_1.id)(false)
|
|
@@ -151,7 +152,7 @@ async function createOidc_nonMemoized(params, preProcessedParams) {
|
|
|
151
152
|
return new Promise(() => { });
|
|
152
153
|
}
|
|
153
154
|
}
|
|
154
|
-
const { transformUrlBeforeRedirect, extraQueryParams: extraQueryParamsOrGetter, extraTokenParams: extraTokenParamsOrGetter, decodedIdTokenSchema, idleSessionLifetimeInSeconds, autoLogoutParams = { redirectTo: "current page" }, autoLogin = false, postLoginRedirectUrl: postLoginRedirectUrl_default, __unsafe_clientSecret, __unsafe_useIdTokenAsAccessToken = false, __metadata, sessionRestorationMethod = params.autoLogin === true ? "full page redirect" : "auto" } = params;
|
|
155
|
+
const { transformUrlBeforeRedirect, extraQueryParams: extraQueryParamsOrGetter, extraTokenParams: extraTokenParamsOrGetter, decodedIdTokenSchema, idleSessionLifetimeInSeconds, autoLogoutParams = { redirectTo: "current page" }, autoLogin = false, postLoginRedirectUrl: postLoginRedirectUrl_default, __unsafe_clientSecret, __unsafe_useIdTokenAsAccessToken = false, __metadata, sessionRestorationMethod = params.autoLogin === true ? "full page redirect" : "auto", dpop } = params;
|
|
155
156
|
const scopes = Array.from(new Set(["openid", ...(params.scopes ?? ["profile"])]));
|
|
156
157
|
const BASE_URL_params = params.BASE_URL ?? params.homeUrl;
|
|
157
158
|
const { issuerUri, clientId, configId, log } = preProcessedParams;
|
|
@@ -200,6 +201,43 @@ async function createOidc_nonMemoized(params, preProcessedParams) {
|
|
|
200
201
|
}
|
|
201
202
|
const stateUrlParamValue_instance = (0, StateData_1.generateStateUrlParamValue)();
|
|
202
203
|
const oidcMetadata = __metadata ?? (await (0, OidcMetadata_1.fetchOidcMetadata)({ issuerUri }));
|
|
204
|
+
const isDPoPEnabled = (() => {
|
|
205
|
+
if (dpop === undefined) {
|
|
206
|
+
log?.("DPoP disabled, to enable it see: https://docs.oidc-spa.dev/features/dpop");
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
if (dpop === "disabled") {
|
|
210
|
+
log?.("DPoP explicitly disabled");
|
|
211
|
+
return false;
|
|
212
|
+
}
|
|
213
|
+
if (oidcMetadata === undefined) {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
if (__unsafe_useIdTokenAsAccessToken) {
|
|
217
|
+
if (dpop === "enabled") {
|
|
218
|
+
throw new Error([
|
|
219
|
+
"oidc-spa: Cannot enable DPoP when",
|
|
220
|
+
"__unsafe_useIdTokenAsAccessToken is set to true"
|
|
221
|
+
].join(" "));
|
|
222
|
+
}
|
|
223
|
+
log?.("DPoP Disabled due to __unsafe_useIdTokenAsAccessToken: true");
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
const isSupported = (() => {
|
|
227
|
+
const { dpop_signing_alg_values_supported } = oidcMetadata;
|
|
228
|
+
if (dpop_signing_alg_values_supported === undefined) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
return dpop_signing_alg_values_supported.includes("ES256");
|
|
232
|
+
})();
|
|
233
|
+
if (!isSupported) {
|
|
234
|
+
log?.("DPoP disabled because it's not supported by your IdP");
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
log?.("DPoP enabled");
|
|
238
|
+
}
|
|
239
|
+
return isSupported;
|
|
240
|
+
})();
|
|
203
241
|
const canUseIframe = (() => {
|
|
204
242
|
switch (sessionRestorationMethod) {
|
|
205
243
|
case "auto":
|
|
@@ -371,7 +409,13 @@ async function createOidc_nonMemoized(params, preProcessedParams) {
|
|
|
371
409
|
prefix: StateData_1.STATE_STORE_KEY_PREFIX
|
|
372
410
|
}),
|
|
373
411
|
client_secret: __unsafe_clientSecret,
|
|
374
|
-
metadata: oidcMetadata
|
|
412
|
+
metadata: oidcMetadata,
|
|
413
|
+
dpop: !isDPoPEnabled
|
|
414
|
+
? undefined
|
|
415
|
+
: {
|
|
416
|
+
bind_authorization_code: false,
|
|
417
|
+
store: (0, dpop_1.createInMemoryDPoPStore)({ configId })
|
|
418
|
+
}
|
|
375
419
|
});
|
|
376
420
|
const evtInitializationOutcomeUserNotLoggedIn = (0, Evt_1.createEvt)();
|
|
377
421
|
const { loginOrGoToAuthServer } = (0, loginOrGoToAuthServer_1.createLoginOrGoToAuthServer)({
|
|
@@ -791,6 +835,7 @@ async function createOidc_nonMemoized(params, preProcessedParams) {
|
|
|
791
835
|
decodedIdTokenSchema,
|
|
792
836
|
__unsafe_useIdTokenAsAccessToken,
|
|
793
837
|
decodedIdToken_previous: undefined,
|
|
838
|
+
isDPoPEnabled,
|
|
794
839
|
log
|
|
795
840
|
});
|
|
796
841
|
detect_useless_idleSessionLifetimeInSeconds: {
|
|
@@ -1044,6 +1089,7 @@ async function createOidc_nonMemoized(params, preProcessedParams) {
|
|
|
1044
1089
|
decodedIdTokenSchema,
|
|
1045
1090
|
__unsafe_useIdTokenAsAccessToken,
|
|
1046
1091
|
decodedIdToken_previous: currentTokens.decodedIdToken,
|
|
1092
|
+
isDPoPEnabled,
|
|
1047
1093
|
log
|
|
1048
1094
|
});
|
|
1049
1095
|
if ((0, persistedAuthState_1.getPersistedAuthState)({ configId }) !== undefined) {
|