@infoxchange/make-it-so 2.10.0-internal-testing-vdt-199-add-oidc-auth.7 → 2.10.0-internal-testing-vdt-199-add-oidc-auth-2.1

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.
Files changed (25) hide show
  1. package/README.md +24 -2
  2. package/dist/cdk-constructs/CloudFrontOidcAuth/auth-check.d.ts.map +1 -0
  3. package/dist/cdk-constructs/CloudFrontOidcAuth/auth-route.d.ts.map +1 -0
  4. package/dist/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/auth-route.js +2 -5
  5. package/dist/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/index.d.ts +1 -1
  6. package/dist/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/index.d.ts.map +1 -1
  7. package/dist/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/index.js +11 -10
  8. package/dist/cdk-constructs/index.d.ts +1 -1
  9. package/dist/cdk-constructs/index.js +1 -1
  10. package/package.json +2 -3
  11. package/src/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/auth-check.ts +12 -5
  12. package/src/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/auth-route.ts +9 -14
  13. package/src/cdk-constructs/CloudFrontOidcAuth/cloudfront.d.ts +245 -0
  14. package/src/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/index.ts +26 -23
  15. package/src/cdk-constructs/index.ts +1 -1
  16. package/dist/cdk-constructs/CloudWatchOidcAuth/auth-check.d.ts.map +0 -1
  17. package/dist/cdk-constructs/CloudWatchOidcAuth/auth-route.d.ts.map +0 -1
  18. package/dist/lib/utils/source-code.d.ts +0 -2
  19. package/dist/lib/utils/source-code.d.ts.map +0 -1
  20. package/dist/lib/utils/source-code.js +0 -1
  21. package/src/cdk-constructs/CloudWatchOidcAuth/cloudfront.d.ts +0 -243
  22. package/src/lib/utils/source-code.ts +0 -0
  23. /package/dist/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/auth-check.d.ts +0 -0
  24. /package/dist/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/auth-check.js +0 -0
  25. /package/dist/cdk-constructs/{CloudWatchOidcAuth → CloudFrontOidcAuth}/auth-route.d.ts +0 -0
package/README.md CHANGED
@@ -13,8 +13,6 @@ npm --save-dev @infoxchange/make-it-so
13
13
  yarn add --dev @infoxchange/make-it-so
