Bug
When a Router is configured with protection: "oac-with-edge-signing", routes added via router.route(lambdaUrl) do not have OAC applied. The
originAccessControlConfig is never set in RouterUrlRoute, so CloudFront does not sign requests to the Lambda URL.
The docs say:
When set, all Functions and SSR sites routing through this Router automatically inherit the protection mode.
But the implementation never passes this._protectionMode to RouterUrlRoute.
Reproduction
const router = new sst.aws.Router("MyRouter", {
protection: "oac-with-edge-signing",
});
// OAC is NOT applied — Lambda URL receives unsigned requests
router.route("app1.example.com", lambdaFunctionUrl);
Root cause
In router.ts, route() creates RouterUrlRoute without passing protection:
new RouterUrlRoute(`${this.constructorName}Route${pattern}`, {
store: this.kvStoreArn!,
routerNamespace: this.kvNamespace!,
pattern,
url,
routeArgs: args,
// ← this._protectionMode is never passed
});
And RouterUrlRoute never sets originAccessControlConfig for Lambda URLs.
Workaround
Patching .sst/platform/src/components/aws/router-url-route.ts on every deploy:
...(host.includes("lambda-url") ? {
originAccessControlConfig: {
enabled: true,
signingBehavior: "always",
signingProtocol: "sigv4",
originType: "lambda",
},
} : {}),
This works but applies OAC unconditionally regardless of the Router's protection setting.
Proposed fix
Pass the Router's protection mode to RouterUrlRoute, and apply originAccessControlConfig only when the mode is oac or oac-with-edge-signing. Also add a per-route
protection field to RouterUrlRouteArgs for explicit override.
diff --git a/platform/src/components/aws/router-url-route.ts b/platform/src/components/aws/router-url-route.ts
index a817c5e33..3e7656ad5 100644
--- a/platform/src/components/aws/router-url-route.ts
+++ b/platform/src/components/aws/router-url-route.ts
@@ -19,6 +19,11 @@ export interface Args extends RouterBaseRouteArgs {
* Additional arguments for the route.
*/
routeArgs?: Input<RouterUrlRouteArgs>;
+ /**
+ * The protection mode for this route, inherited from the Router's `protection`
+ * setting. Can be overridden per-route via `RouterUrlRouteArgs.protection`.
+ */
+ protection?: Input<"none" | "oac" | "oac-with-edge-signing">;
}
@@ -37,12 +42,17 @@ export class RouterUrlRoute extends Component {
- all([args.url, args.pattern, args.routeArgs]).apply(
- ([url, pattern, routeArgs]) => {
+ all([args.url, args.pattern, args.routeArgs, args.protection]).apply(
+ ([url, pattern, routeArgs, protection]) => {
const u = new URL(url);
const host = u.host;
const protocol = u.protocol.slice(0, -1);
+ const isLambdaUrl = host.includes("lambda-url");
+ const useOac =
+ isLambdaUrl &&
+ (protection === "oac" || protection === "oac-with-edge-signing");
+
const patternData = parsePattern(pattern);
const namespace = buildKvNamespace(name);
createKvRouteData(name, args, self, namespace, {
@@ -51,6 +61,16 @@ export class RouterUrlRoute extends Component {
origin: {
protocol: protocol === "https" ? undefined : protocol,
connectionAttempts: routeArgs?.connectionAttempts,
+ ...(useOac
+ ? {
+ originAccessControlConfig: {
+ enabled: true,
+ signingBehavior: "always",
+ signingProtocol: "sigv4",
+ originType: "lambda",
+ },
+ }
+ : {}),
timeouts: (() => {
diff --git a/platform/src/components/aws/router.ts b/platform/src/components/aws/router.ts
@@ -429,6 +429,13 @@ export interface RouterUrlRouteArgs extends RouteArgs {
keepAliveTimeout?: Input<DurationSeconds>;
+ /**
+ * Override the protection mode for this specific route.
+ * When not set, inherits the Router's `protection` setting.
+ */
+ protection?: Input<"none" | "oac" | "oac-with-edge-signing">;
}
@@ -2537,8 +2559,8 @@ async function handler(event) {
- all([pattern, args, this.hasInlineRoutes]).apply(
- ([pattern, args, hasInlineRoutes]) => {
+ all([pattern, args, this.hasInlineRoutes, this._protectionMode]).apply(
+ ([pattern, args, hasInlineRoutes, routerProtection]) => {
...
new RouterUrlRoute(..., {
...
+ protection: args?.protection ?? routerProtection.mode,
});
Happy to open a PR if the direction looks good.
Bug
When a
Routeris configured withprotection: "oac-with-edge-signing", routes added viarouter.route(lambdaUrl)do not have OAC applied. TheoriginAccessControlConfigis never set inRouterUrlRoute, so CloudFront does not sign requests to the Lambda URL.The docs say:
But the implementation never passes
this._protectionModetoRouterUrlRoute.Reproduction
Root cause
In
router.ts,route()createsRouterUrlRoutewithout passingprotection:And
RouterUrlRoutenever setsoriginAccessControlConfigfor Lambda URLs.Workaround
Patching
.sst/platform/src/components/aws/router-url-route.tson every deploy:This works but applies OAC unconditionally regardless of the Router's
protectionsetting.Proposed fix
Pass the Router's
protectionmode toRouterUrlRoute, and applyoriginAccessControlConfigonly when the mode isoacoroac-with-edge-signing. Also add a per-routeprotectionfield toRouterUrlRouteArgsfor explicit override.Happy to open a PR if the direction looks good.