@lunora/cloudflare-access 1.0.0-alpha.20 → 1.0.0-alpha.22
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/dist/admin.mjs +7 -4
- package/dist/context.mjs +3 -2
- package/dist/index.d.mts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.mjs +2 -2
- package/dist/packem_shared/{accessIssuer-83KYwaCp.mjs → accessIssuer-C69kkiYc.mjs} +12 -6
- package/dist/packem_shared/{composeResolvers-BI3envaN.mjs → composeResolvers-BlVswT75.mjs} +10 -9
- package/dist/packem_shared/identity-groups-CONuLY61.mjs +8 -0
- package/dist/roles.mjs +3 -7
- package/package.json +3 -3
package/dist/admin.mjs
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { verifyRequest } from './packem_shared/accessIssuer-
|
|
1
|
+
import { assertVerifyOptions, verifyRequest } from './packem_shared/accessIssuer-C69kkiYc.mjs';
|
|
2
2
|
|
|
3
|
-
const accessAdminGate = (options) =>
|
|
4
|
-
|
|
5
|
-
return
|
|
3
|
+
const accessAdminGate = (options) => {
|
|
4
|
+
assertVerifyOptions(options);
|
|
5
|
+
return async (request) => {
|
|
6
|
+
const claims = await verifyRequest(request, options);
|
|
7
|
+
return claims === void 0 ? false : options.isAdmin(claims);
|
|
8
|
+
};
|
|
6
9
|
};
|
|
7
10
|
|
|
8
11
|
export { accessAdminGate };
|
package/dist/context.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { r as readIdentityGroups } from './packem_shared/identity-groups-CONuLY61.mjs';
|
|
2
|
+
|
|
2
3
|
const stringClaim = (value) => typeof value === "string" ? value : void 0;
|
|
3
4
|
const ANONYMOUS_FACADE = {
|
|
4
5
|
authenticated: false,
|
|
@@ -15,7 +16,7 @@ const facadeFor = (identity, userId) => {
|
|
|
15
16
|
return ANONYMOUS_FACADE;
|
|
16
17
|
}
|
|
17
18
|
const claims = raw;
|
|
18
|
-
const groups =
|
|
19
|
+
const groups = readIdentityGroups(identity) ?? [];
|
|
19
20
|
return {
|
|
20
21
|
authenticated: true,
|
|
21
22
|
claims,
|
package/dist/index.d.mts
CHANGED
|
@@ -40,6 +40,17 @@ declare const composeResolvers: (...resolvers: ResolveIdentityFunction[]) => Res
|
|
|
40
40
|
* bare name with no dot is expanded to the `cloudflareaccess.com` host.
|
|
41
41
|
*/
|
|
42
42
|
declare const accessIssuer: (teamDomain: string) => string;
|
|
43
|
+
/**
|
|
44
|
+
* Eagerly validate the static, construction-time verify options so a misconfigured
|
|
45
|
+
* deployment fails fast at factory build time instead of degrading to
|
|
46
|
+
* silent-anonymous on every request. `createAccessResolver` / `accessAdminGate`
|
|
47
|
+
* call this once when built: `teamDomain` must resolve to a valid Access issuer
|
|
48
|
+
* and `aud` must be a non-empty tag. The per-request catch in {@link verifyRequest}
|
|
49
|
+
* then covers only genuine token-verification failures, not config mistakes — a
|
|
50
|
+
* broken deployment throws here at startup rather than resolving every caller to
|
|
51
|
+
* anonymous with zero signal.
|
|
52
|
+
*/
|
|
53
|
+
|
|
43
54
|
/**
|
|
44
55
|
* Verify a Cloudflare Access JWT and return its claims.
|
|
45
56
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -40,6 +40,17 @@ declare const composeResolvers: (...resolvers: ResolveIdentityFunction[]) => Res
|
|
|
40
40
|
* bare name with no dot is expanded to the `cloudflareaccess.com` host.
|
|
41
41
|
*/
|
|
42
42
|
declare const accessIssuer: (teamDomain: string) => string;
|
|
43
|
+
/**
|
|
44
|
+
* Eagerly validate the static, construction-time verify options so a misconfigured
|
|
45
|
+
* deployment fails fast at factory build time instead of degrading to
|
|
46
|
+
* silent-anonymous on every request. `createAccessResolver` / `accessAdminGate`
|
|
47
|
+
* call this once when built: `teamDomain` must resolve to a valid Access issuer
|
|
48
|
+
* and `aud` must be a non-empty tag. The per-request catch in {@link verifyRequest}
|
|
49
|
+
* then covers only genuine token-verification failures, not config mistakes — a
|
|
50
|
+
* broken deployment throws here at startup rather than resolving every caller to
|
|
51
|
+
* anonymous with zero signal.
|
|
52
|
+
*/
|
|
53
|
+
|
|
43
54
|
/**
|
|
44
55
|
* Verify a Cloudflare Access JWT and return its claims.
|
|
45
56
|
*
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { composeResolvers, createAccessResolver } from './packem_shared/composeResolvers-
|
|
2
|
-
export { accessIssuer, verifyAccessJwt } from './packem_shared/accessIssuer-
|
|
1
|
+
export { composeResolvers, createAccessResolver } from './packem_shared/composeResolvers-BlVswT75.mjs';
|
|
2
|
+
export { accessIssuer, verifyAccessJwt } from './packem_shared/accessIssuer-C69kkiYc.mjs';
|
|
@@ -52,17 +52,23 @@ const remoteJwks = (issuer) => {
|
|
|
52
52
|
}
|
|
53
53
|
return getter;
|
|
54
54
|
};
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
const audiences = (Array.isArray(options.aud) ? options.aud : [options.aud]).filter(
|
|
58
|
-
(entry) => typeof entry === "string" && entry.length > 0
|
|
59
|
-
);
|
|
55
|
+
const normalizeAudiences = (aud) => {
|
|
56
|
+
const audiences = (Array.isArray(aud) ? aud : [aud]).filter((entry) => typeof entry === "string" && entry.length > 0);
|
|
60
57
|
if (audiences.length === 0) {
|
|
61
58
|
throw new LunoraError(
|
|
62
59
|
"INTERNAL",
|
|
63
60
|
"@lunora/cloudflare-access: `aud` is required and must be a non-empty Access AUD tag — refusing to verify a token without an audience to scope it to your application"
|
|
64
61
|
);
|
|
65
62
|
}
|
|
63
|
+
return audiences;
|
|
64
|
+
};
|
|
65
|
+
const assertVerifyOptions = (options) => {
|
|
66
|
+
accessIssuer(options.teamDomain);
|
|
67
|
+
normalizeAudiences(options.aud);
|
|
68
|
+
};
|
|
69
|
+
const verifyAccessJwt = async (token, options) => {
|
|
70
|
+
const issuer = accessIssuer(options.teamDomain);
|
|
71
|
+
const audiences = normalizeAudiences(options.aud);
|
|
66
72
|
const keySet = options.keySet ?? remoteJwks(issuer);
|
|
67
73
|
const { payload } = await jwtVerify(token, keySet, {
|
|
68
74
|
algorithms: ["RS256"],
|
|
@@ -90,4 +96,4 @@ const verifyRequest = async (request, options) => {
|
|
|
90
96
|
}
|
|
91
97
|
};
|
|
92
98
|
|
|
93
|
-
export { accessIssuer, verifyAccessJwt, verifyRequest };
|
|
99
|
+
export { accessIssuer, assertVerifyOptions, verifyAccessJwt, verifyRequest };
|
|
@@ -1,13 +1,11 @@
|
|
|
1
|
-
import { verifyRequest } from './accessIssuer-
|
|
1
|
+
import { assertVerifyOptions, verifyRequest } from './accessIssuer-C69kkiYc.mjs';
|
|
2
2
|
|
|
3
3
|
const ANONYMOUS = null;
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
return sub ?? claims.email ?? claims.common_name;
|
|
7
|
-
};
|
|
4
|
+
const nonEmpty = (value) => typeof value === "string" && value.length > 0 ? value : void 0;
|
|
5
|
+
const deriveUserId = (claims) => nonEmpty(claims.sub) ?? nonEmpty(claims.email) ?? nonEmpty(claims.common_name);
|
|
8
6
|
const toIdentity = (claims, mapClaims) => {
|
|
9
7
|
const overrides = mapClaims?.(claims) ?? {};
|
|
10
|
-
const userId =
|
|
8
|
+
const userId = nonEmpty(overrides.userId) ?? deriveUserId(claims);
|
|
11
9
|
if (userId === void 0) {
|
|
12
10
|
return ANONYMOUS;
|
|
13
11
|
}
|
|
@@ -21,9 +19,12 @@ const toIdentity = (claims, mapClaims) => {
|
|
|
21
19
|
userId
|
|
22
20
|
};
|
|
23
21
|
};
|
|
24
|
-
const createAccessResolver = (options) =>
|
|
25
|
-
|
|
26
|
-
return
|
|
22
|
+
const createAccessResolver = (options) => {
|
|
23
|
+
assertVerifyOptions(options);
|
|
24
|
+
return async (request) => {
|
|
25
|
+
const claims = await verifyRequest(request, options);
|
|
26
|
+
return claims === void 0 ? ANONYMOUS : toIdentity(claims, options.mapClaims);
|
|
27
|
+
};
|
|
27
28
|
};
|
|
28
29
|
const composeResolvers = (...resolvers) => async (request, env) => {
|
|
29
30
|
for (const resolve of resolvers) {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const readIdentityGroups = (identity) => {
|
|
2
|
+
const { access } = identity;
|
|
3
|
+
const nested = typeof access === "object" && access !== null ? access.groups : void 0;
|
|
4
|
+
const groups = identity["groups"] ?? nested;
|
|
5
|
+
return Array.isArray(groups) ? groups.filter((group) => typeof group === "string") : void 0;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export { readIdentityGroups as r };
|
package/dist/roles.mjs
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const nested = typeof access === "object" && access !== null ? access.groups : void 0;
|
|
4
|
-
const groups = identity["groups"] ?? nested;
|
|
5
|
-
return Array.isArray(groups) ? groups.filter((group) => typeof group === "string") : void 0;
|
|
6
|
-
};
|
|
1
|
+
import { r as readIdentityGroups } from './packem_shared/identity-groups-CONuLY61.mjs';
|
|
2
|
+
|
|
7
3
|
const rolesForGroup = (group, map) => {
|
|
8
4
|
if (map === void 0) {
|
|
9
5
|
return [group];
|
|
@@ -15,7 +11,7 @@ const rolesForGroup = (group, map) => {
|
|
|
15
11
|
return Array.isArray(resolved) ? resolved : [resolved];
|
|
16
12
|
};
|
|
17
13
|
const accessRoles = (options = {}) => {
|
|
18
|
-
const readGroups = options.readGroups ??
|
|
14
|
+
const readGroups = options.readGroups ?? readIdentityGroups;
|
|
19
15
|
return async ({ ctx, next }) => {
|
|
20
16
|
const identity = await ctx.auth?.getIdentity?.() ?? void 0;
|
|
21
17
|
const groups = identity ? readGroups(identity) : void 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/cloudflare-access",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.22",
|
|
4
4
|
"description": "Cloudflare Access (Zero Trust) identity for Lunora — verify the Cf-Access-Jwt-Assertion JWT against your team JWKS and feed the verified identity into ctx.auth / RLS via a resolveIdentity adapter",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"access",
|
|
@@ -54,11 +54,11 @@
|
|
|
54
54
|
"access": "public"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@lunora/errors": "1.0.0-alpha.
|
|
57
|
+
"@lunora/errors": "1.0.0-alpha.4",
|
|
58
58
|
"jose": "^6.2.3"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
|
61
|
-
"@lunora/server": "1.0.0-alpha.
|
|
61
|
+
"@lunora/server": "1.0.0-alpha.24"
|
|
62
62
|
},
|
|
63
63
|
"peerDependenciesMeta": {
|
|
64
64
|
"@lunora/server": {
|