14
14
  ```
15
15
 
16
-
17
-
18
16
  ## Features
19
17
 
20
18
  ### deployConfig
@@ -292,6 +290,30 @@ const vpcDetails = new IxVpcDetails(scope, "VpcDetails");
292
290
 
293
291
  </details>
294
292
 
293
+ <details>
294
+ <summary><strong>CloudFrontOidcAuth</strong> - Adds OIDC authentication to a CloudFront distribution.</summary>
295
+
296
+ ```typescript
297
+ import { CloudWatchOidcAuth } from "@infoxchange/make-it-so/cdk-constructs";
298
+
299
+ // You first create an instance of CloudFrontOidcAuth
300
+ const auth = new CloudFrontOidcAuth(stack, "CloudFrontOidcAuth", {
301
+ oidcIssuerUrl: "https://your-oidc-server.com/path/",
302
+ oidcClientId: "your-client-id",
303
+ oidcScope: "email",
304
+ });
305
+
306
+ // Then you apply it to the a CloudFront backed site when it's created
307
+ const site = new IxStaticSite(stack, "IxStaticSite", {
308
+ path: "path/to/site/files",
309
+ cdk: {
310
+ distribution: auth.addToDistributionDefinition(stack, {
311
+ distributionDefinition: {},
312
+ }),
313
+ },
314
+ });
315
+ ```
316
+
295
317
  ## Full Example
296
318
 
297
319
  To deploy a Next.js based site you would include a `sst.config.ts` file at the root of repo with contents like this:
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-check.d.ts","sourceRoot":"","sources":["../../../src/cdk-constructs/CloudFrontOidcAuth/auth-check.ts"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-route.d.ts","sourceRoot":"","sources":["../../../src/cdk-constructs/CloudFrontOidcAuth/auth-route.ts"],"names":[],"mappings":"AAyBA,eAAO,MAAM,OAAO,4CAiCnB,CAAC"}
@@ -24,8 +24,7 @@ export const handler = addRequiredContext(AuthHandler({
24
24
  issuer: await Issuer.discover(oidcIssuerConfigUrl.href),
25
25
  clientID: oidcClientId,
26
26
  scope: oidcScope,
27
- onSuccess: async (tokenset, client) => {
28
- console.log("🟢", client);
27
+ onSuccess: async (tokenset) => {
29
28
  // Payload to include in the token
30
29
  const payload = {
31
30
  userID: tokenset.claims().sub,
@@ -52,11 +51,9 @@ export const handler = addRequiredContext(AuthHandler({
52
51
  }));
53
52
  function addRequiredContext(handler) {
54
53
  return async function (...args) {
55
- const [event, context] = args;
54
+ const [event] = args;
56
55
  // Used by AuthHandler to create callback url sent to oidc server
57
56
  event.requestContext.domainName = event.headers["x-forwarded-host"];
58
- console.log("🟢 event", event);
59
- console.log("🔵 context", context);
60
57
  return await handler(...args);
61
58
  };
62
59
  }
@@ -10,7 +10,7 @@ type Props = {
10
10
  oidcClientId: string;
11
11
  oidcScope: string;
12
12
  };
13
- export declare class CloudWatchOidcAuth extends Construct {
13
+ export declare class CloudFrontOidcAuth extends Construct {
14
14
  readonly oidcIssuerUrl: string;
15
15
  readonly oidcClientId: string;
16
16
  readonly oidcScope: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cdk-constructs/CloudWatchOidcAuth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AASvC,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAI1E,KAAK,cAAc,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,KAAK,WAAW,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9D,KAAK,OAAO,CAAC,CAAC,IAAI;IAChB,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAC/B,CAAC;AAEF,KAAK,KAAK,GAAG;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,qBAAa,kBAAmB,SAAQ,SAAS;IAC/C,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;gBAER,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK;IAQhE,2BAA2B,CACzB,iBAAiB,SAAS,4BAA4B,EAEtD,KAAK,EAAE,cAAc,EACrB,EACE,sBAAsB,EACtB,MAAgB,GACjB,EAAE;QAAE,sBAAsB,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IA6C5E,OAAO,CAAC,sBAAsB;IAyH9B,OAAO,CAAC,sBAAsB;CA0E/B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cdk-constructs/CloudFrontOidcAuth/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AASvC,OAAO,EAAE,4BAA4B,EAAE,MAAM,4BAA4B,CAAC;AAI1E,KAAK,cAAc,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACjE,KAAK,WAAW,GAAG,qBAAqB,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AAE9D,KAAK,OAAO,CAAC,CAAC,IAAI;IAChB,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAC/B,CAAC;AAEF,KAAK,KAAK,GAAG;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,qBAAa,kBAAmB,SAAQ,SAAS;IAC/C,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;gBAER,KAAK,EAAE,cAAc,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK;IAQhE,2BAA2B,CACzB,iBAAiB,SAAS,4BAA4B,EAEtD,KAAK,EAAE,cAAc,EACrB,EACE,sBAAsB,EACtB,MAAgB,GACjB,EAAE;QAAE,sBAAsB,EAAE,OAAO,CAAC,iBAAiB,CAAC,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAuC5E,OAAO,CAAC,sBAAsB;IA8H9B,OAAO,CAAC,sBAAsB;CA8E/B"}
@@ -9,7 +9,7 @@ import { Config as SSTInternalConfig } from "sst/config.js";
9
9
  import CloudFrontOrigins from "aws-cdk-lib/aws-cloudfront-origins";
10
10
  import path from "node:path";
11
11
  import fs from "node:fs";
12
- export class CloudWatchOidcAuth extends Construct {
12
+ export class CloudFrontOidcAuth extends Construct {
13
13
  oidcIssuerUrl;
14
14
  oidcClientId;
15
15
  oidcScope;
@@ -22,7 +22,6 @@ export class CloudWatchOidcAuth extends Construct {
22
22
  this.id = id;
23
23
  }
24
24
  addToDistributionDefinition(scope, { distributionDefinition, prefix = "/auth", }) {
25
- console.log("------", import.meta.dirname, import.meta.url, import.meta.filename);
26
25
  const updatedDistributionDefinition = { ...distributionDefinition };
27
26
  const behaviourName = `${prefix.replace(/^\//g, "")}/*`;
28
27
  updatedDistributionDefinition.additionalBehaviors =
@@ -126,18 +125,20 @@ export class CloudWatchOidcAuth extends Construct {
126
125
  throw new Error("Could not find the underlying Lambda function of the AwsCustomResource");
127
126
  }
128
127
  fn.addEnvironment("NODE_OPTIONS", "--require=@aws-sdk/signature-v4-crt");
129
- const edgeFuncAuthCheck = new CloudFront.Function(scope, `${this.id}AuthCheckFunction`, {
130
- code: CloudFront.FunctionCode.fromInline(fs.readFileSync(path.join(import.meta.dirname, "auth-check.js"), "utf8").replace("__placeholder-for-jwt-secret-key__", key)),
128
+ const authCheckFunction = new CloudFront.Function(scope, `${this.id}AuthCheckFunction`, {
129
+ code: CloudFront.FunctionCode.fromInline(fs
130
+ .readFileSync(path.join(import.meta.dirname, "auth-check.js"), "utf8")
131
+ .replace("__placeholder-for-jwt-secret-key__", key)),
131
132
  runtime: CloudFront.FunctionRuntime.JS_2_0,
132
133
  keyValueStore: cfKeyValueStore,
133
134
  });
134
135
  return {
135
- function: edgeFuncAuthCheck,
136
+ function: authCheckFunction,
136
137
  eventType: CloudFront.FunctionEventType.VIEWER_REQUEST,
137
138
  };
138
139
  }
139
140
  getAuthBehaviorOptions(scope, jwtSecret, prefix) {
140
- const edgeFuncAuth = new SST.Function(scope, `${this.id}EdgeFunctionAuth`, {
141
+ const authRouteFunction = new SST.Function(scope, `${this.id}AuthRouteFunction`, {
141
142
  runtime: "nodejs20.x",
142
143
  handler: path.join(import.meta.dirname, "auth-route.handler"),
143
144
  environment: {
@@ -147,7 +148,7 @@ export class CloudWatchOidcAuth extends Construct {
147
148
  JWT_SECRET: jwtSecret.secretValue.toString(),
148
149
  },
149
150
  });
150
- // edgeFuncAuth uses SST's AuthHandler construct which is normally run inside a lambda that's
151
+ // authRouteFunction uses SST's AuthHandler construct which is normally run inside a lambda that's
151
152
  // created by SST's Auth construct. AuthHandler expects certain environment variables to be set
152
153
  // by the Auth construct so we have to set them ourselves here to keep it happy.
153
154
  const envVarName = SSTInternalConfig.envFor({
@@ -155,8 +156,8 @@ export class CloudWatchOidcAuth extends Construct {
155
156
  id: "id", // It seems like the env var will still be found no matter what this value is
156
157
  prop: "prefix",
157
158
  });
158
- edgeFuncAuth.addEnvironment(envVarName, prefix);
159
- const edgeFuncAuthUrl = edgeFuncAuth.addFunctionUrl({
159
+ authRouteFunction.addEnvironment(envVarName, prefix);
160
+ const authRouteFunctionUrl = authRouteFunction.addFunctionUrl({
160
161
  authType: Lambda.FunctionUrlAuthType.NONE,
161
162
  });
162
163
  const forwardHostHeaderCfFunction = new CloudFront.Function(scope, `${this.id}ForwardHostHeaderFunction`, {
@@ -170,7 +171,7 @@ export class CloudWatchOidcAuth extends Construct {
170
171
  runtime: CloudFront.FunctionRuntime.JS_2_0,
171
172
  });
172
173
  return {
173
- origin: new CloudFrontOrigins.HttpOrigin(CDK.Fn.parseDomainName(edgeFuncAuthUrl.url)),
174
+ origin: new CloudFrontOrigins.HttpOrigin(CDK.Fn.parseDomainName(authRouteFunctionUrl.url)),
174
175
  allowedMethods: CloudFront.AllowedMethods.ALLOW_ALL,
175
176
  cachePolicy: new CloudFront.CachePolicy(scope, `${this.id}AllowAllCookiesPolicy`, {
176
177
  cachePolicyName: "AllowAllCookiesPolicy",
@@ -6,5 +6,5 @@ export * from "./IxStaticSite.js";
6
6
  export * from "./IxElasticache.js";
7
7
  export * from "./IxApi.js";
8
8
  export * from "./IxQuicksightWorkspace.js";
9
- export * from "./CloudWatchOidcAuth/index.js";
9
+ export * from "./CloudFrontOidcAuth/index.js";
10
10
  //# sourceMappingURL=index.d.ts.map
@@ -6,4 +6,4 @@ export * from "./IxStaticSite.js";
6
6
  export * from "./IxElasticache.js";
7
7
  export * from "./IxApi.js";
8
8
  export * from "./IxQuicksightWorkspace.js";
9
- export * from "./CloudWatchOidcAuth/index.js";
9
+ export * from "./CloudFrontOidcAuth/index.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@infoxchange/make-it-so",
3
- "version": "2.10.0-internal-testing-vdt-199-add-oidc-auth.7",
3
+ "version": "2.10.0-internal-testing-vdt-199-add-oidc-auth-2.1",
4
4
  "description": "Makes deploying services to IX infra easy",
5
5
  "repository": "github:infoxchange/make-it-so",
6
6
  "type": "module",
@@ -30,6 +30,7 @@
30
30
  "@commitlint/prompt-cli": "^19.3.1",
31
31
  "@eslint/js": "^9.3.0",
32
32
  "@tsconfig/node21": "^21.0.3",
33
+ "@types/aws-cloudfront-function": "^1.0.6",
33
34
  "@types/jsonwebtoken": "^9.0.10",
34
35
  "aws-cdk-lib": "2.142.1",
35
36
  "constructs": "^10.3.0",
@@ -51,8 +52,6 @@
51
52
  "sst": "^2.0.0"
52
53
  },
53
54
  "dependencies": {
54
- "@aws-sdk/client-lambda": "^3.920.0",
55
- "@types/aws-cloudfront-function": "^1.0.6",
56
55
  "jsonwebtoken": "^9.0.2",
57
56
  "zod": "^3.24.2"
58
57
  }
@@ -72,7 +72,13 @@ function _constantTimeEquals(a: string, b: string) {
72
72
  return 0 === xor;
73
73
  }
74
74
 
75
- function _verify(input: string, key: string, method: string, type: string, signature: string) {
75
+ function _verify(
76
+ input: string,
77
+ key: string,
78
+ method: string,
79
+ type: string,
80
+ signature: string,
81
+ ) {
76
82
  if (type === "hmac") {
77
83
  return _constantTimeEquals(signature, _sign(input, key, method));
78
84
  } else {
@@ -97,7 +103,8 @@ async function handler(event: AWSCloudFrontFunction.Event) {
97
103
  throw new Error("Error retrieving JWT secret key");
98
104
  }
99
105
 
100
- const jwtToken = request.cookies["auth-token"] && request.cookies["auth-token"].value;
106
+ const jwtToken =
107
+ request.cookies["auth-token"] && request.cookies["auth-token"].value;
101
108
 
102
109
  if (!jwtToken) {
103
110
  log("Error: No JWT in the cookies");
@@ -130,18 +137,18 @@ const log: typeof console.log = function () {
130
137
 
131
138
  // CloudFront Function runtime only prints first argument passed to console.log so add other args to the first one if given.
132
139
  // eslint-disable-next-line prefer-rest-params -- We can't use spread or rest parameters in CloudFront Functions
133
- let message = arguments[0]
140
+ let message = arguments[0];
134
141
  if (arguments.length > 1) {
135
142
  const otherArgs = [];
136
143
  for (let i = 1; i < arguments.length; i++) {
137
144
  // eslint-disable-next-line prefer-rest-params
138
- otherArgs[i-1] = arguments[i];
145
+ otherArgs[i - 1] = arguments[i];
139
146
  }
140
147
 
141
148
  message += " - additional args: " + JSON.stringify(otherArgs);
142
149
  }
143
150
  console.log(message);
144
- }
151
+ };
145
152
 
146
153
  // This serves no purpose other than to make TypeScript and eslint happy by showing that that handler is used. We can't
147
154
  // export handler as an alterative because CloudFront Functions don't support exports.
@@ -30,8 +30,7 @@ export const handler = addRequiredContext(
30
30
  issuer: await Issuer.discover(oidcIssuerConfigUrl.href),
31
31
  clientID: oidcClientId,
32
32
  scope: oidcScope,
33
- onSuccess: async (tokenset, client) => {
34
- console.log("🟢", client);
33
+ onSuccess: async (tokenset) => {
35
34
  // Payload to include in the token
36
35
  const payload = {
37
36
  userID: tokenset.claims().sub,
@@ -39,14 +38,10 @@ export const handler = addRequiredContext(
39
38
  const expiresInMs = 1000 * 60 * 60;
40
39
 
41
40
  // Create the token
42
- const token = jwt.sign(
43
- payload,
44
- jwtSecret,
45
- {
46
- algorithm: "HS256",
47
- expiresIn: expiresInMs / 1000,
48
- }
49
- );
41
+ const token = jwt.sign(payload, jwtSecret, {
42
+ algorithm: "HS256",
43
+ expiresIn: expiresInMs / 1000,
44
+ });
50
45
  const expiryDate = new Date(Date.now() + expiresInMs);
51
46
  return {
52
47
  statusCode: 302,
@@ -63,13 +58,13 @@ export const handler = addRequiredContext(
63
58
  }),
64
59
  );
65
60
 
66
- function addRequiredContext(handler: ReturnType<typeof AuthHandler>): ReturnType<typeof AuthHandler> {
61
+ function addRequiredContext(
62
+ handler: ReturnType<typeof AuthHandler>,
63
+ ): ReturnType<typeof AuthHandler> {
67
64
  return async function (...args) {
68
- const [event, context] = args;
65
+ const [event] = args;
69
66
  // Used by AuthHandler to create callback url sent to oidc server
70
67
  event.requestContext.domainName = event.headers["x-forwarded-host"];
71
- console.log("🟢 event", event)
72
- console.log("🔵 context", context)
73
68
 
74
69
  return await handler(...args);
75
70
  };
@@ -0,0 +1,245 @@
1
+ // NOTE: once this is no longer needed we can remove typeRoots from tsconfig.json as well
2
+
3
+ // This is a copy of @types/aws-cloudfront-function but with optional kvsId in kvs() function. We can't just modify the
4
+ // kvs type since we can't modify the default export without messing up the rest of the types. Which is why we
5
+ // unfortunately have to duplicate the whole file here.
6
+ // But once https://github.com/DefinitelyTyped/DefinitelyTyped/issues/73959 is sorted we can get rid of this.
7
+
8
+ declare namespace AWSCloudFrontFunction {
9
+ interface Event {
10
+ version: "1.0";
11
+ context: Context;
12
+ viewer: Viewer;
13
+ request: Request;
14
+ response: Response;
15
+ }
16
+
17
+ interface Context {
18
+ distributionDomainName: string;
19
+ distributionId: string;
20
+ eventType: "viewer-request" | "viewer-response";
21
+ requestId: string;
22
+ }
23
+
24
+ interface Viewer {
25
+ ip: string;
26
+ }
27
+
28
+ interface Request {
29
+ method: string;
30
+ uri: string;
31
+ querystring: ValueObject;
32
+ headers: ValueObject;
33
+ cookies: ValueObject;
34
+ }
35
+
36
+ interface Response {
37
+ statusCode: number;
38
+ statusDescription?: string;
39
+ headers?: ValueObject;
40
+ cookies?: ResponseCookie;
41
+ body?: string | ResponseBody;
42
+ }
43
+
44
+ interface ResponseBody {
45
+ data: string;
46
+ encoding: "text" | "base64";
47
+ }
48
+
49
+ interface ValueObject {
50
+ [name: string]: {
51
+ value: string;
52
+ multiValue?: Array<{
53
+ value: string;
54
+ }>;
55
+ };
56
+ }
57
+
58
+ interface ResponseCookie {
59
+ [name: string]: {
60
+ value: string;
61
+ attributes: string;
62
+ multiValue?: Array<{
63
+ value: string;
64
+ attributes: string;
65
+ }>;
66
+ };
67
+ }
68
+ }
69
+
70
+ declare module "cloudfront" {
71
+ /**
72
+ * Retrieves a reference to a CloudFront Key-Value Store (KVS) by its ID.
73
+ * @param kvsId The identifier of the KVS to use.
74
+ * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/functions-custom-methods.html
75
+ */
76
+ function kvs(kvsId?: string): KVStore;
77
+
78
+ interface KVStore {
79
+ /**
80
+ * Retrieve a value from the store.
81
+ * @param key Key to retrieve.
82
+ * @throws If key does not exist.
83
+ */
84
+ get(key: string): Promise<string>;
85
+ get(key: string, options: { format: "string" }): Promise<string>;
86
+ get(key: string, options: { format: "bytes" }): Promise<Uint8Array>;
87
+ get(key: string, options: { format: "json" }): Promise<unknown>;
88
+
89
+ /**
90
+ * Check if the key exists in the store.
91
+ * @param key Key to check.
92
+ */
93
+ exists(key: string): Promise<boolean>;
94
+
95
+ /**
96
+ * Retrieve metadata about the key-value store.
97
+ */
98
+ meta(): Promise<{
99
+ creationDateTime: string;
100
+ lastUpdatedDateTime: string;
101
+ keyCount: number;
102
+ }>;
103
+ }
104
+
105
+ interface OriginAccessControlConfig {
106
+ enabled: boolean;
107
+ signingBehavior: "always" | "never" | "no-override";
108
+ signingProtocol: "sigv4";
109
+ originType: "s3" | "mediapackagev2" | "mediastore" | "lambda";
110
+ }
111
+
112
+ interface OriginShield {
113
+ enabled: boolean;
114
+ region: string;
115
+ }
116
+
117
+ interface Timeouts {
118
+ /**
119
+ * Max time (seconds) to wait for a response or next packet. (1–60)
120
+ */
121
+ readTimeout?: number;
122
+
123
+ /**
124
+ * Max time (seconds) to keep the connection alive after response. (1–60)
125
+ */
126
+ keepAliveTimeout?: number;
127
+
128
+ /**
129
+ * Max time (seconds) to wait for connection establishment. (1–10)
130
+ */
131
+ connectionTimeout?: number;
132
+ }
133
+
134
+ interface CustomOriginConfig {
135
+ /**
136
+ * Port number of the origin. e.g., 80 or 443
137
+ */
138
+ port: number;
139
+
140
+ /**
141
+ * Protocol used to connect. Must be "http" or "https"
142
+ */
143
+ protocol: "http" | "https";
144
+
145
+ /**
146
+ * Minimum TLS/SSL version to use for HTTPS connections.
147
+ */
148
+ sslProtocols: Array<"SSLv3" | "TLSv1" | "TLSv1.1" | "TLSv1.2">;
149
+ }
150
+
151
+ interface UpdateRequestOriginParams {
152
+ /**
153
+ * New origin's domain name. Optional if reusing existing origin's domain.
154
+ */
155
+ domainName?: string;
156
+
157
+ /**
158
+ * Path prefix to append when forwarding request to origin.
159
+ */
160
+ originPath?: string;
161
+
162
+ /**
163
+ * Override or clear custom headers for the origin request.
164
+ */
165
+ customHeaders?: Record<string, string>;
166
+
167
+ /**
168
+ * Number of connection attempts (1–3).
169
+ */
170
+ connectionAttempts?: number;
171
+
172
+ /**
173
+ * Origin Shield configuration. Enables shield layer if specified.
174
+ */
175
+ originShield?: OriginShield;
176
+
177
+ /**
178
+ * Origin Access Control (OAC) configuration.
179
+ */
180
+ originAccessControlConfig?: OriginAccessControlConfig;
181
+
182
+ /**
183
+ * Response and connection timeout configurations.
184
+ */
185
+ timeouts?: Timeouts;
186
+
187
+ /**
188
+ * Settings for non-S3 origins or S3 with static website hosting.
189
+ */
190
+ customOriginConfig?: CustomOriginConfig;
191
+ }
192
+
193
+ /**
194
+ * Mutates the current request’s origin.
195
+ * You can specify a new origin (e.g., S3 or ALB), change custom headers, enable OAC, or enable Origin Shield.
196
+ * Missing fields will inherit values from the assigned origin.
197
+ * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/helper-functions-origin-modification.html#update-request-origin-helper-function
198
+ */
199
+ function updateRequestOrigin(params: UpdateRequestOriginParams): void;
200
+
201
+ /**
202
+ * Switches to another origin already defined in the distribution by origin ID.
203
+ * This is more efficient than defining a new one via `updateRequestOrigin()`.
204
+ * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/helper-functions-origin-modification.html#select-request-origin-id-helper-function
205
+ */
206
+ function selectRequestOriginById(originId: string): void;
207
+
208
+ interface CreateRequestOriginGroupParams {
209
+ /**
210
+ * Two origin IDs to form an origin group.
211
+ * The first is primary; the second is used for failover.
212
+ */
213
+ originIds: [string, string];
214
+
215
+ /**
216
+ * Failover selection strategy: default or media-quality-score.
217
+ */
218
+ selectionCriteria?: "default" | "media-quality-score";
219
+
220
+ /**
221
+ * List of status codes that trigger failover to the secondary origin.
222
+ */
223
+ failoverCriteria: {
224
+ statusCodes: number[];
225
+ };
226
+ }
227
+
228
+ /**
229
+ * Creates a new origin group for failover logic.
230
+ * The origin group can be referenced later via origin ID.
231
+ * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/helper-functions-origin-modification.html#create-request-origin-group-helper-function
232
+ */
233
+ function createRequestOriginGroup(
234
+ params: CreateRequestOriginGroupParams,
235
+ ): void;
236
+
237
+ const cf: {
238
+ kvs: typeof kvs;
239
+ updateRequestOrigin: typeof updateRequestOrigin;
240
+ selectRequestOriginById: typeof selectRequestOriginById;
241
+ createRequestOriginGroup: typeof createRequestOriginGroup;
242
+ };
243
+
244
+ export default cf;
245
+ }
@@ -24,7 +24,7 @@ type Props = {
24
24
  oidcScope: string;
25
25
  };
26
26
 
27
- export class CloudWatchOidcAuth extends Construct {
27
+ export class CloudFrontOidcAuth extends Construct {
28
28
  readonly oidcIssuerUrl: string;
29
29
  readonly oidcClientId: string;
30
30
  readonly oidcScope: string;
@@ -47,12 +47,6 @@ export class CloudWatchOidcAuth extends Construct {
47
47
  prefix = "/auth",
48
48
  }: { distributionDefinition: Mutable<DistributionProps>; prefix?: string },
49
49
  ) {
50
- console.log(
51
- "------",
52
- import.meta.dirname,
53
- import.meta.url,
54
- import.meta.filename,
55
- );
56
50
  const updatedDistributionDefinition = { ...distributionDefinition };
57
51
  const behaviourName = `${prefix.replace(/^\//g, "")}/*`;
58
52
  updatedDistributionDefinition.additionalBehaviors =
@@ -193,12 +187,17 @@ export class CloudWatchOidcAuth extends Construct {
193
187
  }
194
188
  fn.addEnvironment("NODE_OPTIONS", "--require=@aws-sdk/signature-v4-crt");
195
189
 
196
- const edgeFuncAuthCheck = new CloudFront.Function(
190
+ const authCheckFunction = new CloudFront.Function(
197
191
  scope,
198
192
  `${this.id}AuthCheckFunction`,
199
193
  {
200
194
  code: CloudFront.FunctionCode.fromInline(
201
- fs.readFileSync(path.join(import.meta.dirname, "auth-check.js"), "utf8").replace("__placeholder-for-jwt-secret-key__", key),
195
+ fs
196
+ .readFileSync(
197
+ path.join(import.meta.dirname, "auth-check.js"),
198
+ "utf8",
199
+ )
200
+ .replace("__placeholder-for-jwt-secret-key__", key),
202
201
  ),
203
202
  runtime: CloudFront.FunctionRuntime.JS_2_0,
204
203
  keyValueStore: cfKeyValueStore,
@@ -206,7 +205,7 @@ export class CloudWatchOidcAuth extends Construct {
206
205
  );
207
206
 
208
207
  return {
209
- function: edgeFuncAuthCheck,
208
+ function: authCheckFunction,
210
209
  eventType: CloudFront.FunctionEventType.VIEWER_REQUEST,
211
210
  };
212
211
  }
@@ -216,18 +215,22 @@ export class CloudWatchOidcAuth extends Construct {
216
215
  jwtSecret: SecretsManager.Secret,
217
216
  prefix: string,
218
217
  ): CloudFront.BehaviorOptions {
219
- const edgeFuncAuth = new SST.Function(scope, `${this.id}EdgeFunctionAuth`, {
220
- runtime: "nodejs20.x",
221
- handler: path.join(import.meta.dirname, "auth-route.handler"),
222
- environment: {
223
- OIDC_ISSUER_URL: this.oidcIssuerUrl,
224
- OIDC_CLIENT_ID: this.oidcClientId,
225
- OIDC_SCOPE: this.oidcScope,
226
- JWT_SECRET: jwtSecret.secretValue.toString(),
218
+ const authRouteFunction = new SST.Function(
219
+ scope,
220
+ `${this.id}AuthRouteFunction`,
221
+ {
222
+ runtime: "nodejs20.x",
223
+ handler: path.join(import.meta.dirname, "auth-route.handler"),
224
+ environment: {
225
+ OIDC_ISSUER_URL: this.oidcIssuerUrl,
226
+ OIDC_CLIENT_ID: this.oidcClientId,
227
+ OIDC_SCOPE: this.oidcScope,
228
+ JWT_SECRET: jwtSecret.secretValue.toString(),
229
+ },
227
230
  },
228
- });
231
+ );
229
232
 
230
- // edgeFuncAuth uses SST's AuthHandler construct which is normally run inside a lambda that's
233
+ // authRouteFunction uses SST's AuthHandler construct which is normally run inside a lambda that's
231
234
  // created by SST's Auth construct. AuthHandler expects certain environment variables to be set
232
235
  // by the Auth construct so we have to set them ourselves here to keep it happy.
233
236
  const envVarName = SSTInternalConfig.envFor({
@@ -235,9 +238,9 @@ export class CloudWatchOidcAuth extends Construct {
235
238
  id: "id", // It seems like the env var will still be found no matter what this value is
236
239
  prop: "prefix",
237
240
  });
238
- edgeFuncAuth.addEnvironment(envVarName, prefix);
241
+ authRouteFunction.addEnvironment(envVarName, prefix);
239
242
 
240
- const edgeFuncAuthUrl = edgeFuncAuth.addFunctionUrl({
243
+ const authRouteFunctionUrl = authRouteFunction.addFunctionUrl({
241
244
  authType: Lambda.FunctionUrlAuthType.NONE,
242
245
  });
243
246
  const forwardHostHeaderCfFunction = new CloudFront.Function(
@@ -257,7 +260,7 @@ export class CloudWatchOidcAuth extends Construct {
257
260
 
258
261
  return {
259
262
  origin: new CloudFrontOrigins.HttpOrigin(
260
- CDK.Fn.parseDomainName(edgeFuncAuthUrl.url),
263
+ CDK.Fn.parseDomainName(authRouteFunctionUrl.url),
261
264
  ),
262
265
  allowedMethods: CloudFront.AllowedMethods.ALLOW_ALL,
263
266
  cachePolicy: new CloudFront.CachePolicy(
@@ -6,4 +6,4 @@ export * from "./IxStaticSite.js";
6
6
  export * from "./IxElasticache.js";
7
7
  export * from "./IxApi.js";
8
8
  export * from "./IxQuicksightWorkspace.js";
9
- export * from "./CloudWatchOidcAuth/index.js";
9
+ export * from "./CloudFrontOidcAuth/index.js";
@@ -1 +0,0 @@
1
- {"version":3,"file":"auth-check.d.ts","sourceRoot":"","sources":["../../../src/cdk-constructs/CloudWatchOidcAuth/auth-check.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- {"version":3,"file":"auth-route.d.ts","sourceRoot":"","sources":["../../../src/cdk-constructs/CloudWatchOidcAuth/auth-route.ts"],"names":[],"mappings":"AAyBA,eAAO,MAAM,OAAO,4CAsCnB,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=source-code.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"source-code.d.ts","sourceRoot":"","sources":["../../../src/lib/utils/source-code.ts"],"names":[],"mappings":""}
@@ -1 +0,0 @@
1
- export {};
@@ -1,243 +0,0 @@
1
- // NOTE: once this is no longer needed we can remove typeRoots from tsconfig.json as well
2
-
3
- // This is a copy of @types/aws-cloudfront-function but with optional kvsId in kvs() function. We can't just modify the
4
- // kvs type since we can't modify the default export without messing up the rest of the types. Which is why we
5
- // unfortunately have to duplicate the whole file here.
6
- // But once https://github.com/DefinitelyTyped/DefinitelyTyped/issues/73959 is sorted we can get rid of this.
7
-
8
- declare namespace AWSCloudFrontFunction {
9
- interface Event {
10
- version: "1.0";
11
- context: Context;
12
- viewer: Viewer;
13
- request: Request;
14
- response: Response;
15
- }
16
-
17
- interface Context {
18
- distributionDomainName: string;
19
- distributionId: string;
20
- eventType: "viewer-request" | "viewer-response";
21
- requestId: string;
22
- }
23
-
24
- interface Viewer {
25
- ip: string;
26
- }
27
-
28
- interface Request {
29
- method: string;
30
- uri: string;
31
- querystring: ValueObject;
32
- headers: ValueObject;
33
- cookies: ValueObject;
34
- }
35
-
36
- interface Response {
37
- statusCode: number;
38
- statusDescription?: string;
39
- headers?: ValueObject;
40
- cookies?: ResponseCookie;
41
- body?: string | ResponseBody;
42
- }
43
-
44
- interface ResponseBody {
45
- data: string;
46
- encoding: "text" | "base64";
47
- }
48
-
49
- interface ValueObject {
50
- [name: string]: {
51
- value: string;
52
- multiValue?: Array<{
53
- value: string;
54
- }>;
55
- };
56
- }
57
-
58
- interface ResponseCookie {
59
- [name: string]: {
60
- value: string;
61
- attributes: string;
62
- multiValue?: Array<{
63
- value: string;
64
- attributes: string;
65
- }>;
66
- };
67
- }
68
- }
69
-
70
- declare module "cloudfront" {
71
- /**
72
- * Retrieves a reference to a CloudFront Key-Value Store (KVS) by its ID.
73
- * @param kvsId The identifier of the KVS to use.
74
- * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/functions-custom-methods.html
75
- */
76
- function kvs(kvsId?: string): KVStore;
77
-
78
- interface KVStore {
79
- /**
80
- * Retrieve a value from the store.
81
- * @param key Key to retrieve.
82
- * @throws If key does not exist.
83
- */
84
- get(key: string): Promise<string>;
85
- get(key: string, options: { format: "string" }): Promise<string>;
86
- get(key: string, options: { format: "bytes" }): Promise<Uint8Array>;
87
- get(key: string, options: { format: "json" }): Promise<unknown>;
88
-
89
- /**
90
- * Check if the key exists in the store.
91
- * @param key Key to check.
92
- */
93
- exists(key: string): Promise<boolean>;
94
-
95
- /**
96
- * Retrieve metadata about the key-value store.
97
- */
98
- meta(): Promise<{
99
- creationDateTime: string;
100
- lastUpdatedDateTime: string;
101
- keyCount: number;
102
- }>;
103
- }
104
-
105
- interface OriginAccessControlConfig {
106
- enabled: boolean;
107
- signingBehavior: "always" | "never" | "no-override";
108
- signingProtocol: "sigv4";
109
- originType: "s3" | "mediapackagev2" | "mediastore" | "lambda";
110
- }
111
-
112
- interface OriginShield {
113
- enabled: boolean;
114
- region: string;
115
- }
116
-
117
- interface Timeouts {
118
- /**
119
- * Max time (seconds) to wait for a response or next packet. (1–60)
120
- */
121
- readTimeout?: number;
122
-
123
- /**
124
- * Max time (seconds) to keep the connection alive after response. (1–60)
125
- */
126
- keepAliveTimeout?: number;
127
-
128
- /**
129
- * Max time (seconds) to wait for connection establishment. (1–10)
130
- */
131
- connectionTimeout?: number;
132
- }
133
-
134
- interface CustomOriginConfig {
135
- /**
136
- * Port number of the origin. e.g., 80 or 443
137
- */
138
- port: number;
139
-
140
- /**
141
- * Protocol used to connect. Must be "http" or "https"
142
- */
143
- protocol: "http" | "https";
144
-
145
- /**
146
- * Minimum TLS/SSL version to use for HTTPS connections.
147
- */
148
- sslProtocols: Array<"SSLv3" | "TLSv1" | "TLSv1.1" | "TLSv1.2">;
149
- }
150
-
151
- interface UpdateRequestOriginParams {
152
- /**
153
- * New origin's domain name. Optional if reusing existing origin's domain.
154
- */
155
- domainName?: string;
156
-
157
- /**
158
- * Path prefix to append when forwarding request to origin.
159
- */
160
- originPath?: string;
161
-
162
- /**
163
- * Override or clear custom headers for the origin request.
164
- */
165
- customHeaders?: Record<string, string>;
166
-
167
- /**
168
- * Number of connection attempts (1–3).
169
- */
170
- connectionAttempts?: number;
171
-
172
- /**
173
- * Origin Shield configuration. Enables shield layer if specified.
174
- */
175
- originShield?: OriginShield;
176
-
177
- /**
178
- * Origin Access Control (OAC) configuration.
179
- */
180
- originAccessControlConfig?: OriginAccessControlConfig;
181
-
182
- /**
183
- * Response and connection timeout configurations.
184
- */
185
- timeouts?: Timeouts;
186
-
187
- /**
188
- * Settings for non-S3 origins or S3 with static website hosting.
189
- */
190
- customOriginConfig?: CustomOriginConfig;
191
- }
192
-
193
- /**
194
- * Mutates the current request’s origin.
195
- * You can specify a new origin (e.g., S3 or ALB), change custom headers, enable OAC, or enable Origin Shield.
196
- * Missing fields will inherit values from the assigned origin.
197
- * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/helper-functions-origin-modification.html#update-request-origin-helper-function
198
- */
199
- function updateRequestOrigin(params: UpdateRequestOriginParams): void;
200
-
201
- /**
202
- * Switches to another origin already defined in the distribution by origin ID.
203
- * This is more efficient than defining a new one via `updateRequestOrigin()`.
204
- * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/helper-functions-origin-modification.html#select-request-origin-id-helper-function
205
- */
206
- function selectRequestOriginById(originId: string): void;
207
-
208
- interface CreateRequestOriginGroupParams {
209
- /**
210
- * Two origin IDs to form an origin group.
211
- * The first is primary; the second is used for failover.
212
- */
213
- originIds: [string, string];
214
-
215
- /**
216
- * Failover selection strategy: default or media-quality-score.
217
- */
218
- selectionCriteria?: "default" | "media-quality-score";
219
-
220
- /**
221
- * List of status codes that trigger failover to the secondary origin.
222
- */
223
- failoverCriteria: {
224
- statusCodes: number[];
225
- };
226
- }
227
-
228
- /**
229
- * Creates a new origin group for failover logic.
230
- * The origin group can be referenced later via origin ID.
231
- * @see https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/helper-functions-origin-modification.html#create-request-origin-group-helper-function
232
- */
233
- function createRequestOriginGroup(params: CreateRequestOriginGroupParams): void;
234
-
235
- const cf: {
236
- kvs: typeof kvs;
237
- updateRequestOrigin: typeof updateRequestOrigin;
238
- selectRequestOriginById: typeof selectRequestOriginById;
239
- createRequestOriginGroup: typeof createRequestOriginGroup;
240
- };
241
-
242
- export default cf;
243
- }
File without changes