Skip to content

Commit 88c585f

Browse files
committed
chore: address comments
Signed-off-by: Matt Provost <[email protected]>
1 parent 34c0c6b commit 88c585f

9 files changed

Lines changed: 258 additions & 10 deletions

File tree

src/workerd/api/global-scope.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,14 @@ class ExecutionContext: public jsg::Object {
239239
return js.undefined();
240240
}
241241

242-
// Called by the host runtime to set the Access context for this request.
242+
// Called by the host runtime (edgeworker) to set the Access context for this request.
243243
// Must be called before the worker's handler is invoked.
244+
//
245+
// Unlike other ExecutionContext fields (props, version, exports) which are injected through the
246+
// constructor, access uses a post-construction setter because the Access context is assembled by
247+
// the host runtime after ExecutionContext construction but before handler invocation. The access
248+
// data (audience claim, identity fetcher) originates from the Cloudflare Access integration
249+
// pipeline and is not available during ExecutionContext construction in edgeworker.
244250
void setAccess(jsg::Lock& js, jsg::JsRef<jsg::JsValue> value) {
245251
access = kj::mv(value);
246252
}
@@ -281,6 +287,11 @@ class ExecutionContext: public jsg::Object {
281287
}
282288

283289
// TODO(soon): This is getting unwieldy.
290+
// Note: `access` is included unconditionally in all TS_OVERRIDE branches (unlike `version`
291+
// which is gated by enableVersionApi). This is intentional — adding another conditional would
292+
// double the branch count (from 4 to 8). Since `access` is optional (`?`), the type is
293+
// correct regardless of whether the flag is enabled (the property will be undefined at runtime
294+
// when the flag is off or when setAccess() hasn't been called).
284295
if (flags.getEnableCtxExports()) {
285296
if (flags.getEnableVersionApi()) {
286297
JSG_TS_OVERRIDE(<Props = unknown> {

src/workerd/api/tests/BUILD.bazel

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,12 @@ wd_test(
122122
args = ["--experimental"],
123123
)
124124

125+
wd_test(
126+
src = "ctx-access-test.wd-test",
127+
args = ["--experimental"],
128+
data = ["ctx-access-test.js"],
129+
)
130+
125131
wd_test(
126132
src = "cache-test.wd-test",
127133
args = ["--experimental"],
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { strictEqual } from 'node:assert';
2+
3+
export const ctxAccessPropertyExists = {
4+
test(controller, env, ctx) {
5+
// When enable_ctx_access is enabled, the property should exist on ctx
6+
// (as a lazy instance property), even though its value is undefined
7+
// because setAccess() is only called by the host runtime (edgeworker).
8+
strictEqual('access' in ctx, true);
9+
strictEqual(ctx.access, undefined);
10+
},
11+
};
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
using Workerd = import "/workerd/workerd.capnp";
2+
3+
const unitTests :Workerd.Config = (
4+
services = [
5+
( name = "ctx-access-test",
6+
worker = (
7+
modules = [
8+
(name = "worker", esModule = embed "ctx-access-test.js")
9+
],
10+
compatibilityFlags = ["nodejs_compat", "experimental", "enable_ctx_access"],
11+
)
12+
),
13+
],
14+
);

types/defines/access.d.ts

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,39 @@
11
/**
22
* Represents the identity of a user authenticated via Cloudflare Access.
33
* This matches the result of calling /cdn-cgi/access/get-identity.
4+
*
5+
* The exact structure of the returned object depends on the identity provider
6+
* configuration for the Access application. The fields below represent commonly
7+
* available properties, but additional provider-specific fields may be present.
48
*/
5-
type CloudflareAccessIdentity = object;
9+
interface CloudflareAccessIdentity extends Record<string, unknown> {
10+
/** The user's email address, if available from the identity provider. */
11+
email?: string;
12+
/** The user's display name. */
13+
name?: string;
14+
/** The user's unique identifier. */
15+
user_uuid?: string;
16+
/** The Cloudflare account ID. */
17+
account_id?: string;
18+
/** Login timestamp (Unix epoch seconds). */
19+
iat?: number;
20+
/** The user's IP address at authentication time. */
21+
ip?: string;
22+
/** Authentication methods used (e.g., "pwd"). */
23+
amr?: string[];
24+
/** Identity provider information. */
25+
idp?: { id: string; type: string };
26+
/** Geographic information about where the user authenticated. */
27+
geo?: { country: string };
28+
/** Group memberships from the identity provider. */
29+
groups?: Array<{ id: string; name: string; email?: string }>;
30+
/** Device posture check results, keyed by check ID. */
31+
devicePosture?: Record<string, unknown>;
32+
/** True if the user connected via Cloudflare WARP. */
33+
is_warp?: boolean;
34+
/** True if the user is authenticated via Cloudflare Gateway. */
35+
is_gateway?: boolean;
36+
}
637

738
/**
839
* Cloudflare Access authentication information for the current request.
@@ -16,8 +47,11 @@ interface CloudflareAccessContext {
1647

1748
/**
1849
* Fetches the full identity information for the authenticated user.
50+
* This makes a call to the Access identity service to retrieve extended
51+
* user information such as groups, device posture, and identity provider data.
1952
*
2053
* @returns The subject's identity, if one exists
54+
* @throws May throw if the identity service is unreachable or returns an error.
2155
*/
2256
getIdentity(): Promise<CloudflareAccessIdentity | undefined>;
2357
}

types/generated-snapshot/experimental/index.d.ts

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -500,8 +500,8 @@ interface ExecutionContext<Props = unknown> {
500500
readonly key?: string;
501501
readonly override?: string;
502502
};
503-
abort(reason?: any): void;
504503
readonly access?: CloudflareAccessContext;
504+
abort(reason?: any): void;
505505
}
506506
type ExportedHandlerFetchHandler<
507507
Env = unknown,
@@ -4687,8 +4687,48 @@ interface EventCounts {
46874687
/**
46884688
* Represents the identity of a user authenticated via Cloudflare Access.
46894689
* This matches the result of calling /cdn-cgi/access/get-identity.
4690-
*/
4691-
type CloudflareAccessIdentity = object;
4690+
*
4691+
* The exact structure of the returned object depends on the identity provider
4692+
* configuration for the Access application. The fields below represent commonly
4693+
* available properties, but additional provider-specific fields may be present.
4694+
*/
4695+
interface CloudflareAccessIdentity extends Record<string, unknown> {
4696+
/** The user's email address, if available from the identity provider. */
4697+
email?: string;
4698+
/** The user's display name. */
4699+
name?: string;
4700+
/** The user's unique identifier. */
4701+
user_uuid?: string;
4702+
/** The Cloudflare account ID. */
4703+
account_id?: string;
4704+
/** Login timestamp (Unix epoch seconds). */
4705+
iat?: number;
4706+
/** The user's IP address at authentication time. */
4707+
ip?: string;
4708+
/** Authentication methods used (e.g., "pwd"). */
4709+
amr?: string[];
4710+
/** Identity provider information. */
4711+
idp?: {
4712+
id: string;
4713+
type: string;
4714+
};
4715+
/** Geographic information about where the user authenticated. */
4716+
geo?: {
4717+
country: string;
4718+
};
4719+
/** Group memberships from the identity provider. */
4720+
groups?: Array<{
4721+
id: string;
4722+
name: string;
4723+
email?: string;
4724+
}>;
4725+
/** Device posture check results, keyed by check ID. */
4726+
devicePosture?: Record<string, unknown>;
4727+
/** True if the user connected via Cloudflare WARP. */
4728+
is_warp?: boolean;
4729+
/** True if the user is authenticated via Cloudflare Gateway. */
4730+
is_gateway?: boolean;
4731+
}
46924732
/**
46934733
* Cloudflare Access authentication information for the current request.
46944734
*/
@@ -4700,8 +4740,11 @@ interface CloudflareAccessContext {
47004740
readonly aud: string;
47014741
/**
47024742
* Fetches the full identity information for the authenticated user.
4743+
* This makes a call to the Access identity service to retrieve extended
4744+
* user information such as groups, device posture, and identity provider data.
47034745
*
47044746
* @returns The subject's identity, if one exists
4747+
* @throws May throw if the identity service is unreachable or returns an error.
47054748
*/
47064749
getIdentity(): Promise<CloudflareAccessIdentity | undefined>;
47074750
}

types/generated-snapshot/experimental/index.ts

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -502,8 +502,8 @@ export interface ExecutionContext<Props = unknown> {
502502
readonly key?: string;
503503
readonly override?: string;
504504
};
505-
abort(reason?: any): void;
506505
readonly access?: CloudflareAccessContext;
506+
abort(reason?: any): void;
507507
}
508508
export type ExportedHandlerFetchHandler<
509509
Env = unknown,
@@ -4693,8 +4693,48 @@ export interface EventCounts {
46934693
/**
46944694
* Represents the identity of a user authenticated via Cloudflare Access.
46954695
* This matches the result of calling /cdn-cgi/access/get-identity.
4696-
*/
4697-
export type CloudflareAccessIdentity = object;
4696+
*
4697+
* The exact structure of the returned object depends on the identity provider
4698+
* configuration for the Access application. The fields below represent commonly
4699+
* available properties, but additional provider-specific fields may be present.
4700+
*/
4701+
export interface CloudflareAccessIdentity extends Record<string, unknown> {
4702+
/** The user's email address, if available from the identity provider. */
4703+
email?: string;
4704+
/** The user's display name. */
4705+
name?: string;
4706+
/** The user's unique identifier. */
4707+
user_uuid?: string;
4708+
/** The Cloudflare account ID. */
4709+
account_id?: string;
4710+
/** Login timestamp (Unix epoch seconds). */
4711+
iat?: number;
4712+
/** The user's IP address at authentication time. */
4713+
ip?: string;
4714+
/** Authentication methods used (e.g., "pwd"). */
4715+
amr?: string[];
4716+
/** Identity provider information. */
4717+
idp?: {
4718+
id: string;
4719+
type: string;
4720+
};
4721+
/** Geographic information about where the user authenticated. */
4722+
geo?: {
4723+
country: string;
4724+
};
4725+
/** Group memberships from the identity provider. */
4726+
groups?: Array<{
4727+
id: string;
4728+
name: string;
4729+
email?: string;
4730+
}>;
4731+
/** Device posture check results, keyed by check ID. */
4732+
devicePosture?: Record<string, unknown>;
4733+
/** True if the user connected via Cloudflare WARP. */
4734+
is_warp?: boolean;
4735+
/** True if the user is authenticated via Cloudflare Gateway. */
4736+
is_gateway?: boolean;
4737+
}
46984738
/**
46994739
* Cloudflare Access authentication information for the current request.
47004740
*/
@@ -4706,8 +4746,11 @@ export interface CloudflareAccessContext {
47064746
readonly aud: string;
47074747
/**
47084748
* Fetches the full identity information for the authenticated user.
4749+
* This makes a call to the Access identity service to retrieve extended
4750+
* user information such as groups, device posture, and identity provider data.
47094751
*
47104752
* @returns The subject's identity, if one exists
4753+
* @throws May throw if the identity service is unreachable or returns an error.
47114754
*/
47124755
getIdentity(): Promise<CloudflareAccessIdentity | undefined>;
47134756
}

types/generated-snapshot/latest/index.d.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3995,8 +3995,48 @@ declare abstract class Performance {
39953995
/**
39963996
* Represents the identity of a user authenticated via Cloudflare Access.
39973997
* This matches the result of calling /cdn-cgi/access/get-identity.
3998+
*
3999+
* The exact structure of the returned object depends on the identity provider
4000+
* configuration for the Access application. The fields below represent commonly
4001+
* available properties, but additional provider-specific fields may be present.
39984002
*/
3999-
type CloudflareAccessIdentity = object;
4003+
interface CloudflareAccessIdentity extends Record<string, unknown> {
4004+
/** The user's email address, if available from the identity provider. */
4005+
email?: string;
4006+
/** The user's display name. */
4007+
name?: string;
4008+
/** The user's unique identifier. */
4009+
user_uuid?: string;
4010+
/** The Cloudflare account ID. */
4011+
account_id?: string;
4012+
/** Login timestamp (Unix epoch seconds). */
4013+
iat?: number;
4014+
/** The user's IP address at authentication time. */
4015+
ip?: string;
4016+
/** Authentication methods used (e.g., "pwd"). */
4017+
amr?: string[];
4018+
/** Identity provider information. */
4019+
idp?: {
4020+
id: string;
4021+
type: string;
4022+
};
4023+
/** Geographic information about where the user authenticated. */
4024+
geo?: {
4025+
country: string;
4026+
};
4027+
/** Group memberships from the identity provider. */
4028+
groups?: Array<{
4029+
id: string;
4030+
name: string;
4031+
email?: string;
4032+
}>;
4033+
/** Device posture check results, keyed by check ID. */
4034+
devicePosture?: Record<string, unknown>;
4035+
/** True if the user connected via Cloudflare WARP. */
4036+
is_warp?: boolean;
4037+
/** True if the user is authenticated via Cloudflare Gateway. */
4038+
is_gateway?: boolean;
4039+
}
40004040
/**
40014041
* Cloudflare Access authentication information for the current request.
40024042
*/
@@ -4008,8 +4048,11 @@ interface CloudflareAccessContext {
40084048
readonly aud: string;
40094049
/**
40104050
* Fetches the full identity information for the authenticated user.
4051+
* This makes a call to the Access identity service to retrieve extended
4052+
* user information such as groups, device posture, and identity provider data.
40114053
*
40124054
* @returns The subject's identity, if one exists
4055+
* @throws May throw if the identity service is unreachable or returns an error.
40134056
*/
40144057
getIdentity(): Promise<CloudflareAccessIdentity | undefined>;
40154058
}

types/generated-snapshot/latest/index.ts

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4001,8 +4001,48 @@ export declare abstract class Performance {
40014001
/**
40024002
* Represents the identity of a user authenticated via Cloudflare Access.
40034003
* This matches the result of calling /cdn-cgi/access/get-identity.
4004+
*
4005+
* The exact structure of the returned object depends on the identity provider
4006+
* configuration for the Access application. The fields below represent commonly
4007+
* available properties, but additional provider-specific fields may be present.
40044008
*/
4005-
export type CloudflareAccessIdentity = object;
4009+
export interface CloudflareAccessIdentity extends Record<string, unknown> {
4010+
/** The user's email address, if available from the identity provider. */
4011+
email?: string;
4012+
/** The user's display name. */
4013+
name?: string;
4014+
/** The user's unique identifier. */
4015+
user_uuid?: string;
4016+
/** The Cloudflare account ID. */
4017+
account_id?: string;
4018+
/** Login timestamp (Unix epoch seconds). */
4019+
iat?: number;
4020+
/** The user's IP address at authentication time. */
4021+
ip?: string;
4022+
/** Authentication methods used (e.g., "pwd"). */
4023+
amr?: string[];
4024+
/** Identity provider information. */
4025+
idp?: {
4026+
id: string;
4027+
type: string;
4028+
};
4029+
/** Geographic information about where the user authenticated. */
4030+
geo?: {
4031+
country: string;
4032+
};
4033+
/** Group memberships from the identity provider. */
4034+
groups?: Array<{
4035+
id: string;
4036+
name: string;
4037+
email?: string;
4038+
}>;
4039+
/** Device posture check results, keyed by check ID. */
4040+
devicePosture?: Record<string, unknown>;
4041+
/** True if the user connected via Cloudflare WARP. */
4042+
is_warp?: boolean;
4043+
/** True if the user is authenticated via Cloudflare Gateway. */
4044+
is_gateway?: boolean;
4045+
}
40064046
/**
40074047
* Cloudflare Access authentication information for the current request.
40084048
*/
@@ -4014,8 +4054,11 @@ export interface CloudflareAccessContext {
40144054
readonly aud: string;
40154055
/**
40164056
* Fetches the full identity information for the authenticated user.
4057+
* This makes a call to the Access identity service to retrieve extended
4058+
* user information such as groups, device posture, and identity provider data.
40174059
*
40184060
* @returns The subject's identity, if one exists
4061+
* @throws May throw if the identity service is unreachable or returns an error.
40194062
*/
40204063
getIdentity(): Promise<CloudflareAccessIdentity | undefined>;
40214064
}

0 commit comments

Comments
 (0)