alchemy 0.93.4 → 0.93.7
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/bin/alchemy.js +1966 -1825
- package/bin/alchemy.ts +2 -0
- package/bin/commands/state.ts +58 -0
- package/bin/services/execute-alchemy.ts +9 -1
- package/lib/alchemy.d.ts.map +1 -1
- package/lib/alchemy.js +7 -0
- package/lib/alchemy.js.map +1 -1
- package/lib/cloudflare/access-application.d.ts +204 -0
- package/lib/cloudflare/access-application.d.ts.map +1 -0
- package/lib/cloudflare/access-application.js +205 -0
- package/lib/cloudflare/access-application.js.map +1 -0
- package/lib/cloudflare/access-group.d.ts +115 -0
- package/lib/cloudflare/access-group.d.ts.map +1 -0
- package/lib/cloudflare/access-group.js +147 -0
- package/lib/cloudflare/access-group.js.map +1 -0
- package/lib/cloudflare/access-identity-provider.d.ts +261 -0
- package/lib/cloudflare/access-identity-provider.d.ts.map +1 -0
- package/lib/cloudflare/access-identity-provider.js +229 -0
- package/lib/cloudflare/access-identity-provider.js.map +1 -0
- package/lib/cloudflare/access-policy.d.ts +168 -0
- package/lib/cloudflare/access-policy.d.ts.map +1 -0
- package/lib/cloudflare/access-policy.js +176 -0
- package/lib/cloudflare/access-policy.js.map +1 -0
- package/lib/cloudflare/access-rule.d.ts +248 -0
- package/lib/cloudflare/access-rule.d.ts.map +1 -0
- package/lib/cloudflare/access-rule.js +37 -0
- package/lib/cloudflare/access-rule.js.map +1 -0
- package/lib/cloudflare/access-service-token.d.ts +86 -0
- package/lib/cloudflare/access-service-token.d.ts.map +1 -0
- package/lib/cloudflare/access-service-token.js +127 -0
- package/lib/cloudflare/access-service-token.js.map +1 -0
- package/lib/cloudflare/index.d.ts +6 -0
- package/lib/cloudflare/index.d.ts.map +1 -1
- package/lib/cloudflare/index.js +6 -0
- package/lib/cloudflare/index.js.map +1 -1
- package/lib/cloudflare/miniflare/build-worker-options.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/build-worker-options.js +17 -3
- package/lib/cloudflare/miniflare/build-worker-options.js.map +1 -1
- package/lib/state/file-system-state-store.d.ts +1 -0
- package/lib/state/file-system-state-store.d.ts.map +1 -1
- package/lib/state/file-system-state-store.js +16 -0
- package/lib/state/file-system-state-store.js.map +1 -1
- package/lib/state/operations.d.ts +1 -0
- package/lib/state/operations.d.ts.map +1 -1
- package/lib/state/operations.js +24 -0
- package/lib/state/operations.js.map +1 -1
- package/lib/state/proxy.d.ts +1 -0
- package/lib/state/proxy.d.ts.map +1 -1
- package/lib/state/proxy.js +3 -0
- package/lib/state/proxy.js.map +1 -1
- package/lib/state-cli.d.ts +9 -0
- package/lib/state-cli.d.ts.map +1 -0
- package/lib/state-cli.js +110 -0
- package/lib/state-cli.js.map +1 -0
- package/lib/state.d.ts +2 -0
- package/lib/state.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/alchemy.ts +9 -0
- package/src/cloudflare/access-application.ts +489 -0
- package/src/cloudflare/access-group.ts +271 -0
- package/src/cloudflare/access-identity-provider.ts +584 -0
- package/src/cloudflare/access-policy.ts +392 -0
- package/src/cloudflare/access-rule.ts +307 -0
- package/src/cloudflare/access-service-token.ts +255 -0
- package/src/cloudflare/index.ts +6 -0
- package/src/cloudflare/miniflare/build-worker-options.ts +20 -3
- package/src/state/file-system-state-store.ts +16 -0
- package/src/state/operations.ts +22 -0
- package/src/state/proxy.ts +4 -0
- package/src/state-cli.ts +134 -0
- package/src/state.ts +2 -0
- package/workers/cloudflare-state-store.js +17 -0
- package/workers/tunnel-proxy.js +1 -1
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { Context } from "../context.ts";
|
|
2
|
+
import { type AccessRule } from "./access-rule.ts";
|
|
3
|
+
import { type CloudflareApiOptions } from "./api.ts";
|
|
4
|
+
/**
|
|
5
|
+
* Properties for creating or updating an {@link AccessGroup}.
|
|
6
|
+
*/
|
|
7
|
+
export interface AccessGroupProps extends CloudflareApiOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Display name of the group.
|
|
10
|
+
*
|
|
11
|
+
* @default ${app}-${stage}-${id}
|
|
12
|
+
*/
|
|
13
|
+
name?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Rules that grant membership (OR logic — any match includes the user).
|
|
16
|
+
*/
|
|
17
|
+
include?: AccessRule[];
|
|
18
|
+
/**
|
|
19
|
+
* Rules that revoke membership when matched.
|
|
20
|
+
*/
|
|
21
|
+
exclude?: AccessRule[];
|
|
22
|
+
/**
|
|
23
|
+
* Rules that must additionally match for membership (AND logic).
|
|
24
|
+
*/
|
|
25
|
+
require?: AccessRule[];
|
|
26
|
+
/**
|
|
27
|
+
* Mark this group as the account default. Default groups apply to every
|
|
28
|
+
* Access application unless explicitly overridden.
|
|
29
|
+
*
|
|
30
|
+
* @default false
|
|
31
|
+
*/
|
|
32
|
+
isDefault?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Adopt an existing group with the same name instead of failing.
|
|
35
|
+
*
|
|
36
|
+
* @default false
|
|
37
|
+
*/
|
|
38
|
+
adopt?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Whether to delete the group when removed from Alchemy.
|
|
41
|
+
*
|
|
42
|
+
* @default true
|
|
43
|
+
*/
|
|
44
|
+
delete?: boolean;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Output for an {@link AccessGroup}.
|
|
48
|
+
*/
|
|
49
|
+
export type AccessGroup = Omit<AccessGroupProps, "adopt" | "delete"> & {
|
|
50
|
+
/** Cloudflare-assigned group UUID. */
|
|
51
|
+
id: string;
|
|
52
|
+
/** Display name. */
|
|
53
|
+
name: string;
|
|
54
|
+
/** ISO 8601 creation timestamp. */
|
|
55
|
+
createdAt: string;
|
|
56
|
+
/** ISO 8601 last-update timestamp. */
|
|
57
|
+
updatedAt: string;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Type guard for {@link AccessGroup}.
|
|
61
|
+
*/
|
|
62
|
+
export declare function isAccessGroup(resource: any): resource is AccessGroup;
|
|
63
|
+
/**
|
|
64
|
+
* Creates a Cloudflare Zero Trust [Access group](https://developers.cloudflare.com/cloudflare-one/identity/users/groups/),
|
|
65
|
+
* a reusable bundle of rules that can be referenced by Access policies.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* // Engineering team by email domain.
|
|
69
|
+
* const engineering = await AccessGroup("engineering", {
|
|
70
|
+
* name: "Engineering",
|
|
71
|
+
* include: [{ email_domain: { domain: "acme.com" } }],
|
|
72
|
+
* });
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* // Allow a managed IP list, exclude one specific IP.
|
|
76
|
+
* const officeIps = await AccessGroup("office", {
|
|
77
|
+
* name: "Office IPs",
|
|
78
|
+
* include: [{ ip_list: { id: "<list-uuid>" } }],
|
|
79
|
+
* exclude: [{ ip: { ip: "203.0.113.99/32" } }],
|
|
80
|
+
* });
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* // Compose groups: admins are engineers who are also on-call. Resources
|
|
84
|
+
* // can be passed directly — Alchemy lifts `.id` at the wire boundary.
|
|
85
|
+
* const onCall = await AccessGroup("on-call", {
|
|
86
|
+
* include: [{ email_domain: { domain: "acme.com" } }],
|
|
87
|
+
* });
|
|
88
|
+
* const admins = await AccessGroup("admins", {
|
|
89
|
+
* include: [{ group: { id: engineering } }],
|
|
90
|
+
* require: [{ group: { id: onCall } }],
|
|
91
|
+
* });
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* // IdP-bound rules — match Okta groups via an AccessIdentityProvider.
|
|
95
|
+
* const okta = await AccessIdentityProvider("okta", {
|
|
96
|
+
* type: "okta",
|
|
97
|
+
* name: "Acme Okta",
|
|
98
|
+
* oktaAccount: "acme.okta.com",
|
|
99
|
+
* clientId: "...",
|
|
100
|
+
* clientSecret: alchemy.secret.env.OKTA_SECRET,
|
|
101
|
+
* });
|
|
102
|
+
* const sre = await AccessGroup("sre", {
|
|
103
|
+
* include: [{ okta: { name: "sre", identity_provider_id: okta } }],
|
|
104
|
+
* });
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* // Account default — applied implicitly to every Access application.
|
|
108
|
+
* await AccessGroup("default-deny", {
|
|
109
|
+
* isDefault: true,
|
|
110
|
+
* include: [{ everyone: {} }],
|
|
111
|
+
* exclude: [{ email_domain: { domain: "acme.com" } }],
|
|
112
|
+
* });
|
|
113
|
+
*/
|
|
114
|
+
export declare const AccessGroup: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<AccessGroup>, id: string, props: AccessGroupProps) => Promise<AccessGroup>);
|
|
115
|
+
//# sourceMappingURL=access-group.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access-group.d.ts","sourceRoot":"","sources":["../../src/cloudflare/access-group.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAG7C,OAAO,EAAuB,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAMxE,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,UAAU,CAAC;AAElB;;GAEG;AACH,MAAM,WAAW,gBAAiB,SAAQ,oBAAoB;IAC5D;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;IAEvB;;OAEG;IACH,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;IAEvB;;OAEG;IACH,OAAO,CAAC,EAAE,UAAU,EAAE,CAAC;IAEvB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,gBAAgB,EAAE,OAAO,GAAG,QAAQ,CAAC,GAAG;IACrE,sCAAsC;IACtC,EAAE,EAAE,MAAM,CAAC;IACX,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,sCAAsC;IACtC,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,GAAG,GAAG,QAAQ,IAAI,WAAW,CAEpE;AAaD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,eAAO,MAAM,WAAW,yFAGd,OAAO,CAAC,WAAW,CAAC,MACtB,MAAM,SACH,gBAAgB,KACtB,OAAO,CAAC,WAAW,CAAC,CAkExB,CAAC"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { Resource, ResourceKind } from "../resource.js";
|
|
2
|
+
import { logger } from "../util/logger.js";
|
|
3
|
+
import { serializeAccessRule } from "./access-rule.js";
|
|
4
|
+
import { isCloudflareApiError } from "./api-error.js";
|
|
5
|
+
import { extractCloudflareResult, } from "./api-response.js";
|
|
6
|
+
import { createCloudflareApi, } from "./api.js";
|
|
7
|
+
/**
|
|
8
|
+
* Type guard for {@link AccessGroup}.
|
|
9
|
+
*/
|
|
10
|
+
export function isAccessGroup(resource) {
|
|
11
|
+
return resource?.[ResourceKind] === "cloudflare::AccessGroup";
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Creates a Cloudflare Zero Trust [Access group](https://developers.cloudflare.com/cloudflare-one/identity/users/groups/),
|
|
15
|
+
* a reusable bundle of rules that can be referenced by Access policies.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* // Engineering team by email domain.
|
|
19
|
+
* const engineering = await AccessGroup("engineering", {
|
|
20
|
+
* name: "Engineering",
|
|
21
|
+
* include: [{ email_domain: { domain: "acme.com" } }],
|
|
22
|
+
* });
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* // Allow a managed IP list, exclude one specific IP.
|
|
26
|
+
* const officeIps = await AccessGroup("office", {
|
|
27
|
+
* name: "Office IPs",
|
|
28
|
+
* include: [{ ip_list: { id: "<list-uuid>" } }],
|
|
29
|
+
* exclude: [{ ip: { ip: "203.0.113.99/32" } }],
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* // Compose groups: admins are engineers who are also on-call. Resources
|
|
34
|
+
* // can be passed directly — Alchemy lifts `.id` at the wire boundary.
|
|
35
|
+
* const onCall = await AccessGroup("on-call", {
|
|
36
|
+
* include: [{ email_domain: { domain: "acme.com" } }],
|
|
37
|
+
* });
|
|
38
|
+
* const admins = await AccessGroup("admins", {
|
|
39
|
+
* include: [{ group: { id: engineering } }],
|
|
40
|
+
* require: [{ group: { id: onCall } }],
|
|
41
|
+
* });
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* // IdP-bound rules — match Okta groups via an AccessIdentityProvider.
|
|
45
|
+
* const okta = await AccessIdentityProvider("okta", {
|
|
46
|
+
* type: "okta",
|
|
47
|
+
* name: "Acme Okta",
|
|
48
|
+
* oktaAccount: "acme.okta.com",
|
|
49
|
+
* clientId: "...",
|
|
50
|
+
* clientSecret: alchemy.secret.env.OKTA_SECRET,
|
|
51
|
+
* });
|
|
52
|
+
* const sre = await AccessGroup("sre", {
|
|
53
|
+
* include: [{ okta: { name: "sre", identity_provider_id: okta } }],
|
|
54
|
+
* });
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* // Account default — applied implicitly to every Access application.
|
|
58
|
+
* await AccessGroup("default-deny", {
|
|
59
|
+
* isDefault: true,
|
|
60
|
+
* include: [{ everyone: {} }],
|
|
61
|
+
* exclude: [{ email_domain: { domain: "acme.com" } }],
|
|
62
|
+
* });
|
|
63
|
+
*/
|
|
64
|
+
export const AccessGroup = Resource("cloudflare::AccessGroup", async function (id, props) {
|
|
65
|
+
const api = await createCloudflareApi(props);
|
|
66
|
+
const name = props.name ?? this.scope.createPhysicalName(id);
|
|
67
|
+
const basePath = `/accounts/${api.accountId}/access/groups`;
|
|
68
|
+
if (this.phase === "delete") {
|
|
69
|
+
if (this.output?.id && props.delete !== false) {
|
|
70
|
+
await deleteAccessGroup(api, this.output.id);
|
|
71
|
+
}
|
|
72
|
+
return this.destroy();
|
|
73
|
+
}
|
|
74
|
+
const body = {
|
|
75
|
+
name,
|
|
76
|
+
include: (props.include ?? []).map(serializeAccessRule),
|
|
77
|
+
exclude: (props.exclude ?? []).map(serializeAccessRule),
|
|
78
|
+
require: (props.require ?? []).map(serializeAccessRule),
|
|
79
|
+
is_default: props.isDefault ?? false,
|
|
80
|
+
};
|
|
81
|
+
let group;
|
|
82
|
+
if (this.phase === "update" && this.output?.id) {
|
|
83
|
+
group = await extractCloudflareResult(`update access group "${name}"`, api.put(`${basePath}/${this.output.id}`, body));
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
const adopt = props.adopt ?? this.scope.adopt;
|
|
87
|
+
try {
|
|
88
|
+
group = await extractCloudflareResult(`create access group "${name}"`, api.post(basePath, body));
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
if (adopt && isAccessDuplicateNameError(err)) {
|
|
92
|
+
const existing = await findAccessGroupByName(api, name);
|
|
93
|
+
if (!existing) {
|
|
94
|
+
throw new Error(`Access group "${name}" already exists but could not be found for adoption.`, { cause: err });
|
|
95
|
+
}
|
|
96
|
+
logger.log(`Adopting existing access group "${name}" (${existing.id})`);
|
|
97
|
+
group = await extractCloudflareResult(`adopt access group "${name}"`, api.put(`${basePath}/${existing.id}`, body));
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
throw err;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return {
|
|
105
|
+
id: group.id,
|
|
106
|
+
name: group.name,
|
|
107
|
+
include: props.include,
|
|
108
|
+
exclude: props.exclude,
|
|
109
|
+
require: props.require,
|
|
110
|
+
isDefault: group.is_default,
|
|
111
|
+
createdAt: group.created_at,
|
|
112
|
+
updatedAt: group.updated_at,
|
|
113
|
+
};
|
|
114
|
+
});
|
|
115
|
+
function isAccessDuplicateNameError(err) {
|
|
116
|
+
if (isCloudflareApiError(err, { status: 409 }) ||
|
|
117
|
+
isCloudflareApiError(err, { status: 400 })) {
|
|
118
|
+
const data = err.errorData;
|
|
119
|
+
return (Array.isArray(data) &&
|
|
120
|
+
data.some((e) => "message" in e && /already exists/i.test(String(e.message))));
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
async function findAccessGroupByName(api, name) {
|
|
125
|
+
let page = 1;
|
|
126
|
+
const perPage = 50;
|
|
127
|
+
while (true) {
|
|
128
|
+
const response = await api.get(`/accounts/${api.accountId}/access/groups?page=${page}&per_page=${perPage}`);
|
|
129
|
+
if (!response.ok)
|
|
130
|
+
return null;
|
|
131
|
+
const data = (await response.json());
|
|
132
|
+
const match = data.result.find((g) => g.name === name);
|
|
133
|
+
if (match)
|
|
134
|
+
return match;
|
|
135
|
+
const info = data.result_info;
|
|
136
|
+
if (!info || info.page * info.per_page >= info.total_count)
|
|
137
|
+
return null;
|
|
138
|
+
page++;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async function deleteAccessGroup(api, groupId) {
|
|
142
|
+
const response = await api.delete(`/accounts/${api.accountId}/access/groups/${groupId}`);
|
|
143
|
+
if (!response.ok && response.status !== 404) {
|
|
144
|
+
logger.error(`Error deleting access group ${groupId}: ${response.status} ${response.statusText}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=access-group.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access-group.js","sourceRoot":"","sources":["../../src/cloudflare/access-group.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import type { Context } from "../context.ts";
|
|
2
|
+
import { Secret } from "../secret.ts";
|
|
3
|
+
import { type CloudflareApiOptions } from "./api.ts";
|
|
4
|
+
/**
|
|
5
|
+
* Supported Access identity provider types. The five most common providers
|
|
6
|
+
* have strict {@link AccessIdentityProviderProps} variants below; everything
|
|
7
|
+
* else falls back to {@link OtherIdentityProviderProps} with a permissive
|
|
8
|
+
* `config` shape.
|
|
9
|
+
*/
|
|
10
|
+
export type AccessIdentityProviderType = "onetimepin" | "google" | "google-apps" | "github" | "okta" | "azureAD" | "oidc" | "saml" | "centrify" | "facebook" | "linkedin" | "onelogin" | "pingone" | "yandex" | (string & {});
|
|
11
|
+
interface BaseAccessIdpProps extends CloudflareApiOptions {
|
|
12
|
+
/**
|
|
13
|
+
* Display name shown on the Access login page.
|
|
14
|
+
*
|
|
15
|
+
* @default ${app}-${stage}-${id}
|
|
16
|
+
*/
|
|
17
|
+
name?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Adopt an existing IdP with the same name instead of failing.
|
|
20
|
+
*
|
|
21
|
+
* @default false
|
|
22
|
+
*/
|
|
23
|
+
adopt?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Whether to delete the IdP when removed from Alchemy.
|
|
26
|
+
*
|
|
27
|
+
* @default true
|
|
28
|
+
*/
|
|
29
|
+
delete?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* One-Time PIN — Cloudflare emails a code to the user. No external IdP
|
|
33
|
+
* configuration required.
|
|
34
|
+
*/
|
|
35
|
+
export interface OneTimePinIdentityProviderProps extends BaseAccessIdpProps {
|
|
36
|
+
type: "onetimepin";
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Google OAuth identity provider.
|
|
40
|
+
*/
|
|
41
|
+
export interface GoogleIdentityProviderProps extends BaseAccessIdpProps {
|
|
42
|
+
type: "google";
|
|
43
|
+
/**
|
|
44
|
+
* OAuth 2.0 client ID issued by Google for your application.
|
|
45
|
+
* This is a public identifier (not a secret).
|
|
46
|
+
*/
|
|
47
|
+
clientId: string;
|
|
48
|
+
/**
|
|
49
|
+
* OAuth 2.0 client secret issued by Google. Use {@link alchemy.secret} so
|
|
50
|
+
* the value is encrypted at rest in the Alchemy state file.
|
|
51
|
+
*/
|
|
52
|
+
clientSecret: string | Secret;
|
|
53
|
+
/**
|
|
54
|
+
* Custom claims to request from the IdP and forward into the Access JWT.
|
|
55
|
+
*/
|
|
56
|
+
claims?: string[];
|
|
57
|
+
/**
|
|
58
|
+
* Override the OIDC claim Cloudflare reads as the user's email
|
|
59
|
+
* (defaults to `email`).
|
|
60
|
+
*/
|
|
61
|
+
emailClaimName?: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Okta identity provider (OIDC under the hood).
|
|
65
|
+
*/
|
|
66
|
+
export interface OktaIdentityProviderProps extends BaseAccessIdpProps {
|
|
67
|
+
type: "okta";
|
|
68
|
+
/**
|
|
69
|
+
* Your Okta tenant subdomain, e.g. `acme` for `acme.okta.com`.
|
|
70
|
+
*/
|
|
71
|
+
oktaAccount: string;
|
|
72
|
+
/**
|
|
73
|
+
* Custom Okta authorization server ID. Omit to use Okta's default
|
|
74
|
+
* authorization server.
|
|
75
|
+
*/
|
|
76
|
+
authorizationServerId?: string;
|
|
77
|
+
/**
|
|
78
|
+
* OAuth 2.0 client ID of the Okta app integration.
|
|
79
|
+
*/
|
|
80
|
+
clientId: string;
|
|
81
|
+
/**
|
|
82
|
+
* OAuth 2.0 client secret of the Okta app integration. Use
|
|
83
|
+
* {@link alchemy.secret} for at-rest encryption.
|
|
84
|
+
*/
|
|
85
|
+
clientSecret: string | Secret;
|
|
86
|
+
/**
|
|
87
|
+
* Custom claims to request from Okta and forward into the Access JWT.
|
|
88
|
+
*/
|
|
89
|
+
claims?: string[];
|
|
90
|
+
/**
|
|
91
|
+
* Override the OIDC claim Cloudflare reads as the user's email
|
|
92
|
+
* (defaults to `email`).
|
|
93
|
+
*/
|
|
94
|
+
emailClaimName?: string;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Generic OpenID Connect identity provider.
|
|
98
|
+
*/
|
|
99
|
+
export interface OidcIdentityProviderProps extends BaseAccessIdpProps {
|
|
100
|
+
type: "oidc";
|
|
101
|
+
/**
|
|
102
|
+
* IdP authorization endpoint URL (the page users are redirected to to
|
|
103
|
+
* sign in).
|
|
104
|
+
*/
|
|
105
|
+
authUrl: string;
|
|
106
|
+
/**
|
|
107
|
+
* IdP token endpoint URL (used by Cloudflare to exchange the auth code
|
|
108
|
+
* for tokens).
|
|
109
|
+
*/
|
|
110
|
+
tokenUrl: string;
|
|
111
|
+
/**
|
|
112
|
+
* JWKS endpoint URL — public keys Cloudflare uses to verify ID-token
|
|
113
|
+
* signatures.
|
|
114
|
+
*/
|
|
115
|
+
certsUrl: string;
|
|
116
|
+
/**
|
|
117
|
+
* OAuth 2.0 client ID registered with the IdP.
|
|
118
|
+
*/
|
|
119
|
+
clientId: string;
|
|
120
|
+
/**
|
|
121
|
+
* OAuth 2.0 client secret registered with the IdP. Use
|
|
122
|
+
* {@link alchemy.secret} for at-rest encryption.
|
|
123
|
+
*/
|
|
124
|
+
clientSecret: string | Secret;
|
|
125
|
+
/**
|
|
126
|
+
* OIDC scopes to request. Defaults to `["openid", "email", "profile"]`
|
|
127
|
+
* server-side if omitted.
|
|
128
|
+
*/
|
|
129
|
+
scopes?: string[];
|
|
130
|
+
/**
|
|
131
|
+
* Custom claims to request from the IdP and forward into the Access JWT.
|
|
132
|
+
*/
|
|
133
|
+
claims?: string[];
|
|
134
|
+
/**
|
|
135
|
+
* Override the OIDC claim Cloudflare reads as the user's email
|
|
136
|
+
* (defaults to `email`).
|
|
137
|
+
*/
|
|
138
|
+
emailClaimName?: string;
|
|
139
|
+
/**
|
|
140
|
+
* Enable PKCE on the authorization code flow. Recommended for public
|
|
141
|
+
* clients and required by some IdPs.
|
|
142
|
+
*/
|
|
143
|
+
pkceEnabled?: boolean;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Generic SAML 2.0 identity provider.
|
|
147
|
+
*/
|
|
148
|
+
export interface SamlIdentityProviderProps extends BaseAccessIdpProps {
|
|
149
|
+
type: "saml";
|
|
150
|
+
/**
|
|
151
|
+
* SAML issuer (entity ID) of the IdP, used to validate the `Issuer`
|
|
152
|
+
* element of incoming assertions.
|
|
153
|
+
*/
|
|
154
|
+
issuerUrl: string;
|
|
155
|
+
/**
|
|
156
|
+
* IdP single sign-on URL — Cloudflare redirects users here to start
|
|
157
|
+
* the SAML flow.
|
|
158
|
+
*/
|
|
159
|
+
ssoTargetUrl: string;
|
|
160
|
+
/**
|
|
161
|
+
* PEM-encoded x509 certificates the IdP will use to sign assertions.
|
|
162
|
+
* Multiple entries support certificate rotation.
|
|
163
|
+
*/
|
|
164
|
+
idpPublicCerts: string[];
|
|
165
|
+
/**
|
|
166
|
+
* SAML attributes to forward from the assertion into the Access JWT.
|
|
167
|
+
*/
|
|
168
|
+
attributes?: string[];
|
|
169
|
+
/**
|
|
170
|
+
* Override the SAML attribute Cloudflare reads as the user's email
|
|
171
|
+
* (defaults to `email`).
|
|
172
|
+
*/
|
|
173
|
+
emailAttributeName?: string;
|
|
174
|
+
/**
|
|
175
|
+
* Map SAML attributes to HTTP headers Cloudflare will inject when
|
|
176
|
+
* forwarding requests to the origin.
|
|
177
|
+
*/
|
|
178
|
+
headerAttributes?: {
|
|
179
|
+
headerName: string;
|
|
180
|
+
attributeName: string;
|
|
181
|
+
}[];
|
|
182
|
+
/**
|
|
183
|
+
* Sign outgoing AuthnRequests with Cloudflare's signing key.
|
|
184
|
+
*/
|
|
185
|
+
signRequest?: boolean;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Catch-all for IdP types not covered by a strict variant
|
|
189
|
+
* (`azureAD`, `github`, `google-apps`, `centrify`, `facebook`, `linkedin`,
|
|
190
|
+
* `onelogin`, `pingone`, `yandex`, or future providers).
|
|
191
|
+
*
|
|
192
|
+
* Pass a free-form camelCase `config` object — keys are converted to
|
|
193
|
+
* snake_case at the API boundary. This nested escape hatch is an
|
|
194
|
+
* intentional exception to the flat-props convention used by the strict
|
|
195
|
+
* variants above.
|
|
196
|
+
*/
|
|
197
|
+
export interface OtherIdentityProviderProps extends BaseAccessIdpProps {
|
|
198
|
+
type: Exclude<AccessIdentityProviderType, "onetimepin" | "google" | "okta" | "oidc" | "saml">;
|
|
199
|
+
/**
|
|
200
|
+
* Free-form provider configuration. Use {@link alchemy.secret} for any
|
|
201
|
+
* sensitive values; they are unwrapped before sending to Cloudflare.
|
|
202
|
+
*/
|
|
203
|
+
config: {
|
|
204
|
+
clientId?: string;
|
|
205
|
+
clientSecret?: string | Secret;
|
|
206
|
+
} & Record<string, unknown>;
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Properties for creating or updating an {@link AccessIdentityProvider}.
|
|
210
|
+
*/
|
|
211
|
+
export type AccessIdentityProviderProps = OneTimePinIdentityProviderProps | GoogleIdentityProviderProps | OktaIdentityProviderProps | OidcIdentityProviderProps | SamlIdentityProviderProps | OtherIdentityProviderProps;
|
|
212
|
+
/**
|
|
213
|
+
* Output for an {@link AccessIdentityProvider}.
|
|
214
|
+
*/
|
|
215
|
+
export type AccessIdentityProvider = Omit<AccessIdentityProviderProps, "adopt" | "delete"> & {
|
|
216
|
+
/** Cloudflare-assigned IdP UUID. */
|
|
217
|
+
id: string;
|
|
218
|
+
/** Display name. */
|
|
219
|
+
name: string;
|
|
220
|
+
};
|
|
221
|
+
/**
|
|
222
|
+
* Type guard for {@link AccessIdentityProvider}.
|
|
223
|
+
*/
|
|
224
|
+
export declare function isAccessIdentityProvider(resource: any): resource is AccessIdentityProvider;
|
|
225
|
+
/**
|
|
226
|
+
* Creates a Cloudflare Zero Trust [Access identity provider](https://developers.cloudflare.com/cloudflare-one/identity/idp-integration/)
|
|
227
|
+
* which lets users sign in to Access-protected applications.
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* // Built-in One-Time PIN (no IdP setup required).
|
|
231
|
+
* const otp = await AccessIdentityProvider("otp", {
|
|
232
|
+
* type: "onetimepin",
|
|
233
|
+
* name: "Email OTP",
|
|
234
|
+
* });
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* // Google OAuth. clientId is a public OAuth identifier (not a secret).
|
|
238
|
+
* const google = await AccessIdentityProvider("google", {
|
|
239
|
+
* type: "google",
|
|
240
|
+
* name: "Google",
|
|
241
|
+
* clientId: process.env.GOOGLE_CLIENT_ID!,
|
|
242
|
+
* clientSecret: alchemy.secret.env.GOOGLE_CLIENT_SECRET,
|
|
243
|
+
* });
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* // Generic OIDC provider.
|
|
247
|
+
* const oidc = await AccessIdentityProvider("idp", {
|
|
248
|
+
* type: "oidc",
|
|
249
|
+
* name: "Corporate IdP",
|
|
250
|
+
* authUrl: "https://idp.example.com/oauth2/authorize",
|
|
251
|
+
* tokenUrl: "https://idp.example.com/oauth2/token",
|
|
252
|
+
* certsUrl: "https://idp.example.com/oauth2/certs",
|
|
253
|
+
* clientId: "my-app",
|
|
254
|
+
* clientSecret: alchemy.secret.env.IDP_CLIENT_SECRET,
|
|
255
|
+
* scopes: ["openid", "email", "profile"],
|
|
256
|
+
* pkceEnabled: true,
|
|
257
|
+
* });
|
|
258
|
+
*/
|
|
259
|
+
export declare const AccessIdentityProvider: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<AccessIdentityProvider>, id: string, props: AccessIdentityProviderProps) => Promise<AccessIdentityProvider>);
|
|
260
|
+
export {};
|
|
261
|
+
//# sourceMappingURL=access-identity-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access-identity-provider.d.ts","sourceRoot":"","sources":["../../src/cloudflare/access-identity-provider.ts"],"names":[],"mappings":"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"}
|