Skip to content

Commit 637a2bb

Browse files
committed
test(webapp): pin that an ordinary PAT still passes the PAT-only helper
1 parent 8fbbcf0 commit 637a2bb

1 file changed

Lines changed: 30 additions & 3 deletions

File tree

apps/webapp/test/userActorTokenClaimsAndScopes.test.ts

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/**
22
* Two seams a delegated user-actor token meets outside the route builder: the PAT-only
3-
* authentication (which enforces nothing, so it refuses the token outright), and the
3+
* authentication (which enforces nothing, so it refuses the token outright while still
4+
* authenticating an ordinary PAT), and the
45
* environment JWT exchange (which ceilings the minted scopes by the token's cap and only
56
* mints for the environment it was signed for).
67
*/
@@ -24,7 +25,10 @@ vi.mock("~/db.server", () => {
2425
return { prisma: proxy, $replica: proxy, sqlDatabaseSchema: undefined };
2526
});
2627
vi.mock("~/env.server", () => ({
27-
env: { SESSION_SECRET: "test-session-secret-for-user-actor-claims" },
28+
env: {
29+
SESSION_SECRET: "test-session-secret-for-user-actor-claims",
30+
ENCRYPTION_KEY: "12345678901234567890123456789012",
31+
},
2832
}));
2933
vi.mock("~/services/logger.server", () => ({
3034
logger: { debug: vi.fn(), error: vi.fn(), warn: vi.fn(), info: vi.fn() },
@@ -63,7 +67,7 @@ vi.mock("~/services/rbac.server", async () => {
6367
};
6468
});
6569

66-
const { authenticateApiRequestWithPersonalAccessToken } =
70+
const { authenticateApiRequestWithPersonalAccessToken, createPersonalAccessToken } =
6771
await import("~/services/personalAccessToken.server");
6872
const { action: jwtAction } = await import("~/routes/api.v1.projects.$projectRef.$env.jwt");
6973

@@ -108,6 +112,29 @@ function suffix() {
108112
return Math.random().toString(36).slice(2, 10);
109113
}
110114

115+
// The other direction: the refusal is aimed at the token type only, so an ordinary PAT still
116+
// authenticates through the same helper.
117+
postgresTest(
118+
"authenticates an ordinary personal access token",
119+
async ({ prisma }) => {
120+
ctx.prisma = prisma;
121+
const user = await prisma.user.create({
122+
data: { email: `pat_${suffix()}@example.com`, authenticationMethod: "MAGIC_LINK" },
123+
});
124+
const pat = await createPersonalAccessToken({ name: "claims-test", userId: user.id });
125+
126+
const result = await authenticateApiRequestWithPersonalAccessToken(bearer(pat.token));
127+
128+
expect(result?.userId).toBe(user.id);
129+
130+
// And it is the stored token that authenticates, not the prefix.
131+
expect(
132+
await authenticateApiRequestWithPersonalAccessToken(bearer(`tr_pat_${suffix()}`))
133+
).toBeUndefined();
134+
},
135+
60_000
136+
);
137+
111138
/** An org with one project, a prod and a staging environment, and a member user. */
112139
async function seedProject(prisma: PrismaClient) {
113140
const slug = `jwt_${suffix()}`;

0 commit comments

Comments
 (0)