oidc-spa 8.6.18 → 8.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- 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 +46 -6
- 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/evtIsUserActive.d.ts +8 -1
- package/core/evtIsUserActive.js +4 -2
- package/core/evtIsUserActive.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 +46 -6
- 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/evtIsUserActive.d.ts +8 -1
- package/esm/core/evtIsUserActive.mjs +4 -2
- package/esm/core/evtIsUserActive.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/tools/startCountdown.mjs +9 -3
- package/esm/tools/startCountdown.mjs.map +1 -1
- 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 +61 -9
- package/src/core/dpop.ts +583 -0
- package/src/core/earlyInit.ts +3 -0
- package/src/core/evtIsUserActive.ts +11 -5
- 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/tools/startCountdown.ts +10 -3
- 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/tools/startCountdown.js +9 -3
- package/tools/startCountdown.js.map +1 -1
- 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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,CAAC,MAAM,OAAO,GAAG,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claims defined by RFC 9068: "JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens"
|
|
3
|
+
* https://datatracker.ietf.org/doc/html/rfc9068
|
|
4
|
+
*
|
|
5
|
+
* These tokens are intended for consumption by resource servers.
|
|
6
|
+
*/
|
|
7
|
+
export type DecodedAccessToken_RFC9068 = {
|
|
8
|
+
iss: string;
|
|
9
|
+
sub: string;
|
|
10
|
+
aud: string | string[];
|
|
11
|
+
exp: number;
|
|
12
|
+
iat: number;
|
|
13
|
+
client_id?: string;
|
|
14
|
+
scope?: string;
|
|
15
|
+
jti?: string;
|
|
16
|
+
nbf?: number;
|
|
17
|
+
auth_time?: number;
|
|
18
|
+
cnf?: Record<string, unknown>;
|
|
19
|
+
[key: string]: unknown;
|
|
20
|
+
};
|
|
21
|
+
export type ValidateAndDecodeAccessToken<DecodedAccessToken> = (params: {
|
|
22
|
+
request: {
|
|
23
|
+
method: string;
|
|
24
|
+
url: string;
|
|
25
|
+
headers: Record<"Authorization" | "DPoP", string | null | undefined>;
|
|
26
|
+
};
|
|
27
|
+
}) => Promise<ValidateAndDecodeAccessToken.ReturnType<DecodedAccessToken>>;
|
|
28
|
+
export declare namespace ValidateAndDecodeAccessToken {
|
|
29
|
+
type ReturnType<DecodedAccessToken> = (ReturnType.Success<DecodedAccessToken> & {
|
|
30
|
+
errorCause?: never;
|
|
31
|
+
debugErrorMessage?: never;
|
|
32
|
+
}) | (ReturnType.Errored & {
|
|
33
|
+
decodedAccessToken?: never;
|
|
34
|
+
decodedAccessToken_original?: never;
|
|
35
|
+
accessToken?: never;
|
|
36
|
+
});
|
|
37
|
+
namespace ReturnType {
|
|
38
|
+
type Success<DecodedAccessToken> = {
|
|
39
|
+
isSuccess: true;
|
|
40
|
+
decodedAccessToken: DecodedAccessToken;
|
|
41
|
+
decodedAccessToken_original: DecodedAccessToken_RFC9068;
|
|
42
|
+
accessToken: string;
|
|
43
|
+
};
|
|
44
|
+
type Errored = {
|
|
45
|
+
isSuccess: false;
|
|
46
|
+
errorCause: "missing Authorization header" | "validation error" | "validation error - access token expired" | "validation error - invalid signature";
|
|
47
|
+
debugErrorMessage: string;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export type ParamsOfBootstrap<DecodedAccessToken> = ParamsOfBootstrap.Real | ParamsOfBootstrap.Mock<DecodedAccessToken>;
|
|
52
|
+
export declare namespace ParamsOfBootstrap {
|
|
53
|
+
type Real = {
|
|
54
|
+
implementation: "real";
|
|
55
|
+
issuerUri: string;
|
|
56
|
+
expectedAudience: string | undefined;
|
|
57
|
+
};
|
|
58
|
+
type Mock<DecodedAccessToken> = Mock.DecodeOnly | Mock.UseStaticIdentity<DecodedAccessToken>;
|
|
59
|
+
namespace Mock {
|
|
60
|
+
type Common = {
|
|
61
|
+
implementation: "mock";
|
|
62
|
+
};
|
|
63
|
+
export type DecodeOnly = Common & {
|
|
64
|
+
behavior: "decode only";
|
|
65
|
+
};
|
|
66
|
+
export type UseStaticIdentity<DecodedAccessToken> = Common & {
|
|
67
|
+
behavior: "use static identity";
|
|
68
|
+
decodedAccessToken_mock: DecodedAccessToken;
|
|
69
|
+
decodedAccessToken_original_mock?: DecodedAccessToken_RFC9068;
|
|
70
|
+
accessToken_mock?: string;
|
|
71
|
+
};
|
|
72
|
+
export {};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
export type OidcSpaUtils<DecodedAccessToken> = {
|
|
76
|
+
bootstrapAuth: (params: ParamsOfBootstrap<DecodedAccessToken>) => Promise<void>;
|
|
77
|
+
validateAndDecodeAccessToken: ValidateAndDecodeAccessToken<DecodedAccessToken>;
|
|
78
|
+
ofTypeDecodedAccessToken: DecodedAccessToken;
|
|
79
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.mjs","sourceRoot":"","sources":["../../src/server/types.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { OidcSpaUtils } from "./types";
|
|
2
|
+
import type { ZodSchemaLike } from "../tools/ZodSchemaLike";
|
|
3
|
+
import type { DecodedAccessToken_RFC9068 } from "./types";
|
|
4
|
+
export type OidcSpaUtilsBuilder<DecodedAccessToken extends Record<string, unknown> = DecodedAccessToken_RFC9068, ExcludedMethod extends "withExpectedDecodedAccessTokenShape" | "createUtils" = never> = Omit<{
|
|
5
|
+
withExpectedDecodedAccessTokenShape: <DecodedAccessToken extends Record<string, unknown>>(params: {
|
|
6
|
+
decodedAccessTokenSchema: ZodSchemaLike<DecodedAccessToken_RFC9068, DecodedAccessToken>;
|
|
7
|
+
}) => OidcSpaUtilsBuilder<DecodedAccessToken, ExcludedMethod | "withExpectedDecodedAccessTokenShape">;
|
|
8
|
+
createUtils: () => OidcSpaUtils<DecodedAccessToken>;
|
|
9
|
+
}, ExcludedMethod>;
|
|
10
|
+
export declare const oidcSpaUtilsBuilder: OidcSpaUtilsBuilder<DecodedAccessToken_RFC9068, never>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createOidcSpaUtils } from "./createOidcSpaUtils.mjs";
|
|
2
|
+
function createOidcSpaUtilsBuilder(params) {
|
|
3
|
+
return {
|
|
4
|
+
withExpectedDecodedAccessTokenShape: ({ decodedAccessTokenSchema }) => createOidcSpaUtilsBuilder({ decodedAccessTokenSchema }),
|
|
5
|
+
createUtils: () => createOidcSpaUtils({
|
|
6
|
+
decodedAccessTokenSchema: params.decodedAccessTokenSchema
|
|
7
|
+
})
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export const oidcSpaUtilsBuilder = createOidcSpaUtilsBuilder({
|
|
11
|
+
decodedAccessTokenSchema: undefined
|
|
12
|
+
});
|
|
13
|
+
//# sourceMappingURL=utilsBuilder.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utilsBuilder.mjs","sourceRoot":"","sources":["../../src/server/utilsBuilder.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAqB1D,SAAS,yBAAyB,CAEhC,MAED;IACG,OAAO;QACH,mCAAmC,EAAE,CAAC,EAAE,wBAAwB,EAAE,EAAE,EAAE,CAClE,yBAAyB,CAAC,EAAE,wBAAwB,EAAE,CAAC;QAC3D,WAAW,EAAE,GAAG,EAAE,CACd,kBAAkB,CAAqB;YACnC,wBAAwB,EAAE,MAAM,CAAC,wBAAwB;SAC5D,CAAC;KACT,CAAC;AACN,CAAC;AAED,MAAM,CAAC,MAAM,mBAAmB,GAAG,yBAAyB,CAAC;IACzD,wBAAwB,EAAE,SAAS;CACtC,CAAC,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CreateValidateAndGetAccessTokenClaims, ParamsOfBootstrap } from "./types";
|
|
2
|
-
import type { DecodedAccessToken_RFC9068 as AccessTokenClaims_RFC9068 } from "../../
|
|
2
|
+
import type { DecodedAccessToken_RFC9068 as AccessTokenClaims_RFC9068 } from "../../server/types";
|
|
3
3
|
import type { ZodSchemaLike } from "../../tools/ZodSchemaLike";
|
|
4
4
|
export declare function createCreateValidateAndGetAccessTokenClaims_rfc9068<AccessTokenClaims extends Record<string, unknown>>(params: {
|
|
5
5
|
accessTokenClaimsSchema?: ZodSchemaLike<AccessTokenClaims_RFC9068, AccessTokenClaims>;
|
|
@@ -1,14 +1,67 @@
|
|
|
1
1
|
import { createObjectThatThrowsIfAccessed } from "../../tools/createObjectThatThrowsIfAccessed.mjs";
|
|
2
|
-
import { assert, is } from "../../
|
|
2
|
+
import { assert, is, id } from "../../vendor/server/tsafe.mjs";
|
|
3
3
|
export function createCreateValidateAndGetAccessTokenClaims_rfc9068(params) {
|
|
4
4
|
const { accessTokenClaimsSchema, accessTokenClaims_mock, expectedAudience: expectedAudienceGetter } = params;
|
|
5
5
|
const createValidateAndGetAccessTokenClaims = ({ paramsOfBootstrap }) => {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
const prValidateAndDecodeAccessToken = (async () => {
|
|
7
|
+
const { oidcSpa: oidcSpa_server } = await import("../../server/index.mjs");
|
|
8
|
+
const { bootstrapAuth, validateAndDecodeAccessToken } = accessTokenClaimsSchema === undefined
|
|
9
|
+
? oidcSpa_server.createUtils()
|
|
10
|
+
: oidcSpa_server
|
|
11
|
+
.withExpectedDecodedAccessTokenShape({
|
|
12
|
+
decodedAccessTokenSchema: accessTokenClaimsSchema
|
|
13
|
+
})
|
|
14
|
+
.createUtils();
|
|
15
|
+
switch (paramsOfBootstrap.implementation) {
|
|
16
|
+
case "real":
|
|
17
|
+
{
|
|
18
|
+
const expectedAudience = (() => {
|
|
19
|
+
if (expectedAudienceGetter === undefined) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
const missingEnvNames = new Set();
|
|
23
|
+
const env_proxy = new Proxy({}, {
|
|
24
|
+
get: (...[, envName]) => {
|
|
25
|
+
assert(typeof envName === "string");
|
|
26
|
+
const value = process.env[envName];
|
|
27
|
+
if (value === undefined) {
|
|
28
|
+
missingEnvNames.add(envName);
|
|
29
|
+
return "";
|
|
30
|
+
}
|
|
31
|
+
return value;
|
|
32
|
+
},
|
|
33
|
+
has: (...[, envName]) => {
|
|
34
|
+
assert(typeof envName === "string");
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
const expectedAudience = expectedAudienceGetter?.({
|
|
39
|
+
paramsOfBootstrap,
|
|
40
|
+
process: { env: env_proxy }
|
|
41
|
+
});
|
|
42
|
+
if (!expectedAudience) {
|
|
43
|
+
throw new Error([
|
|
44
|
+
"oidc-spa: The expectedAudience() you provided returned empty.",
|
|
45
|
+
"If you specified the expectedAudience in withAccessTokenValidation",
|
|
46
|
+
"it's probably an error.",
|
|
47
|
+
missingEnvNames.size !== 0 &&
|
|
48
|
+
`Did you forget to set the env var: ${Array.from(missingEnvNames).join(", ")} ?`
|
|
49
|
+
]
|
|
50
|
+
.filter(line => typeof line === "string")
|
|
51
|
+
.join(" "));
|
|
52
|
+
}
|
|
53
|
+
return expectedAudience;
|
|
54
|
+
})();
|
|
55
|
+
await bootstrapAuth({
|
|
56
|
+
implementation: "real",
|
|
57
|
+
issuerUri: paramsOfBootstrap.issuerUri,
|
|
58
|
+
expectedAudience
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
break;
|
|
62
|
+
case "mock":
|
|
63
|
+
{
|
|
64
|
+
const decodedAccessToken_mock = (() => {
|
|
12
65
|
if (paramsOfBootstrap.accessTokenClaims_mock !== undefined) {
|
|
13
66
|
assert(is(paramsOfBootstrap.accessTokenClaims_mock));
|
|
14
67
|
return paramsOfBootstrap.accessTokenClaims_mock;
|
|
@@ -24,99 +77,54 @@ export function createCreateValidateAndGetAccessTokenClaims_rfc9068(params) {
|
|
|
24
77
|
"specify accessTokenClaims_mock when calling bootstrapOidc()"
|
|
25
78
|
].join(" ")
|
|
26
79
|
});
|
|
27
|
-
})()
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const prVerifyAndDecodeAccessToken = (async () => {
|
|
34
|
-
const { createOidcBackend } = await import("../../backend.mjs");
|
|
35
|
-
const { verifyAndDecodeAccessToken } = await createOidcBackend({
|
|
36
|
-
issuerUri: paramsOfBootstrap.issuerUri,
|
|
37
|
-
decodedAccessTokenSchema: accessTokenClaimsSchema
|
|
38
|
-
});
|
|
39
|
-
return verifyAndDecodeAccessToken;
|
|
40
|
-
})();
|
|
41
|
-
const expectedAudience = (() => {
|
|
42
|
-
if (expectedAudienceGetter === undefined) {
|
|
43
|
-
return undefined;
|
|
44
|
-
}
|
|
45
|
-
const missingEnvNames = new Set();
|
|
46
|
-
const env_proxy = new Proxy({}, {
|
|
47
|
-
get: (...[, envName]) => {
|
|
48
|
-
assert(typeof envName === "string");
|
|
49
|
-
const value = process.env[envName];
|
|
50
|
-
if (value === undefined) {
|
|
51
|
-
missingEnvNames.add(envName);
|
|
52
|
-
return "";
|
|
80
|
+
})();
|
|
81
|
+
await bootstrapAuth({
|
|
82
|
+
implementation: "mock",
|
|
83
|
+
behavior: "use static identity",
|
|
84
|
+
decodedAccessToken_mock
|
|
85
|
+
});
|
|
53
86
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
assert(typeof envName === "string");
|
|
58
|
-
return true;
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
const expectedAudience = expectedAudienceGetter?.({
|
|
62
|
-
paramsOfBootstrap,
|
|
63
|
-
process: { env: env_proxy }
|
|
64
|
-
});
|
|
65
|
-
if (!expectedAudience) {
|
|
66
|
-
throw new Error([
|
|
67
|
-
"oidc-spa: The expectedAudience() you provided returned empty.",
|
|
68
|
-
"If you specified the expectedAudience in withAccessTokenValidation",
|
|
69
|
-
"it's probably and error.",
|
|
70
|
-
missingEnvNames.size !== 0 &&
|
|
71
|
-
`Did you forget to set the env var: ${Array.from(missingEnvNames).join(", ")} ?`
|
|
72
|
-
]
|
|
73
|
-
.filter(line => typeof line === "string")
|
|
74
|
-
.join(" "));
|
|
87
|
+
break;
|
|
88
|
+
default:
|
|
89
|
+
assert(false);
|
|
75
90
|
}
|
|
76
|
-
return
|
|
91
|
+
return validateAndDecodeAccessToken;
|
|
77
92
|
})();
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return "The access token is malformed or missing required claims";
|
|
90
|
-
case "expired":
|
|
91
|
-
return "The access token expired";
|
|
92
|
-
case "invalid signature":
|
|
93
|
-
return "The access token signature is invalid";
|
|
94
|
-
}
|
|
95
|
-
})()
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
if (expectedAudience !== undefined) {
|
|
99
|
-
const aud_array = typeof decodedAccessToken_original.aud === "string"
|
|
100
|
-
? [decodedAccessToken_original.aud]
|
|
101
|
-
: decodedAccessToken_original.aud;
|
|
102
|
-
if (!aud_array.includes(expectedAudience)) {
|
|
103
|
-
return {
|
|
104
|
-
isValid: false,
|
|
105
|
-
errorMessage: [
|
|
106
|
-
"Access token is not for the expected audience.",
|
|
107
|
-
`Got aud claim: ${JSON.stringify(decodedAccessToken_original.aud)}`,
|
|
108
|
-
`Expected: ${expectedAudience}`
|
|
109
|
-
].join(" "),
|
|
110
|
-
wwwAuthenticateHeaderErrorDescription: "The access token audience is invalid"
|
|
111
|
-
};
|
|
112
|
-
}
|
|
93
|
+
const validateAndGetAccessTokenClaims = async ({ request }) => {
|
|
94
|
+
const validateAndDecodeAccessToken = await prValidateAndDecodeAccessToken;
|
|
95
|
+
const { isSuccess, errorCause, debugErrorMessage, decodedAccessToken, accessToken } = await validateAndDecodeAccessToken({
|
|
96
|
+
request
|
|
97
|
+
});
|
|
98
|
+
if (!isSuccess) {
|
|
99
|
+
if (errorCause === "missing Authorization header") {
|
|
100
|
+
return id({
|
|
101
|
+
isSuccess: false,
|
|
102
|
+
isAnonymousRequest: true
|
|
103
|
+
});
|
|
113
104
|
}
|
|
114
|
-
return {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
105
|
+
return id({
|
|
106
|
+
isSuccess: false,
|
|
107
|
+
isAnonymousRequest: false,
|
|
108
|
+
debugErrorMessage: `${errorCause}: ${debugErrorMessage}`,
|
|
109
|
+
wwwAuthenticateResponseHeaderValue: `Bearer error="invalid_token", error_description="${(() => {
|
|
110
|
+
switch (errorCause) {
|
|
111
|
+
case "validation error":
|
|
112
|
+
case "validation error - invalid signature":
|
|
113
|
+
case "validation error - access token expired":
|
|
114
|
+
return "Validation Failed";
|
|
115
|
+
default:
|
|
116
|
+
assert(false);
|
|
117
|
+
}
|
|
118
|
+
})()}"`
|
|
119
|
+
});
|
|
118
120
|
}
|
|
121
|
+
return id({
|
|
122
|
+
isSuccess: true,
|
|
123
|
+
accessTokenClaims: decodedAccessToken,
|
|
124
|
+
accessToken
|
|
125
|
+
});
|
|
119
126
|
};
|
|
127
|
+
return { validateAndGetAccessTokenClaims };
|
|
120
128
|
};
|
|
121
129
|
return { createValidateAndGetAccessTokenClaims };
|
|
122
130
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"accessTokenValidation_rfc9068.mjs","sourceRoot":"","sources":["../../../src/tanstack-start/react/accessTokenValidation_rfc9068.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"accessTokenValidation_rfc9068.mjs","sourceRoot":"","sources":["../../../src/tanstack-start/react/accessTokenValidation_rfc9068.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CreateValidateAndGetAccessTokenClaims,
|
|
1
|
+
import type { CreateValidateAndGetAccessTokenClaims, OidcSpaUtils } from "./types";
|
|
2
2
|
import type { ZodSchemaLike } from "../../tools/ZodSchemaLike";
|
|
3
3
|
import type { Oidc as Oidc_core } from "../../core";
|
|
4
4
|
export declare function createOidcSpaApi<AutoLogin extends boolean, DecodedIdToken extends Record<string, unknown>, AccessTokenClaims extends Record<string, unknown> | undefined>(params: {
|
|
@@ -6,4 +6,4 @@ export declare function createOidcSpaApi<AutoLogin extends boolean, DecodedIdTok
|
|
|
6
6
|
decodedIdTokenSchema: ZodSchemaLike<Oidc_core.Tokens.DecodedIdToken_OidcCoreSpec, DecodedIdToken> | undefined;
|
|
7
7
|
decodedIdToken_mock: DecodedIdToken | undefined;
|
|
8
8
|
createValidateAndGetAccessTokenClaims: CreateValidateAndGetAccessTokenClaims<AccessTokenClaims> | undefined;
|
|
9
|
-
}):
|
|
9
|
+
}): OidcSpaUtils<AutoLogin, DecodedIdToken, AccessTokenClaims>;
|
|
@@ -10,6 +10,7 @@ import { typeGuard } from "../../tools/tsafe/typeGuard.mjs";
|
|
|
10
10
|
import { createServerFn, createMiddleware } from "@tanstack/react-start";
|
|
11
11
|
// @ts-expect-error: Since our module is not labeled as ESM we don't have the types here.
|
|
12
12
|
import { getRequest, setResponseHeader, setResponseStatus } from "@tanstack/react-start/server";
|
|
13
|
+
//import { getRequest, setResponseHeader, setResponseStatus } from "@tanstack/react-start-server";
|
|
13
14
|
import { toFullyQualifiedUrl } from "../../tools/toFullyQualifiedUrl.mjs";
|
|
14
15
|
import { BEFORE_LOAD_FN_BRAND_PROPERTY_NAME } from "./disableSsrIfLoginEnforced.mjs";
|
|
15
16
|
import { setDesiredPostLoginRedirectUrl } from "../../core/desiredPostLoginRedirectUrl.mjs";
|
|
@@ -469,7 +470,8 @@ export function createOidcSpaApi(params) {
|
|
|
469
470
|
__unsafe_clientSecret: paramsOfBootstrap.__unsafe_clientSecret,
|
|
470
471
|
__metadata: paramsOfBootstrap.__metadata,
|
|
471
472
|
__unsafe_useIdTokenAsAccessToken: paramsOfBootstrap.__unsafe_useIdTokenAsAccessToken,
|
|
472
|
-
autoLogoutParams: paramsOfBootstrap.autoLogoutParams
|
|
473
|
+
autoLogoutParams: paramsOfBootstrap.autoLogoutParams,
|
|
474
|
+
dpop: paramsOfBootstrap.dpop
|
|
473
475
|
});
|
|
474
476
|
}
|
|
475
477
|
catch (error) {
|
|
@@ -550,57 +552,64 @@ export function createOidcSpaApi(params) {
|
|
|
550
552
|
return async (options) => {
|
|
551
553
|
const { next } = options;
|
|
552
554
|
const unauthorized = (params) => {
|
|
553
|
-
const {
|
|
554
|
-
setResponseHeader("WWW-Authenticate",
|
|
555
|
-
setResponseStatus(
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
"Asserted user logged in for that serverFn request",
|
|
564
|
-
"but no access token was attached to the request"
|
|
565
|
-
].join(" ");
|
|
566
|
-
throw unauthorized({
|
|
567
|
-
errorMessage,
|
|
568
|
-
wwwAuthenticateHeaderErrorDescription: errorMessage
|
|
569
|
-
});
|
|
570
|
-
}
|
|
571
|
-
return next({
|
|
572
|
-
context: {
|
|
573
|
-
oidc: id(id({
|
|
574
|
-
isUserLoggedIn: false
|
|
575
|
-
}))
|
|
555
|
+
const { code, wwwAuthenticateResponseHeaderValue, debugErrorMessage } = params;
|
|
556
|
+
setResponseHeader("WWW-Authenticate", wwwAuthenticateResponseHeaderValue);
|
|
557
|
+
setResponseStatus(code, (() => {
|
|
558
|
+
switch (code) {
|
|
559
|
+
case 401:
|
|
560
|
+
return "Unauthorized";
|
|
561
|
+
case 403:
|
|
562
|
+
return "Forbidden";
|
|
563
|
+
default:
|
|
564
|
+
assert(false);
|
|
576
565
|
}
|
|
577
|
-
});
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
const prefix = "Bearer ";
|
|
581
|
-
if (!authorizationHeaderValue.startsWith(prefix)) {
|
|
582
|
-
return undefined;
|
|
566
|
+
})());
|
|
567
|
+
if (process.env.NODE_ENV === "development") {
|
|
568
|
+
console.error(`oidc-spa: ${debugErrorMessage}`);
|
|
583
569
|
}
|
|
584
|
-
return
|
|
585
|
-
}
|
|
586
|
-
if (accessToken === undefined) {
|
|
587
|
-
const errorMessage = "Missing well formed Authorization header with Bearer <access_token>";
|
|
588
|
-
throw unauthorized({
|
|
589
|
-
errorMessage,
|
|
590
|
-
wwwAuthenticateHeaderErrorDescription: errorMessage
|
|
591
|
-
});
|
|
592
|
-
}
|
|
570
|
+
return new Error(`oidc-spa: ${wwwAuthenticateResponseHeaderValue}`);
|
|
571
|
+
};
|
|
593
572
|
assert(prValidateAndGetAccessTokenClaims !== undefined);
|
|
594
573
|
const { validateAndGetAccessTokenClaims } = await prValidateAndGetAccessTokenClaims;
|
|
595
|
-
const
|
|
596
|
-
|
|
597
|
-
|
|
574
|
+
const { headers, url, method } = getRequest();
|
|
575
|
+
const resultOfValidate = await validateAndGetAccessTokenClaims({
|
|
576
|
+
request: {
|
|
577
|
+
url,
|
|
578
|
+
method,
|
|
579
|
+
headers: {
|
|
580
|
+
Authorization: headers.get("Authorization"),
|
|
581
|
+
DPoP: headers.get("DPoP")
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
if (!resultOfValidate.isSuccess) {
|
|
586
|
+
if (resultOfValidate.isAnonymousRequest) {
|
|
587
|
+
if (params?.assert === "user logged in") {
|
|
588
|
+
throw unauthorized({
|
|
589
|
+
code: 401,
|
|
590
|
+
wwwAuthenticateResponseHeaderValue: "Bearer error=\"invalid_request\", error_description=\"Missing access token\"",
|
|
591
|
+
debugErrorMessage: [
|
|
592
|
+
"Asserted user logged in for that serverFn request",
|
|
593
|
+
"but no access token was attached to the request"
|
|
594
|
+
].join(" ")
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
return next({
|
|
598
|
+
context: {
|
|
599
|
+
oidc: id(id({
|
|
600
|
+
isUserLoggedIn: false
|
|
601
|
+
}))
|
|
602
|
+
}
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
const { debugErrorMessage, wwwAuthenticateResponseHeaderValue } = resultOfValidate;
|
|
598
606
|
throw unauthorized({
|
|
599
|
-
|
|
600
|
-
|
|
607
|
+
code: 401,
|
|
608
|
+
wwwAuthenticateResponseHeaderValue,
|
|
609
|
+
debugErrorMessage
|
|
601
610
|
});
|
|
602
611
|
}
|
|
603
|
-
const { accessTokenClaims } = resultOfValidate;
|
|
612
|
+
const { accessTokenClaims, accessToken } = resultOfValidate;
|
|
604
613
|
assert(is(accessTokenClaims));
|
|
605
614
|
check_required_claims: {
|
|
606
615
|
const getHasRequiredClaims = params?.hasRequiredClaims;
|
|
@@ -626,13 +635,13 @@ export function createOidcSpaApi(params) {
|
|
|
626
635
|
if (hasRequiredClaims) {
|
|
627
636
|
break check_required_claims;
|
|
628
637
|
}
|
|
629
|
-
const errorMessage = [
|
|
630
|
-
"Missing or invalid required access token claim.",
|
|
631
|
-
`Related to claims: ${Array.from(accessedClaimNames).join(" and/or ")}`
|
|
632
|
-
].join(" ");
|
|
633
638
|
throw unauthorized({
|
|
634
|
-
|
|
635
|
-
|
|
639
|
+
code: 403,
|
|
640
|
+
wwwAuthenticateResponseHeaderValue: "Bearer error=\"insufficient_scope\", error_description=\"Insufficient privileges\"",
|
|
641
|
+
debugErrorMessage: [
|
|
642
|
+
"Missing or invalid required access token claim.",
|
|
643
|
+
`Related to claims: ${Array.from(accessedClaimNames).join(" and/or ")}`
|
|
644
|
+
].join(" ")
|
|
636
645
|
});
|
|
637
646
|
}
|
|
638
647
|
return next({
|