Skip to content

Commit 6464eee

Browse files
authored
fix(webapp): correctly generate JWT tokens for preview branches after triggering a run (fix #2678) (#2695)
1 parent bee59de commit 6464eee

File tree

12 files changed

+207
-57
lines changed

12 files changed

+207
-57
lines changed

apps/webapp/app/routes/api.v1.tasks.$taskId.trigger.ts

Lines changed: 19 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { prisma } from "~/db.server";
1111
import { env } from "~/env.server";
1212
import { ApiAuthenticationResultSuccess, getOneTimeUseToken } from "~/services/apiAuth.server";
1313
import { logger } from "~/services/logger.server";
14+
import { extractJwtSigningSecretKey } from "~/services/realtime/jwtAuth.server";
1415
import { determineRealtimeStreamsVersion } from "~/services/realtime/v1StreamsGlobal.server";
1516
import { createActionApiRoute } from "~/services/routeBuilders/apiBuilder.server";
1617
import { resolveIdempotencyKeyTTL } from "~/utils/idempotencyKeys.server";
@@ -85,7 +86,7 @@ const { action, loader } = createActionApiRoute(
8586
isCached: false,
8687
}),
8788
buildResponseHeaders: async (responseBody, cachedEntity) => {
88-
return await responseHeaders(cachedEntity, authentication, triggerClient);
89+
return await responseHeaders(cachedEntity, authentication);
8990
},
9091
});
9192

@@ -140,7 +141,12 @@ const { action, loader } = createActionApiRoute(
140141

141142
await saveRequestIdempotency(requestIdempotencyKey, "trigger", result.run.id);
142143

143-
const $responseHeaders = await responseHeaders(result.run, authentication, triggerClient);
144+
const $responseHeaders = await responseHeaders(result.run, authentication);
145+
146+
logger.debug("responseHeaders authentication", {
147+
authentication,
148+
responseHeaders: $responseHeaders,
149+
});
144150

145151
return json(
146152
{
@@ -170,39 +176,26 @@ const { action, loader } = createActionApiRoute(
170176

171177
async function responseHeaders(
172178
run: Pick<TaskRun, "friendlyId">,
173-
authentication: ApiAuthenticationResultSuccess,
174-
triggerClient?: string | null
179+
authentication: ApiAuthenticationResultSuccess
175180
): Promise<Record<string, string>> {
176181
const { environment, realtime } = authentication;
177182

178-
const claimsHeader = JSON.stringify({
183+
const claims = {
179184
sub: environment.id,
180185
pub: true,
186+
scopes: [`read:runs:${run.friendlyId}`],
181187
realtime,
182-
});
183-
184-
if (triggerClient === "browser") {
185-
const claims = {
186-
sub: environment.id,
187-
pub: true,
188-
scopes: [`read:runs:${run.friendlyId}`],
189-
realtime,
190-
};
191-
192-
const jwt = await internal_generateJWT({
193-
secretKey: environment.apiKey,
194-
payload: claims,
195-
expirationTime: "1h",
196-
});
188+
};
197189

198-
return {
199-
"x-trigger-jwt-claims": claimsHeader,
200-
"x-trigger-jwt": jwt,
201-
};
202-
}
190+
const jwt = await internal_generateJWT({
191+
secretKey: extractJwtSigningSecretKey(environment),
192+
payload: claims,
193+
expirationTime: "1h",
194+
});
203195

204196
return {
205-
"x-trigger-jwt-claims": claimsHeader,
197+
"x-trigger-jwt-claims": JSON.stringify(claims),
198+
"x-trigger-jwt": jwt,
206199
};
207200
}
208201

apps/webapp/app/routes/api.v1.tasks.batch.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
import { OutOfEntitlementError } from "~/v3/services/triggerTask.server";
1818
import { HeadersSchema } from "./api.v1.tasks.$taskId.trigger";
1919
import { determineRealtimeStreamsVersion } from "~/services/realtime/v1StreamsGlobal.server";
20+
import { extractJwtSigningSecretKey } from "~/services/realtime/jwtAuth.server";
2021

2122
const { action, loader } = createActionApiRoute(
2223
{
@@ -163,7 +164,7 @@ async function responseHeaders(
163164
};
164165

165166
const jwt = await generateJWT({
166-
secretKey: environment.apiKey,
167+
secretKey: extractJwtSigningSecretKey(environment),
167168
payload: claims,
168169
expirationTime: "1h",
169170
});

apps/webapp/app/routes/api.v2.tasks.batch.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { BatchProcessingStrategy } from "~/v3/services/batchTriggerV3.server";
1919
import { OutOfEntitlementError } from "~/v3/services/triggerTask.server";
2020
import { HeadersSchema } from "./api.v1.tasks.$taskId.trigger";
2121
import { determineRealtimeStreamsVersion } from "~/services/realtime/v1StreamsGlobal.server";
22+
import { extractJwtSigningSecretKey } from "~/services/realtime/jwtAuth.server";
2223

2324
const { action, loader } = createActionApiRoute(
2425
{
@@ -178,7 +179,7 @@ async function responseHeaders(
178179
};
179180

180181
const jwt = await generateJWT({
181-
secretKey: environment.apiKey,
182+
secretKey: extractJwtSigningSecretKey(environment),
182183
payload: claims,
183184
expirationTime: "1h",
184185
});

apps/webapp/app/services/apiAuth.server.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,8 @@ async function authenticateApiKeyWithFailure(
236236
case "PUBLIC_JWT": {
237237
const validationResults = await validatePublicJwtKey(result.apiKey);
238238

239+
logger.debug("validatePublicJwtKey", { validationResults });
240+
239241
if (!validationResults.ok) {
240242
return validationResults;
241243
}

apps/webapp/app/services/realtime/jwtAuth.server.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { json } from "@remix-run/server-runtime";
22
import { validateJWT } from "@trigger.dev/core/v3/jwt";
33
import { findEnvironmentById } from "~/models/runtimeEnvironment.server";
44
import { AuthenticatedEnvironment } from "../apiAuth.server";
5+
import { logger } from "../logger.server";
56

67
export type ValidatePublicJwtKeySuccess = {
78
ok: true;
@@ -38,6 +39,8 @@ export async function validatePublicJwtKey(token: string): Promise<ValidatePubli
3839
environment.parentEnvironment?.apiKey ?? environment.apiKey
3940
);
4041

42+
logger.debug("validateJWT result", { result });
43+
4144
if (!result.ok) {
4245
switch (result.code) {
4346
case "ERR_JWT_EXPIRED": {
@@ -89,6 +92,12 @@ export function isPublicJWT(token: string): boolean {
8992
}
9093
}
9194

95+
export function extractJwtSigningSecretKey(
96+
environment: AuthenticatedEnvironment & { parentEnvironment?: { apiKey: string } }
97+
) {
98+
return environment.parentEnvironment?.apiKey ?? environment.apiKey;
99+
}
100+
92101
function extractJWTSub(token: string): string | undefined {
93102
// Split the token
94103
const parts = token.split(".");

0 commit comments

Comments
 (0)