From 9f7fe48ee46f7c7b6b7205399a49621d7ba8a894 Mon Sep 17 00:00:00 2001 From: Matt Provost Date: Wed, 25 Mar 2026 16:19:06 +0000 Subject: [PATCH 1/3] feat: add AccessContext types Signed-off-by: Matt Provost --- src/workerd/api/global-scope.h | 4 ++++ types/defines/access.d.ts | 23 +++++++++++++++++++ .../experimental/index.d.ts | 22 ++++++++++++++++++ .../generated-snapshot/experimental/index.ts | 22 ++++++++++++++++++ types/generated-snapshot/latest/index.d.ts | 22 ++++++++++++++++++ types/generated-snapshot/latest/index.ts | 22 ++++++++++++++++++ 6 files changed, 115 insertions(+) create mode 100644 types/defines/access.d.ts diff --git a/src/workerd/api/global-scope.h b/src/workerd/api/global-scope.h index ffaf66fac9e..174ea82b827 100644 --- a/src/workerd/api/global-scope.h +++ b/src/workerd/api/global-scope.h @@ -276,11 +276,13 @@ class ExecutionContext: public jsg::Object { readonly key?: string; readonly override?: string; }; + readonly access?: AccessContext; }); } else { JSG_TS_OVERRIDE( { readonly props: Props; readonly exports: Cloudflare.Exports; + readonly access?: AccessContext; }); } } else { @@ -293,10 +295,12 @@ class ExecutionContext: public jsg::Object { readonly key?: string; readonly override?: string; }; + readonly access?: AccessContext; }); } else { JSG_TS_OVERRIDE( { readonly props: Props; + readonly access?: AccessContext; }); } } diff --git a/types/defines/access.d.ts b/types/defines/access.d.ts new file mode 100644 index 00000000000..818d9541baa --- /dev/null +++ b/types/defines/access.d.ts @@ -0,0 +1,23 @@ +/** + * Represents the identity of a user authenticated via Cloudflare Access. + * This matches the result of calling /cdn-cgi/access/get-identity. + */ +type Identity = object; + +/** + * Cloudflare Access authentication information for the current request. + */ +interface AccessContext { + /** + * The audience claim from the Access JWT. This identifies which Access + * application the request matched. + */ + readonly aud: string; + + /** + * Fetches the full identity information for the authenticated user. + * + * @returns The subject's identity, if one exists + */ + getIdentity(): Promise; +} diff --git a/types/generated-snapshot/experimental/index.d.ts b/types/generated-snapshot/experimental/index.d.ts index 0d465249549..ce726495bd5 100755 --- a/types/generated-snapshot/experimental/index.d.ts +++ b/types/generated-snapshot/experimental/index.d.ts @@ -501,6 +501,7 @@ interface ExecutionContext { readonly override?: string; }; abort(reason?: any): void; + readonly access?: AccessContext; } type ExportedHandlerFetchHandler< Env = unknown, @@ -4683,6 +4684,27 @@ interface EventCounts { ): void; [Symbol.iterator](): IterableIterator; } +/** + * Represents the identity of a user authenticated via Cloudflare Access. + * This matches the result of calling /cdn-cgi/access/get-identity. + */ +type Identity = object; +/** + * Cloudflare Access authentication information for the current request. + */ +interface AccessContext { + /** + * The audience claim from the Access JWT. This identifies which Access + * application the request matched. + */ + readonly aud: string; + /** + * Fetches the full identity information for the authenticated user. + * + * @returns The subject's identity, if one exists + */ + getIdentity(): Promise; +} // ============ AI Search Error Interfaces ============ interface AiSearchInternalError extends Error {} interface AiSearchNotFoundError extends Error {} diff --git a/types/generated-snapshot/experimental/index.ts b/types/generated-snapshot/experimental/index.ts index f29bd13ac03..b0c8a3584eb 100755 --- a/types/generated-snapshot/experimental/index.ts +++ b/types/generated-snapshot/experimental/index.ts @@ -503,6 +503,7 @@ export interface ExecutionContext { readonly override?: string; }; abort(reason?: any): void; + readonly access?: AccessContext; } export type ExportedHandlerFetchHandler< Env = unknown, @@ -4689,6 +4690,27 @@ export interface EventCounts { ): void; [Symbol.iterator](): IterableIterator; } +/** + * Represents the identity of a user authenticated via Cloudflare Access. + * This matches the result of calling /cdn-cgi/access/get-identity. + */ +export type Identity = object; +/** + * Cloudflare Access authentication information for the current request. + */ +export interface AccessContext { + /** + * The audience claim from the Access JWT. This identifies which Access + * application the request matched. + */ + readonly aud: string; + /** + * Fetches the full identity information for the authenticated user. + * + * @returns The subject's identity, if one exists + */ + getIdentity(): Promise; +} // ============ AI Search Error Interfaces ============ export interface AiSearchInternalError extends Error {} export interface AiSearchNotFoundError extends Error {} diff --git a/types/generated-snapshot/latest/index.d.ts b/types/generated-snapshot/latest/index.d.ts index d7a249b33c8..cc6b6d0bb58 100755 --- a/types/generated-snapshot/latest/index.d.ts +++ b/types/generated-snapshot/latest/index.d.ts @@ -479,6 +479,7 @@ interface ExecutionContext { passThroughOnException(): void; readonly exports: Cloudflare.Exports; readonly props: Props; + readonly access?: AccessContext; } type ExportedHandlerFetchHandler< Env = unknown, @@ -3991,6 +3992,27 @@ declare abstract class Performance { */ toJSON(): object; } +/** + * Represents the identity of a user authenticated via Cloudflare Access. + * This matches the result of calling /cdn-cgi/access/get-identity. + */ +type Identity = object; +/** + * Cloudflare Access authentication information for the current request. + */ +interface AccessContext { + /** + * The audience claim from the Access JWT. This identifies which Access + * application the request matched. + */ + readonly aud: string; + /** + * Fetches the full identity information for the authenticated user. + * + * @returns The subject's identity, if one exists + */ + getIdentity(): Promise; +} // ============ AI Search Error Interfaces ============ interface AiSearchInternalError extends Error {} interface AiSearchNotFoundError extends Error {} diff --git a/types/generated-snapshot/latest/index.ts b/types/generated-snapshot/latest/index.ts index 343b5d5fd7d..8c2e93f8e1a 100755 --- a/types/generated-snapshot/latest/index.ts +++ b/types/generated-snapshot/latest/index.ts @@ -481,6 +481,7 @@ export interface ExecutionContext { passThroughOnException(): void; readonly exports: Cloudflare.Exports; readonly props: Props; + readonly access?: AccessContext; } export type ExportedHandlerFetchHandler< Env = unknown, @@ -3997,6 +3998,27 @@ export declare abstract class Performance { */ toJSON(): object; } +/** + * Represents the identity of a user authenticated via Cloudflare Access. + * This matches the result of calling /cdn-cgi/access/get-identity. + */ +export type Identity = object; +/** + * Cloudflare Access authentication information for the current request. + */ +export interface AccessContext { + /** + * The audience claim from the Access JWT. This identifies which Access + * application the request matched. + */ + readonly aud: string; + /** + * Fetches the full identity information for the authenticated user. + * + * @returns The subject's identity, if one exists + */ + getIdentity(): Promise; +} // ============ AI Search Error Interfaces ============ export interface AiSearchInternalError extends Error {} export interface AiSearchNotFoundError extends Error {} From 34c0c6b0d60168c081c9557c92d14bc7697420df Mon Sep 17 00:00:00 2001 From: Matt Provost Date: Tue, 31 Mar 2026 21:17:13 +0000 Subject: [PATCH 2/3] chore: update names Signed-off-by: Matt Provost --- src/workerd/api/global-scope.h | 27 ++++++++++++++++--- src/workerd/io/compatibility-date.capnp | 9 +++++++ types/defines/access.d.ts | 6 ++--- .../experimental/index.d.ts | 8 +++--- .../generated-snapshot/experimental/index.ts | 8 +++--- types/generated-snapshot/latest/index.d.ts | 8 +++--- types/generated-snapshot/latest/index.ts | 8 +++--- 7 files changed, 51 insertions(+), 23 deletions(-) diff --git a/src/workerd/api/global-scope.h b/src/workerd/api/global-scope.h index 174ea82b827..2bd666aa6d5 100644 --- a/src/workerd/api/global-scope.h +++ b/src/workerd/api/global-scope.h @@ -239,6 +239,19 @@ class ExecutionContext: public jsg::Object { return js.undefined(); } + // Called by the host runtime to set the Access context for this request. + // Must be called before the worker's handler is invoked. + void setAccess(jsg::Lock& js, jsg::JsRef value) { + access = kj::mv(value); + } + + jsg::JsValue getAccess(jsg::Lock& js) { + KJ_IF_SOME(a, access) { + return a.getHandle(js); + } + return js.undefined(); + } + JSG_RESOURCE_TYPE(ExecutionContext, CompatibilityFlags::Reader flags) { JSG_METHOD(waitUntil); JSG_METHOD(passThroughOnException); @@ -249,6 +262,9 @@ class ExecutionContext: public jsg::Object { if (flags.getEnableVersionApi()) { JSG_LAZY_INSTANCE_PROPERTY(version, getVersion); } + if (flags.getEnableCtxAccess()) { + JSG_LAZY_INSTANCE_PROPERTY(access, getAccess); + } if (flags.getWorkerdExperimental()) { // TODO(soon): Before making this generally available we need to: @@ -276,13 +292,13 @@ class ExecutionContext: public jsg::Object { readonly key?: string; readonly override?: string; }; - readonly access?: AccessContext; + readonly access?: CloudflareAccessContext; }); } else { JSG_TS_OVERRIDE( { readonly props: Props; readonly exports: Cloudflare.Exports; - readonly access?: AccessContext; + readonly access?: CloudflareAccessContext; }); } } else { @@ -295,12 +311,12 @@ class ExecutionContext: public jsg::Object { readonly key?: string; readonly override?: string; }; - readonly access?: AccessContext; + readonly access?: CloudflareAccessContext; }); } else { JSG_TS_OVERRIDE( { readonly props: Props; - readonly access?: AccessContext; + readonly access?: CloudflareAccessContext; }); } } @@ -309,16 +325,19 @@ class ExecutionContext: public jsg::Object { void visitForMemoryInfo(jsg::MemoryTracker& tracker) const { tracker.trackField("props", props); tracker.trackField("version", version); + tracker.trackField("access", access); } private: jsg::JsRef exports; jsg::JsRef props; kj::Maybe> version; + kj::Maybe> access; void visitForGc(jsg::GcVisitor& visitor) { visitor.visit(props); visitor.visit(version); + visitor.visit(access); } }; diff --git a/src/workerd/io/compatibility-date.capnp b/src/workerd/io/compatibility-date.capnp index d3998c0794b..03477c9da14 100644 --- a/src/workerd/io/compatibility-date.capnp +++ b/src/workerd/io/compatibility-date.capnp @@ -1508,4 +1508,13 @@ struct CompatibilityFlags @0x8f8c1b68151b6cef { $compatDisableFlag("resizable_array_buffer_in_blob"); # When enabled, creating a Blob with a resizable ArrayBuffer will throw a TypeError, matching # expected spec behavior. + + enableCtxAccess @174 :Bool + $compatEnableFlag("enable_ctx_access") + $experimental; + # Enables the ctx.access property for Cloudflare Access integration. + # When enabled, ctx.access provides Access authentication context including the + # matched application audience (AUD) and an identity-fetching function. The value + # is set by the host runtime (edgeworker) per-request; in open-source workerd the + # property will always be undefined. } diff --git a/types/defines/access.d.ts b/types/defines/access.d.ts index 818d9541baa..c7442a09995 100644 --- a/types/defines/access.d.ts +++ b/types/defines/access.d.ts @@ -2,12 +2,12 @@ * Represents the identity of a user authenticated via Cloudflare Access. * This matches the result of calling /cdn-cgi/access/get-identity. */ -type Identity = object; +type CloudflareAccessIdentity = object; /** * Cloudflare Access authentication information for the current request. */ -interface AccessContext { +interface CloudflareAccessContext { /** * The audience claim from the Access JWT. This identifies which Access * application the request matched. @@ -19,5 +19,5 @@ interface AccessContext { * * @returns The subject's identity, if one exists */ - getIdentity(): Promise; + getIdentity(): Promise; } diff --git a/types/generated-snapshot/experimental/index.d.ts b/types/generated-snapshot/experimental/index.d.ts index ce726495bd5..d5a4941588f 100755 --- a/types/generated-snapshot/experimental/index.d.ts +++ b/types/generated-snapshot/experimental/index.d.ts @@ -501,7 +501,7 @@ interface ExecutionContext { readonly override?: string; }; abort(reason?: any): void; - readonly access?: AccessContext; + readonly access?: CloudflareAccessContext; } type ExportedHandlerFetchHandler< Env = unknown, @@ -4688,11 +4688,11 @@ interface EventCounts { * Represents the identity of a user authenticated via Cloudflare Access. * This matches the result of calling /cdn-cgi/access/get-identity. */ -type Identity = object; +type CloudflareAccessIdentity = object; /** * Cloudflare Access authentication information for the current request. */ -interface AccessContext { +interface CloudflareAccessContext { /** * The audience claim from the Access JWT. This identifies which Access * application the request matched. @@ -4703,7 +4703,7 @@ interface AccessContext { * * @returns The subject's identity, if one exists */ - getIdentity(): Promise; + getIdentity(): Promise; } // ============ AI Search Error Interfaces ============ interface AiSearchInternalError extends Error {} diff --git a/types/generated-snapshot/experimental/index.ts b/types/generated-snapshot/experimental/index.ts index b0c8a3584eb..4c2e1709fb7 100755 --- a/types/generated-snapshot/experimental/index.ts +++ b/types/generated-snapshot/experimental/index.ts @@ -503,7 +503,7 @@ export interface ExecutionContext { readonly override?: string; }; abort(reason?: any): void; - readonly access?: AccessContext; + readonly access?: CloudflareAccessContext; } export type ExportedHandlerFetchHandler< Env = unknown, @@ -4694,11 +4694,11 @@ export interface EventCounts { * Represents the identity of a user authenticated via Cloudflare Access. * This matches the result of calling /cdn-cgi/access/get-identity. */ -export type Identity = object; +export type CloudflareAccessIdentity = object; /** * Cloudflare Access authentication information for the current request. */ -export interface AccessContext { +export interface CloudflareAccessContext { /** * The audience claim from the Access JWT. This identifies which Access * application the request matched. @@ -4709,7 +4709,7 @@ export interface AccessContext { * * @returns The subject's identity, if one exists */ - getIdentity(): Promise; + getIdentity(): Promise; } // ============ AI Search Error Interfaces ============ export interface AiSearchInternalError extends Error {} diff --git a/types/generated-snapshot/latest/index.d.ts b/types/generated-snapshot/latest/index.d.ts index cc6b6d0bb58..d96ccdef2aa 100755 --- a/types/generated-snapshot/latest/index.d.ts +++ b/types/generated-snapshot/latest/index.d.ts @@ -479,7 +479,7 @@ interface ExecutionContext { passThroughOnException(): void; readonly exports: Cloudflare.Exports; readonly props: Props; - readonly access?: AccessContext; + readonly access?: CloudflareAccessContext; } type ExportedHandlerFetchHandler< Env = unknown, @@ -3996,11 +3996,11 @@ declare abstract class Performance { * Represents the identity of a user authenticated via Cloudflare Access. * This matches the result of calling /cdn-cgi/access/get-identity. */ -type Identity = object; +type CloudflareAccessIdentity = object; /** * Cloudflare Access authentication information for the current request. */ -interface AccessContext { +interface CloudflareAccessContext { /** * The audience claim from the Access JWT. This identifies which Access * application the request matched. @@ -4011,7 +4011,7 @@ interface AccessContext { * * @returns The subject's identity, if one exists */ - getIdentity(): Promise; + getIdentity(): Promise; } // ============ AI Search Error Interfaces ============ interface AiSearchInternalError extends Error {} diff --git a/types/generated-snapshot/latest/index.ts b/types/generated-snapshot/latest/index.ts index 8c2e93f8e1a..95583ac9928 100755 --- a/types/generated-snapshot/latest/index.ts +++ b/types/generated-snapshot/latest/index.ts @@ -481,7 +481,7 @@ export interface ExecutionContext { passThroughOnException(): void; readonly exports: Cloudflare.Exports; readonly props: Props; - readonly access?: AccessContext; + readonly access?: CloudflareAccessContext; } export type ExportedHandlerFetchHandler< Env = unknown, @@ -4002,11 +4002,11 @@ export declare abstract class Performance { * Represents the identity of a user authenticated via Cloudflare Access. * This matches the result of calling /cdn-cgi/access/get-identity. */ -export type Identity = object; +export type CloudflareAccessIdentity = object; /** * Cloudflare Access authentication information for the current request. */ -export interface AccessContext { +export interface CloudflareAccessContext { /** * The audience claim from the Access JWT. This identifies which Access * application the request matched. @@ -4017,7 +4017,7 @@ export interface AccessContext { * * @returns The subject's identity, if one exists */ - getIdentity(): Promise; + getIdentity(): Promise; } // ============ AI Search Error Interfaces ============ export interface AiSearchInternalError extends Error {} From 88c585f01fc687b2cf40532b34469d756e0d8e2c Mon Sep 17 00:00:00 2001 From: Matt Provost Date: Tue, 7 Apr 2026 23:40:43 +0000 Subject: [PATCH 3/3] chore: address comments Signed-off-by: Matt Provost --- src/workerd/api/global-scope.h | 13 ++++- src/workerd/api/tests/BUILD.bazel | 6 +++ src/workerd/api/tests/ctx-access-test.js | 11 +++++ src/workerd/api/tests/ctx-access-test.wd-test | 14 ++++++ types/defines/access.d.ts | 36 +++++++++++++- .../experimental/index.d.ts | 49 +++++++++++++++++-- .../generated-snapshot/experimental/index.ts | 49 +++++++++++++++++-- types/generated-snapshot/latest/index.d.ts | 45 ++++++++++++++++- types/generated-snapshot/latest/index.ts | 45 ++++++++++++++++- 9 files changed, 258 insertions(+), 10 deletions(-) create mode 100644 src/workerd/api/tests/ctx-access-test.js create mode 100644 src/workerd/api/tests/ctx-access-test.wd-test diff --git a/src/workerd/api/global-scope.h b/src/workerd/api/global-scope.h index 2bd666aa6d5..b4993060f66 100644 --- a/src/workerd/api/global-scope.h +++ b/src/workerd/api/global-scope.h @@ -239,8 +239,14 @@ class ExecutionContext: public jsg::Object { return js.undefined(); } - // Called by the host runtime to set the Access context for this request. + // Called by the host runtime (edgeworker) to set the Access context for this request. // Must be called before the worker's handler is invoked. + // + // Unlike other ExecutionContext fields (props, version, exports) which are injected through the + // constructor, access uses a post-construction setter because the Access context is assembled by + // the host runtime after ExecutionContext construction but before handler invocation. The access + // data (audience claim, identity fetcher) originates from the Cloudflare Access integration + // pipeline and is not available during ExecutionContext construction in edgeworker. void setAccess(jsg::Lock& js, jsg::JsRef value) { access = kj::mv(value); } @@ -281,6 +287,11 @@ class ExecutionContext: public jsg::Object { } // TODO(soon): This is getting unwieldy. + // Note: `access` is included unconditionally in all TS_OVERRIDE branches (unlike `version` + // which is gated by enableVersionApi). This is intentional — adding another conditional would + // double the branch count (from 4 to 8). Since `access` is optional (`?`), the type is + // correct regardless of whether the flag is enabled (the property will be undefined at runtime + // when the flag is off or when setAccess() hasn't been called). if (flags.getEnableCtxExports()) { if (flags.getEnableVersionApi()) { JSG_TS_OVERRIDE( { diff --git a/src/workerd/api/tests/BUILD.bazel b/src/workerd/api/tests/BUILD.bazel index 6312de1a723..bd1814ba39b 100644 --- a/src/workerd/api/tests/BUILD.bazel +++ b/src/workerd/api/tests/BUILD.bazel @@ -122,6 +122,12 @@ wd_test( args = ["--experimental"], ) +wd_test( + src = "ctx-access-test.wd-test", + args = ["--experimental"], + data = ["ctx-access-test.js"], +) + wd_test( src = "cache-test.wd-test", args = ["--experimental"], diff --git a/src/workerd/api/tests/ctx-access-test.js b/src/workerd/api/tests/ctx-access-test.js new file mode 100644 index 00000000000..587f5429993 --- /dev/null +++ b/src/workerd/api/tests/ctx-access-test.js @@ -0,0 +1,11 @@ +import { strictEqual } from 'node:assert'; + +export const ctxAccessPropertyExists = { + test(controller, env, ctx) { + // When enable_ctx_access is enabled, the property should exist on ctx + // (as a lazy instance property), even though its value is undefined + // because setAccess() is only called by the host runtime (edgeworker). + strictEqual('access' in ctx, true); + strictEqual(ctx.access, undefined); + }, +}; diff --git a/src/workerd/api/tests/ctx-access-test.wd-test b/src/workerd/api/tests/ctx-access-test.wd-test new file mode 100644 index 00000000000..578e5338703 --- /dev/null +++ b/src/workerd/api/tests/ctx-access-test.wd-test @@ -0,0 +1,14 @@ +using Workerd = import "/workerd/workerd.capnp"; + +const unitTests :Workerd.Config = ( + services = [ + ( name = "ctx-access-test", + worker = ( + modules = [ + (name = "worker", esModule = embed "ctx-access-test.js") + ], + compatibilityFlags = ["nodejs_compat", "experimental", "enable_ctx_access"], + ) + ), + ], +); diff --git a/types/defines/access.d.ts b/types/defines/access.d.ts index c7442a09995..18319ad6269 100644 --- a/types/defines/access.d.ts +++ b/types/defines/access.d.ts @@ -1,8 +1,39 @@ /** * Represents the identity of a user authenticated via Cloudflare Access. * This matches the result of calling /cdn-cgi/access/get-identity. + * + * The exact structure of the returned object depends on the identity provider + * configuration for the Access application. The fields below represent commonly + * available properties, but additional provider-specific fields may be present. */ -type CloudflareAccessIdentity = object; +interface CloudflareAccessIdentity extends Record { + /** The user's email address, if available from the identity provider. */ + email?: string; + /** The user's display name. */ + name?: string; + /** The user's unique identifier. */ + user_uuid?: string; + /** The Cloudflare account ID. */ + account_id?: string; + /** Login timestamp (Unix epoch seconds). */ + iat?: number; + /** The user's IP address at authentication time. */ + ip?: string; + /** Authentication methods used (e.g., "pwd"). */ + amr?: string[]; + /** Identity provider information. */ + idp?: { id: string; type: string }; + /** Geographic information about where the user authenticated. */ + geo?: { country: string }; + /** Group memberships from the identity provider. */ + groups?: Array<{ id: string; name: string; email?: string }>; + /** Device posture check results, keyed by check ID. */ + devicePosture?: Record; + /** True if the user connected via Cloudflare WARP. */ + is_warp?: boolean; + /** True if the user is authenticated via Cloudflare Gateway. */ + is_gateway?: boolean; +} /** * Cloudflare Access authentication information for the current request. @@ -16,8 +47,11 @@ interface CloudflareAccessContext { /** * Fetches the full identity information for the authenticated user. + * This makes a call to the Access identity service to retrieve extended + * user information such as groups, device posture, and identity provider data. * * @returns The subject's identity, if one exists + * @throws May throw if the identity service is unreachable or returns an error. */ getIdentity(): Promise; } diff --git a/types/generated-snapshot/experimental/index.d.ts b/types/generated-snapshot/experimental/index.d.ts index d5a4941588f..d529337a130 100755 --- a/types/generated-snapshot/experimental/index.d.ts +++ b/types/generated-snapshot/experimental/index.d.ts @@ -500,8 +500,8 @@ interface ExecutionContext { readonly key?: string; readonly override?: string; }; - abort(reason?: any): void; readonly access?: CloudflareAccessContext; + abort(reason?: any): void; } type ExportedHandlerFetchHandler< Env = unknown, @@ -4687,8 +4687,48 @@ interface EventCounts { /** * Represents the identity of a user authenticated via Cloudflare Access. * This matches the result of calling /cdn-cgi/access/get-identity. - */ -type CloudflareAccessIdentity = object; + * + * The exact structure of the returned object depends on the identity provider + * configuration for the Access application. The fields below represent commonly + * available properties, but additional provider-specific fields may be present. + */ +interface CloudflareAccessIdentity extends Record { + /** The user's email address, if available from the identity provider. */ + email?: string; + /** The user's display name. */ + name?: string; + /** The user's unique identifier. */ + user_uuid?: string; + /** The Cloudflare account ID. */ + account_id?: string; + /** Login timestamp (Unix epoch seconds). */ + iat?: number; + /** The user's IP address at authentication time. */ + ip?: string; + /** Authentication methods used (e.g., "pwd"). */ + amr?: string[]; + /** Identity provider information. */ + idp?: { + id: string; + type: string; + }; + /** Geographic information about where the user authenticated. */ + geo?: { + country: string; + }; + /** Group memberships from the identity provider. */ + groups?: Array<{ + id: string; + name: string; + email?: string; + }>; + /** Device posture check results, keyed by check ID. */ + devicePosture?: Record; + /** True if the user connected via Cloudflare WARP. */ + is_warp?: boolean; + /** True if the user is authenticated via Cloudflare Gateway. */ + is_gateway?: boolean; +} /** * Cloudflare Access authentication information for the current request. */ @@ -4700,8 +4740,11 @@ interface CloudflareAccessContext { readonly aud: string; /** * Fetches the full identity information for the authenticated user. + * This makes a call to the Access identity service to retrieve extended + * user information such as groups, device posture, and identity provider data. * * @returns The subject's identity, if one exists + * @throws May throw if the identity service is unreachable or returns an error. */ getIdentity(): Promise; } diff --git a/types/generated-snapshot/experimental/index.ts b/types/generated-snapshot/experimental/index.ts index 4c2e1709fb7..f9eaa744744 100755 --- a/types/generated-snapshot/experimental/index.ts +++ b/types/generated-snapshot/experimental/index.ts @@ -502,8 +502,8 @@ export interface ExecutionContext { readonly key?: string; readonly override?: string; }; - abort(reason?: any): void; readonly access?: CloudflareAccessContext; + abort(reason?: any): void; } export type ExportedHandlerFetchHandler< Env = unknown, @@ -4693,8 +4693,48 @@ export interface EventCounts { /** * Represents the identity of a user authenticated via Cloudflare Access. * This matches the result of calling /cdn-cgi/access/get-identity. - */ -export type CloudflareAccessIdentity = object; + * + * The exact structure of the returned object depends on the identity provider + * configuration for the Access application. The fields below represent commonly + * available properties, but additional provider-specific fields may be present. + */ +export interface CloudflareAccessIdentity extends Record { + /** The user's email address, if available from the identity provider. */ + email?: string; + /** The user's display name. */ + name?: string; + /** The user's unique identifier. */ + user_uuid?: string; + /** The Cloudflare account ID. */ + account_id?: string; + /** Login timestamp (Unix epoch seconds). */ + iat?: number; + /** The user's IP address at authentication time. */ + ip?: string; + /** Authentication methods used (e.g., "pwd"). */ + amr?: string[]; + /** Identity provider information. */ + idp?: { + id: string; + type: string; + }; + /** Geographic information about where the user authenticated. */ + geo?: { + country: string; + }; + /** Group memberships from the identity provider. */ + groups?: Array<{ + id: string; + name: string; + email?: string; + }>; + /** Device posture check results, keyed by check ID. */ + devicePosture?: Record; + /** True if the user connected via Cloudflare WARP. */ + is_warp?: boolean; + /** True if the user is authenticated via Cloudflare Gateway. */ + is_gateway?: boolean; +} /** * Cloudflare Access authentication information for the current request. */ @@ -4706,8 +4746,11 @@ export interface CloudflareAccessContext { readonly aud: string; /** * Fetches the full identity information for the authenticated user. + * This makes a call to the Access identity service to retrieve extended + * user information such as groups, device posture, and identity provider data. * * @returns The subject's identity, if one exists + * @throws May throw if the identity service is unreachable or returns an error. */ getIdentity(): Promise; } diff --git a/types/generated-snapshot/latest/index.d.ts b/types/generated-snapshot/latest/index.d.ts index d96ccdef2aa..9dc417dc87d 100755 --- a/types/generated-snapshot/latest/index.d.ts +++ b/types/generated-snapshot/latest/index.d.ts @@ -3995,8 +3995,48 @@ declare abstract class Performance { /** * Represents the identity of a user authenticated via Cloudflare Access. * This matches the result of calling /cdn-cgi/access/get-identity. + * + * The exact structure of the returned object depends on the identity provider + * configuration for the Access application. The fields below represent commonly + * available properties, but additional provider-specific fields may be present. */ -type CloudflareAccessIdentity = object; +interface CloudflareAccessIdentity extends Record { + /** The user's email address, if available from the identity provider. */ + email?: string; + /** The user's display name. */ + name?: string; + /** The user's unique identifier. */ + user_uuid?: string; + /** The Cloudflare account ID. */ + account_id?: string; + /** Login timestamp (Unix epoch seconds). */ + iat?: number; + /** The user's IP address at authentication time. */ + ip?: string; + /** Authentication methods used (e.g., "pwd"). */ + amr?: string[]; + /** Identity provider information. */ + idp?: { + id: string; + type: string; + }; + /** Geographic information about where the user authenticated. */ + geo?: { + country: string; + }; + /** Group memberships from the identity provider. */ + groups?: Array<{ + id: string; + name: string; + email?: string; + }>; + /** Device posture check results, keyed by check ID. */ + devicePosture?: Record; + /** True if the user connected via Cloudflare WARP. */ + is_warp?: boolean; + /** True if the user is authenticated via Cloudflare Gateway. */ + is_gateway?: boolean; +} /** * Cloudflare Access authentication information for the current request. */ @@ -4008,8 +4048,11 @@ interface CloudflareAccessContext { readonly aud: string; /** * Fetches the full identity information for the authenticated user. + * This makes a call to the Access identity service to retrieve extended + * user information such as groups, device posture, and identity provider data. * * @returns The subject's identity, if one exists + * @throws May throw if the identity service is unreachable or returns an error. */ getIdentity(): Promise; } diff --git a/types/generated-snapshot/latest/index.ts b/types/generated-snapshot/latest/index.ts index 95583ac9928..20f01485e39 100755 --- a/types/generated-snapshot/latest/index.ts +++ b/types/generated-snapshot/latest/index.ts @@ -4001,8 +4001,48 @@ export declare abstract class Performance { /** * Represents the identity of a user authenticated via Cloudflare Access. * This matches the result of calling /cdn-cgi/access/get-identity. + * + * The exact structure of the returned object depends on the identity provider + * configuration for the Access application. The fields below represent commonly + * available properties, but additional provider-specific fields may be present. */ -export type CloudflareAccessIdentity = object; +export interface CloudflareAccessIdentity extends Record { + /** The user's email address, if available from the identity provider. */ + email?: string; + /** The user's display name. */ + name?: string; + /** The user's unique identifier. */ + user_uuid?: string; + /** The Cloudflare account ID. */ + account_id?: string; + /** Login timestamp (Unix epoch seconds). */ + iat?: number; + /** The user's IP address at authentication time. */ + ip?: string; + /** Authentication methods used (e.g., "pwd"). */ + amr?: string[]; + /** Identity provider information. */ + idp?: { + id: string; + type: string; + }; + /** Geographic information about where the user authenticated. */ + geo?: { + country: string; + }; + /** Group memberships from the identity provider. */ + groups?: Array<{ + id: string; + name: string; + email?: string; + }>; + /** Device posture check results, keyed by check ID. */ + devicePosture?: Record; + /** True if the user connected via Cloudflare WARP. */ + is_warp?: boolean; + /** True if the user is authenticated via Cloudflare Gateway. */ + is_gateway?: boolean; +} /** * Cloudflare Access authentication information for the current request. */ @@ -4014,8 +4054,11 @@ export interface CloudflareAccessContext { readonly aud: string; /** * Fetches the full identity information for the authenticated user. + * This makes a call to the Access identity service to retrieve extended + * user information such as groups, device posture, and identity provider data. * * @returns The subject's identity, if one exists + * @throws May throw if the identity service is unreachable or returns an error. */ getIdentity(): Promise; }