-
Notifications
You must be signed in to change notification settings - Fork 178
Expand file tree
/
Copy pathprotected-api-key-auth.node.test.ts
More file actions
119 lines (109 loc) · 3.47 KB
/
Copy pathprotected-api-key-auth.node.test.ts
File metadata and controls
119 lines (109 loc) · 3.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import { describe, expect, it } from "@effect/vitest";
import { Effect, Layer } from "effect";
import { ApiKeyService } from "../auth/api-keys";
import { UserStoreService } from "../auth/context";
import { WorkOSClient, type WorkOSClientService } from "../auth/workos";
import { resolveProtectedPrincipal } from "./protected";
const createdAt = new Date("2026-01-01T00:00:00.000Z");
const stubApiKeys = Layer.succeed(ApiKeyService)({
validate: (value: string) =>
Effect.succeed(
value === "valid_user_key"
? {
accountId: "user_123",
organizationId: "org_123",
keyId: "api_key_123",
}
: null,
),
listUserKeys: () => Effect.succeed([]),
createUserKey: () => Effect.die("protected API auth test does not create API keys"),
revokeUserKey: () => Effect.void,
});
const stubWorkOS = Layer.succeed(
WorkOSClient,
new Proxy({} as WorkOSClientService, {
get: (_target, prop) => {
if (prop === "listUserMemberships") {
return (userId: string) =>
Effect.succeed({
data:
userId === "user_123"
? [{ userId, organizationId: "org_123", status: "active" }]
: [],
});
}
return () => Effect.die(`unexpected WorkOSClient.${String(prop)} call`);
},
}),
);
const stubUsers = Layer.succeed(UserStoreService)({
use: (fn) =>
Effect.promise(() =>
fn({
ensureAccount: async (id: string) => ({ id, createdAt }),
getAccount: async (id: string) => ({ id, createdAt }),
upsertOrganization: async (org: { id: string; name: string }) => ({
...org,
slug: `org-slug-${org.id}`,
createdAt,
}),
getOrganization: async (id: string) => ({
id,
name: `Org ${id}`,
slug: `org-slug-${id}`,
createdAt,
}),
getOrganizationBySlug: async (slug: string) => ({
id: "org_by_slug",
name: `Org ${slug}`,
slug,
createdAt,
}),
}),
),
});
const run = (request: Request) =>
resolveProtectedPrincipal(request).pipe(
Effect.provide(Layer.mergeAll(stubApiKeys, stubWorkOS, stubUsers)),
);
describe("protected API key auth", () => {
it.effect("resolves a valid bearer API key into protected identity", () =>
Effect.gen(function* () {
const identity = yield* run(
new Request("https://executor.test/api/tools", {
headers: { authorization: "Bearer valid_user_key" },
}),
);
expect(identity).toEqual({
accountId: "user_123",
organizationId: "org_123",
organizationName: "Org org_123",
organizationSlug: "org-slug-org_123",
email: "",
name: null,
avatarUrl: null,
roles: [],
});
}),
);
it.effect("rejects invalid bearer API keys", () =>
Effect.gen(function* () {
const error = yield* Effect.flip(
run(
new Request("https://executor.test/api/tools", {
headers: { authorization: "Bearer invalid_user_key" },
}),
),
);
// The resolver now raises the SHARED `Unauthorized` carrying the same
// machine code; cloud's failure strategy renders it as the byte-identical
// 401 `{ error: "Invalid API key", code: "invalid_api_key" }`.
expect(error).toMatchObject({
_tag: "Unauthorized",
code: "invalid_api_key",
message: "Invalid API key",
});
}),
);
});