@parlor/auth 0.3.2 → 0.4.0
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.
- package/dist/audit.d.ts +2 -1
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js +15 -4
- package/dist/audit.js.map +1 -1
- package/dist/provider.d.ts +9 -3
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +39 -3
- package/dist/provider.js.map +1 -1
- package/dist/tokens.d.ts +8 -2
- package/dist/tokens.d.ts.map +1 -1
- package/dist/tokens.js +8 -2
- package/dist/tokens.js.map +1 -1
- package/package.json +7 -7
package/dist/audit.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type DataProvider } from "@parlor/core";
|
|
2
2
|
import type { ActionAudit, Migration } from "@parlor/server";
|
|
3
3
|
export declare const AUDIT_MIGRATION: Migration;
|
|
4
|
+
export declare const AUDIT_KEY_MIGRATION: Migration;
|
|
4
5
|
export interface AuditLog {
|
|
5
6
|
record(audit: ActionAudit): void;
|
|
6
7
|
flush(): Promise<void>;
|
package/dist/audit.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,YAAY,EAAU,MAAM,cAAc,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAK7D,eAAO,MAAM,eAAe,EAAE,SAiC7B,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,SAKjC,CAAC;AAqCF,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAAC;IACjC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED,wBAAgB,cAAc,CAAC,QAAQ,EAAE,YAAY,GAAG,QAAQ,CAkE/D"}
|
package/dist/audit.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { userOf } from "@parlor/core";
|
|
1
2
|
import { sql } from "drizzle-orm";
|
|
2
3
|
export const AUDIT_MIGRATION = {
|
|
3
4
|
id: "auth/0006_audit",
|
|
@@ -33,15 +34,25 @@ export const AUDIT_MIGRATION = {
|
|
|
33
34
|
before update or delete on parlor_auth_audit
|
|
34
35
|
for each row execute function parlor_auth_audit_append_only()`,
|
|
35
36
|
};
|
|
37
|
+
export const AUDIT_KEY_MIGRATION = {
|
|
38
|
+
id: "auth/0008_audit_key",
|
|
39
|
+
sql: `
|
|
40
|
+
alter table parlor_auth_audit add column key_id text, add column key_name text;
|
|
41
|
+
create index parlor_auth_audit_by_key on parlor_auth_audit (key_id, at)`,
|
|
42
|
+
};
|
|
36
43
|
const FLUSH_MS = 250;
|
|
37
44
|
const FLUSH_AT = 100;
|
|
38
45
|
const KEEP_AT_MOST = 10_000;
|
|
39
46
|
function audited({ principal, stage, confirmation }) {
|
|
40
|
-
return principal.kind === "agent" ||
|
|
47
|
+
return (principal.kind === "agent" ||
|
|
48
|
+
principal.kind === "key" ||
|
|
49
|
+
stage === "refused" ||
|
|
50
|
+
confirmation !== undefined);
|
|
41
51
|
}
|
|
42
52
|
function rowOf(audit) {
|
|
43
53
|
const { principal } = audit;
|
|
44
|
-
const user = principal
|
|
54
|
+
const user = userOf(principal);
|
|
55
|
+
const key = principal.kind === "key" ? principal : undefined;
|
|
45
56
|
const grant = principal.kind === "agent" || principal.kind === "host"
|
|
46
57
|
? principal.grantId
|
|
47
58
|
: undefined;
|
|
@@ -56,7 +67,7 @@ function rowOf(audit) {
|
|
|
56
67
|
${principal.kind === "agent" ? principal.agent.verified : null},
|
|
57
68
|
${turn?.threadId ?? null}, ${turn?.turnId ?? null},
|
|
58
69
|
${audit.source}, ${audit.scope}, ${audit.inputDigest}, ${audit.stage}, ${audit.outcome},
|
|
59
|
-
${audit.confirmation ?? null})`;
|
|
70
|
+
${audit.confirmation ?? null}, ${key?.keyId ?? null}, ${key?.name ?? null})`;
|
|
60
71
|
}
|
|
61
72
|
export function createAuditLog(database) {
|
|
62
73
|
let queued = [];
|
|
@@ -74,7 +85,7 @@ export function createAuditLog(database) {
|
|
|
74
85
|
insert into parlor_auth_audit
|
|
75
86
|
(at, action, actor_kind, user_id, grant_id, session_id, device_id, host_id,
|
|
76
87
|
agent_name, agent_verified, thread_id, turn_id, source, scope, input_digest,
|
|
77
|
-
stage, outcome, confirmation)
|
|
88
|
+
stage, outcome, confirmation, key_id, key_name)
|
|
78
89
|
values ${sql.join(batch.map(rowOf), sql `, `)}`);
|
|
79
90
|
});
|
|
80
91
|
}
|
package/dist/audit.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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","sourcesContent":["import { type DataProvider, userOf } from \"@parlor/core\";\nimport type { ActionAudit, Migration } from \"@parlor/server\";\nimport { type SQL, sql } from \"drizzle-orm\";\n\nimport type { Database } from \"./database.js\";\n\nexport const AUDIT_MIGRATION: Migration = {\n id: \"auth/0006_audit\",\n sql: `\n create table parlor_auth_audit (\n id bigint generated always as identity primary key,\n at timestamptz not null,\n action text not null,\n actor_kind text not null,\n user_id text,\n grant_id text,\n session_id text,\n device_id text,\n host_id text,\n agent_name text,\n agent_verified boolean,\n thread_id text,\n turn_id text,\n source text not null,\n scope text not null,\n input_digest text not null,\n stage text not null,\n outcome text not null,\n confirmation text\n );\n create index parlor_auth_audit_by_user on parlor_auth_audit (user_id, at);\n create function parlor_auth_audit_append_only() returns trigger language plpgsql as $$\n begin\n raise exception 'parlor_auth_audit is append-only';\n end\n $$;\n create trigger parlor_auth_audit_append_only\n before update or delete on parlor_auth_audit\n for each row execute function parlor_auth_audit_append_only()`,\n};\n\nexport const AUDIT_KEY_MIGRATION: Migration = {\n id: \"auth/0008_audit_key\",\n sql: `\n alter table parlor_auth_audit add column key_id text, add column key_name text;\n create index parlor_auth_audit_by_key on parlor_auth_audit (key_id, at)`,\n};\n\nconst FLUSH_MS = 250;\nconst FLUSH_AT = 100;\nconst KEEP_AT_MOST = 10_000;\n\nfunction audited({ principal, stage, confirmation }: ActionAudit): boolean {\n return (\n principal.kind === \"agent\" ||\n principal.kind === \"key\" ||\n stage === \"refused\" ||\n confirmation !== undefined\n );\n}\n\nfunction rowOf(audit: ActionAudit): SQL {\n const { principal } = audit;\n const user = userOf(principal);\n const key = principal.kind === \"key\" ? principal : undefined;\n const grant =\n principal.kind === \"agent\" || principal.kind === \"host\"\n ? principal.grantId\n : undefined;\n const turn = principal.kind === \"agent\" ? principal.turn : undefined;\n const host = principal.kind === \"host\" ? principal.hostId : turn?.hostId;\n return sql`(${new Date(audit.at).toISOString()}, ${audit.action}, ${principal.kind},\n ${user ?? null}, ${grant ?? null},\n ${principal.kind === \"user\" ? principal.sessionId : null},\n ${principal.kind === \"user\" ? (principal.deviceId ?? null) : null},\n ${host ?? null},\n ${principal.kind === \"agent\" ? principal.agent.name : null},\n ${principal.kind === \"agent\" ? principal.agent.verified : null},\n ${turn?.threadId ?? null}, ${turn?.turnId ?? null},\n ${audit.source}, ${audit.scope}, ${audit.inputDigest}, ${audit.stage}, ${audit.outcome},\n ${audit.confirmation ?? null}, ${key?.keyId ?? null}, ${key?.name ?? null})`;\n}\n\nexport interface AuditLog {\n record(audit: ActionAudit): void;\n flush(): Promise<void>;\n stop(): Promise<void>;\n}\n\nexport function createAuditLog(database: DataProvider): AuditLog {\n let queued: ActionAudit[] = [];\n let timer: ReturnType<typeof setTimeout> | undefined;\n let writing: Promise<void> = Promise.resolve();\n let stopped = false;\n\n const write = async () => {\n if (queued.length === 0) return;\n const batch = queued;\n queued = [];\n try {\n await database.transaction(async (tx) => {\n await (tx as Database).execute(sql`\n insert into parlor_auth_audit\n (at, action, actor_kind, user_id, grant_id, session_id, device_id, host_id,\n agent_name, agent_verified, thread_id, turn_id, source, scope, input_digest,\n stage, outcome, confirmation, key_id, key_name)\n values ${sql.join(batch.map(rowOf), sql`, `)}`);\n });\n } catch (error) {\n queued = [...batch, ...queued].slice(-KEEP_AT_MOST);\n throw error;\n }\n };\n\n const flush = () => {\n if (timer !== undefined) clearTimeout(timer);\n timer = undefined;\n const next = writing.then(write, write);\n writing = next.catch(() => {});\n return next;\n };\n\n const schedule = () => {\n if (timer !== undefined || stopped) return;\n timer = setTimeout(() => {\n timer = undefined;\n flush().catch((error: unknown) => {\n console.error(\"[parlor] audit write failed, will retry:\", error);\n schedule();\n });\n }, FLUSH_MS);\n timer.unref?.();\n };\n\n return {\n record(audit) {\n if (!audited(audit)) return;\n queued.push(audit);\n if (queued.length >= FLUSH_AT) {\n flush().catch((error: unknown) => {\n console.error(\"[parlor] audit write failed, will retry:\", error);\n schedule();\n });\n } else {\n schedule();\n }\n },\n flush,\n async stop() {\n stopped = true;\n await flush().catch((error: unknown) => {\n console.error(\"[parlor] audit write failed on shutdown:\", error);\n });\n },\n };\n}\n"]}
|
package/dist/provider.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AuthProvider } from "@parlor/server";
|
|
1
|
+
import { type AuthProvider, type KeyVerifier } from "@parlor/server";
|
|
2
2
|
import { type BetterAuthOptions } from "better-auth";
|
|
3
3
|
/** The slice of a Better Auth instance Parlor relies on. */
|
|
4
4
|
export interface BetterAuthInstance {
|
|
@@ -61,7 +61,7 @@ export interface StoredSession {
|
|
|
61
61
|
readonly ipAddress?: string | null | undefined;
|
|
62
62
|
readonly userAgent?: string | null | undefined;
|
|
63
63
|
}
|
|
64
|
-
export type BetterAuthProviderOptions = {
|
|
64
|
+
export type BetterAuthProviderOptions = ({
|
|
65
65
|
readonly instance: BetterAuthInstance;
|
|
66
66
|
} | {
|
|
67
67
|
/**
|
|
@@ -70,11 +70,17 @@ export type BetterAuthProviderOptions = {
|
|
|
70
70
|
* runtimes, such as Cloudflare's, allow no I/O while the app loads.
|
|
71
71
|
*/
|
|
72
72
|
readonly options: BetterAuthOptions;
|
|
73
|
+
}) & {
|
|
74
|
+
/**
|
|
75
|
+
* The app's API keys: a `Bearer` token that starts with `keys.prefix` becomes the key
|
|
76
|
+
* principal `keys.verify` answers. Keys reach actions, MCP and the manifest only.
|
|
77
|
+
*/
|
|
78
|
+
readonly keys?: KeyVerifier | undefined;
|
|
73
79
|
};
|
|
74
80
|
/**
|
|
75
81
|
* Sessions become user principals: a cookie on the same-origin web, a bearer token in
|
|
76
82
|
* native shells. Access tokens Better Auth issued to MCP clients become agent principals
|
|
77
|
-
* without a turn.
|
|
83
|
+
* without a turn, and the app's API keys, with `keys`, key principals.
|
|
78
84
|
*/
|
|
79
85
|
export declare function betterAuthProvider(provided: BetterAuthProviderOptions): AuthProvider;
|
|
80
86
|
export {};
|
package/dist/provider.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}
|
package/dist/provider.js
CHANGED
|
@@ -4,7 +4,7 @@ import { AuthFailure, REVOCATION_HORIZON_MS, } from "@parlor/server";
|
|
|
4
4
|
import { betterAuth } from "better-auth";
|
|
5
5
|
import { createLocalJWKSet, decodeProtectedHeader, errors, jwtVerify, } from "jose";
|
|
6
6
|
import { accountActions } from "./account.js";
|
|
7
|
-
import { AUDIT_MIGRATION, createAuditLog } from "./audit.js";
|
|
7
|
+
import { AUDIT_KEY_MIGRATION, AUDIT_MIGRATION, createAuditLog } from "./audit.js";
|
|
8
8
|
import { AUTH_PLUGIN, bridgeOf, MCP_SCOPE, } from "./better-auth.js";
|
|
9
9
|
import { createDeviceRegistry, deviceAccountActions, DEVICE_LINKING_MIGRATION, DEVICES_MIGRATION, } from "./devices.js";
|
|
10
10
|
import { grantIdOf } from "./grants.js";
|
|
@@ -14,6 +14,24 @@ import { RevocationSet } from "./revocation.js";
|
|
|
14
14
|
import { authRoutes } from "./routes.js";
|
|
15
15
|
import { agentPrincipalOf, credentialOf, delegate, delegateAgent, outsideAgentPrincipalOf, verifyAgentToken, verifyTurnToken, } from "./tokens.js";
|
|
16
16
|
import { createTurnKeyStore, TURN_KEYS_MIGRATION, } from "./turn-keys.js";
|
|
17
|
+
/** A prefix of letters and digits alone could start a Better Auth session token. */
|
|
18
|
+
function checkKeyPrefix({ prefix }) {
|
|
19
|
+
if (!/[^A-Za-z0-9]/.test(prefix)) {
|
|
20
|
+
throw new Error(`The API key prefix "${prefix}" needs a character other than a letter or digit, such as "_", so no session token starts with it.`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function isKeyPrincipal(value) {
|
|
24
|
+
if (typeof value !== "object" || value === null)
|
|
25
|
+
return false;
|
|
26
|
+
const key = value;
|
|
27
|
+
return (key.kind === "key" &&
|
|
28
|
+
typeof key.keyId === "string" &&
|
|
29
|
+
typeof key.scope === "string" &&
|
|
30
|
+
key.scope !== "" &&
|
|
31
|
+
typeof key.name === "string" &&
|
|
32
|
+
typeof key.claims === "object" &&
|
|
33
|
+
key.claims !== null);
|
|
34
|
+
}
|
|
17
35
|
/** Stands in for the instance until the first call needs it. */
|
|
18
36
|
function deferredInstance(options) {
|
|
19
37
|
let created;
|
|
@@ -36,10 +54,13 @@ function hasCookie(request, name) {
|
|
|
36
54
|
/**
|
|
37
55
|
* Sessions become user principals: a cookie on the same-origin web, a bearer token in
|
|
38
56
|
* native shells. Access tokens Better Auth issued to MCP clients become agent principals
|
|
39
|
-
* without a turn.
|
|
57
|
+
* without a turn, and the app's API keys, with `keys`, key principals.
|
|
40
58
|
*/
|
|
41
59
|
export function betterAuthProvider(provided) {
|
|
42
60
|
const instance = "instance" in provided ? provided.instance : deferredInstance(provided.options);
|
|
61
|
+
const apiKeys = provided.keys;
|
|
62
|
+
if (apiKeys)
|
|
63
|
+
checkKeyPrefix(apiKeys);
|
|
43
64
|
const bridge = bridgeOf(instance.options);
|
|
44
65
|
const settings = bridge.settings;
|
|
45
66
|
let revocations;
|
|
@@ -187,10 +208,24 @@ export function betterAuthProvider(provided) {
|
|
|
187
208
|
}
|
|
188
209
|
return outsideAgentPrincipalOf(claims);
|
|
189
210
|
};
|
|
211
|
+
const keyOf = async (secret, request) => {
|
|
212
|
+
const key = await apiKeys?.verify(secret, request);
|
|
213
|
+
if (!key) {
|
|
214
|
+
throw new AuthFailure("invalid", "The API key is invalid or revoked.", {
|
|
215
|
+
challenge: false,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
if (!isKeyPrincipal(key)) {
|
|
219
|
+
throw new TypeError('keys.verify must answer a key principal: { kind: "key", keyId, scope, name, claims }.');
|
|
220
|
+
}
|
|
221
|
+
return key;
|
|
222
|
+
};
|
|
190
223
|
const authenticateRequest = async (request) => {
|
|
191
224
|
await ready();
|
|
192
|
-
const credential = credentialOf(request.headers.get("authorization"));
|
|
225
|
+
const credential = credentialOf(request.headers.get("authorization"), apiKeys?.prefix);
|
|
193
226
|
switch (credential?.kind) {
|
|
227
|
+
case "key":
|
|
228
|
+
return keyOf(credential.secret, request);
|
|
194
229
|
case "host":
|
|
195
230
|
return hostOf(request, credential.assertion);
|
|
196
231
|
case "turn":
|
|
@@ -222,6 +257,7 @@ export function betterAuthProvider(provided) {
|
|
|
222
257
|
TURN_KEYS_MIGRATION,
|
|
223
258
|
AUDIT_MIGRATION,
|
|
224
259
|
DEVICE_LINKING_MIGRATION,
|
|
260
|
+
AUDIT_KEY_MIGRATION,
|
|
225
261
|
],
|
|
226
262
|
enforcing: true,
|
|
227
263
|
setup(host) {
|
package/dist/provider.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type AgentPrincipal,\n ANONYMOUS,\n asId,\n type AuthenticatedPrincipal,\n type DeviceId,\n type GrantId,\n type HostPrincipal,\n type Principal,\n type UserId,\n type UserPrincipal,\n} from \"@parlor/core\";\nimport { createRegistry } from \"@parlor/core/registry\";\nimport {\n type AccountProfile,\n AuthFailure,\n type AuthProvider,\n type Delegation,\n type DeviceKeys,\n type PluginHost,\n REVOCATION_HORIZON_MS,\n type TurnDelegation,\n type AgentDelegation,\n} from \"@parlor/server\";\nimport { betterAuth, type BetterAuthOptions } from \"better-auth\";\nimport {\n createLocalJWKSet,\n decodeProtectedHeader,\n errors,\n type JSONWebKeySet,\n type JWTPayload,\n jwtVerify,\n} from \"jose\";\n\nimport { accountActions } from \"./account.js\";\nimport { AUDIT_MIGRATION, createAuditLog } from \"./audit.js\";\nimport {\n AUTH_PLUGIN,\n bridgeOf,\n MCP_SCOPE,\n type ParlorAuthSettings,\n} from \"./better-auth.js\";\nimport {\n createDeviceRegistry,\n type DeviceRegistry,\n deviceAccountActions,\n DEVICE_LINKING_MIGRATION,\n DEVICES_MIGRATION,\n} from \"./devices.js\";\nimport { grantIdOf } from \"./grants.js\";\nimport {\n createGrantKeys,\n type GrantKeys,\n hostAccountActions,\n hostPrincipalOf,\n HOSTS_MIGRATION,\n hostRoutes,\n verifyHostAssertion,\n} from \"./hosts.js\";\nimport { AUTH_MIGRATIONS } from \"./migrations.js\";\nimport { RevocationSet } from \"./revocation.js\";\nimport { authRoutes } from \"./routes.js\";\nimport {\n type AgentToken,\n agentPrincipalOf,\n credentialOf,\n delegate,\n delegateAgent,\n type HostAssertion,\n outsideAgentPrincipalOf,\n type TurnToken,\n verifyAgentToken,\n verifyTurnToken,\n} from \"./tokens.js\";\nimport {\n createTurnKeyStore,\n TURN_KEYS_MIGRATION,\n type TurnKeyStore,\n} from \"./turn-keys.js\";\n\n/** The slice of a Better Auth instance Parlor relies on. */\nexport interface BetterAuthInstance {\n readonly options: BetterAuthOptions;\n handler(request: Request): Promise<Response>;\n readonly api: {\n getSession(input: { headers: Headers }): Promise<{\n readonly session: { readonly id: string; readonly userId: string };\n readonly user: {\n readonly id: string;\n readonly name: string;\n readonly email: string;\n };\n } | null>;\n };\n readonly $context: Promise<BetterAuthContext>;\n}\n\ninterface Where {\n readonly field: string;\n readonly value: string;\n}\n\nexport interface BetterAuthContext {\n readonly authCookies: { readonly sessionToken: { readonly name: string } };\n readonly adapter: {\n findMany<T>(input: { model: string; where?: Where[] }): Promise<T[]>;\n findOne<T>(input: { model: string; where: Where[] }): Promise<T | null>;\n deleteMany(input: { model: string; where: Where[] }): Promise<number>;\n };\n readonly secret: string;\n readonly internalAdapter: {\n listSessions(userId: string): Promise<StoredSession[]>;\n deleteSession(token: string): Promise<void>;\n };\n}\n\nexport interface StoredSession {\n readonly id: string;\n readonly token: string;\n readonly userId: string;\n readonly createdAt: Date;\n readonly updatedAt: Date;\n readonly expiresAt: Date;\n readonly ipAddress?: string | null | undefined;\n readonly userAgent?: string | null | undefined;\n}\n\nexport type BetterAuthProviderOptions =\n | { readonly instance: BetterAuthInstance }\n | {\n /**\n * The options for `betterAuth()`, which the provider calls on the first request.\n * Better Auth starts querying the database as soon as it is created, and some\n * runtimes, such as Cloudflare's, allow no I/O while the app loads.\n */\n readonly options: BetterAuthOptions;\n };\n\n/** Stands in for the instance until the first call needs it. */\nfunction deferredInstance(options: BetterAuthOptions): BetterAuthInstance {\n let created: BetterAuthInstance | undefined;\n const current = () =>\n (created ??= betterAuth(options) as unknown as BetterAuthInstance);\n return {\n options,\n handler: (request) => current().handler(request),\n api: { getSession: (input) => current().api.getSession(input) },\n get $context() {\n return current().$context;\n },\n };\n}\n\nfunction hasCookie(request: Request, name: string): boolean {\n const cookie = request.headers.get(\"cookie\");\n if (!cookie) return false;\n return cookie.split(\";\").some((part) => part.trim().startsWith(`${name}=`));\n}\n\n/**\n * Sessions become user principals: a cookie on the same-origin web, a bearer token in\n * native shells. Access tokens Better Auth issued to MCP clients become agent principals\n * without a turn.\n */\nexport function betterAuthProvider(provided: BetterAuthProviderOptions): AuthProvider {\n const instance =\n \"instance\" in provided ? provided.instance : deferredInstance(provided.options);\n const bridge = bridgeOf(instance.options);\n const settings: ParlorAuthSettings = bridge.settings;\n let revocations: RevocationSet | undefined;\n let keys: ReturnType<typeof createLocalJWKSet> | undefined;\n let grantKeys: GrantKeys | undefined;\n let turnKeys: TurnKeyStore | undefined;\n let devices: DeviceRegistry | undefined;\n const clientNames = new Map<string, Promise<string>>();\n const authenticatedAt = new WeakMap<object, number>();\n\n const installed = () => {\n if (!grantKeys || !turnKeys || !devices) {\n throw new Error(\"The auth provider is not installed.\");\n }\n return { grantKeys, turnKeys, devices };\n };\n\n const started = () => {\n if (!revocations) throw new Error(\"The auth provider is not installed.\");\n return revocations;\n };\n\n let preparingTurnKeys = false;\n const ready = async (): Promise<void> => {\n await started().ready();\n if (!preparingTurnKeys) {\n preparingTurnKeys = true;\n installed()\n .turnKeys.keys()\n .catch(() => {\n preparingTurnKeys = false;\n });\n }\n };\n\n const loadKeys = async () => {\n const response = await instance.handler(new Request(`${settings.baseURL}/jwks`));\n if (!response.ok)\n throw new Error(`Better Auth answered /jwks with ${response.status}`);\n return createLocalJWKSet((await response.json()) as JSONWebKeySet);\n };\n\n const verify = async (token: string): Promise<JWTPayload> => {\n const options = {\n issuer: settings.baseURL,\n audience: settings.resource,\n typ: \"at+jwt\",\n };\n keys ??= await loadKeys();\n try {\n return (await jwtVerify(token, keys, options)).payload;\n } catch (error) {\n if (!(error instanceof errors.JWKSNoMatchingKey)) throw error;\n keys = await loadKeys();\n return (await jwtVerify(token, keys, options)).payload;\n }\n };\n\n const clientName = (clientId: string): Promise<string> => {\n let name = clientNames.get(clientId);\n if (!name) {\n name = instance.$context\n .then((context) =>\n context.adapter.findOne<{ name?: string | null }>({\n model: \"oauthClient\",\n where: [{ field: \"clientId\", value: clientId }],\n }),\n )\n .then((client) => client?.name || clientId);\n name.catch(() => clientNames.delete(clientId));\n clientNames.set(clientId, name);\n }\n return name;\n };\n\n const agentOf = async (token: string): Promise<AgentPrincipal> => {\n let payload: JWTPayload;\n try {\n payload = await verify(token);\n } catch (error) {\n if (error instanceof errors.JWTExpired) {\n throw new AuthFailure(\"expired\", \"The access token expired.\");\n }\n throw new AuthFailure(\"invalid\", \"The access token is invalid.\");\n }\n const { sub, iat } = payload;\n const clientId = payload.client_id;\n const scopes = typeof payload.scope === \"string\" ? payload.scope.split(\" \") : [];\n if (typeof sub !== \"string\" || typeof clientId !== \"string\" || iat === undefined) {\n throw new AuthFailure(\"invalid\", \"The access token is missing claims.\");\n }\n if (!scopes.includes(MCP_SCOPE)) {\n throw new AuthFailure(\n \"invalid\",\n `The access token lacks the \"${MCP_SCOPE}\" scope.`,\n );\n }\n const grantId = grantIdOf(sub, clientId);\n if (await started().isRevoked({ kind: \"grant\", id: grantId }, iat * 1000)) {\n throw new AuthFailure(\"revoked\", \"Access for this agent was revoked.\");\n }\n return {\n kind: \"agent\",\n userId: asId(\"user\", sub),\n grantId,\n agent: {\n name: await clientName(clientId),\n verified: clientId.startsWith(\"https://\"),\n },\n };\n };\n\n const userOf = async (request: Request): Promise<UserPrincipal | undefined> => {\n const found = await instance.api.getSession({ headers: request.headers });\n if (!found) return undefined;\n return {\n kind: \"user\",\n userId: asId(\"user\", found.user.id),\n sessionId: found.session.id,\n };\n };\n\n const publicUrlOf = (request: Request): string =>\n new URL(new URL(request.url).pathname, settings.origin).href;\n\n const hostOf = async (\n request: Request,\n assertion: HostAssertion,\n ): Promise<HostPrincipal> => {\n const grant = await verifyHostAssertion(\n assertion,\n { method: request.method, url: publicUrlOf(request) },\n installed().grantKeys,\n Date.now(),\n );\n if (await started().isRevoked({ kind: \"grant\", id: grant.grantId })) {\n throw new AuthFailure(\"revoked\", \"This computer was disconnected.\");\n }\n return hostPrincipalOf(grant);\n };\n\n const turnOf = async (token: TurnToken): Promise<AgentPrincipal> => {\n const store = installed().turnKeys;\n let turnTokenKeys = await store.keys();\n const kid = decodeProtectedHeader(token).kid;\n if (kid !== undefined && !turnTokenKeys.publicKeys.has(kid)) {\n turnTokenKeys = await store.refresh();\n }\n const claims = await verifyTurnToken(turnTokenKeys, token, Date.now());\n if (await started().isRevoked({ kind: \"grant\", id: claims.gid })) {\n throw new AuthFailure(\"revoked\", \"This computer was disconnected.\");\n }\n return agentPrincipalOf(claims);\n };\n\n const outsideAgentOf = async (token: AgentToken): Promise<AgentPrincipal> => {\n const store = installed().turnKeys;\n let turnTokenKeys = await store.keys();\n const kid = decodeProtectedHeader(token).kid;\n if (kid !== undefined && !turnTokenKeys.publicKeys.has(kid)) {\n turnTokenKeys = await store.refresh();\n }\n const claims = await verifyAgentToken(turnTokenKeys, token, Date.now());\n if (await started().isRevoked({ kind: \"grant\", id: claims.gid })) {\n throw new AuthFailure(\"revoked\", \"This computer was disconnected.\");\n }\n return outsideAgentPrincipalOf(claims);\n };\n\n const authenticateRequest = async (request: Request): Promise<Principal> => {\n await ready();\n const credential = credentialOf(request.headers.get(\"authorization\"));\n switch (credential?.kind) {\n case \"host\":\n return hostOf(request, credential.assertion);\n case \"turn\":\n return turnOf(credential.token);\n case \"agent\":\n return outsideAgentOf(credential.token);\n case \"access\":\n return agentOf(credential.token);\n case \"session\": {\n const user = await userOf(request);\n if (!user)\n throw new AuthFailure(\"invalid\", \"The session is invalid or has ended.\");\n return user;\n }\n case undefined:\n break;\n }\n const { authCookies } = await instance.$context;\n if (!hasCookie(request, authCookies.sessionToken.name)) return ANONYMOUS;\n return (await userOf(request)) ?? ANONYMOUS;\n };\n\n return {\n name: AUTH_PLUGIN,\n migrations: [\n ...AUTH_MIGRATIONS,\n HOSTS_MIGRATION,\n DEVICES_MIGRATION,\n TURN_KEYS_MIGRATION,\n AUDIT_MIGRATION,\n DEVICE_LINKING_MIGRATION,\n ],\n enforcing: true,\n setup(host: PluginHost) {\n const { database } = host;\n if (!database) throw new Error(\"The auth plugin needs a database.\");\n const set = new RevocationSet({\n database,\n horizonMs: REVOCATION_HORIZON_MS,\n });\n revocations = set;\n const auditLog = createAuditLog(database);\n bridge.revoke = (notice) =>\n database.transaction((tx) => RevocationSet.revoke(tx, notice));\n grantKeys = createGrantKeys(database);\n devices = createDeviceRegistry(database);\n turnKeys = createTurnKeyStore({\n database,\n issuer: settings.baseURL,\n secret: async () => (await instance.$context).secret,\n });\n const hostDeps = {\n host,\n settings,\n };\n return {\n actions: createRegistry({\n ...accountActions({ instance, host, revoke: bridge.revoke }).actions,\n ...hostAccountActions(hostDeps).actions,\n ...deviceAccountActions({ host, registry: devices }).actions,\n }),\n routes: [...authRoutes({ instance, settings, host }), ...hostRoutes(hostDeps)],\n audit: (record) => auditLog.record(record),\n close: async () => {\n await Promise.all([set.stop(), auditLog.stop()]);\n },\n };\n },\n async authenticate(request: Request): Promise<Principal> {\n const startedAt = Date.now();\n const principal = await authenticateRequest(request);\n if (principal.kind !== \"anonymous\") authenticatedAt.set(principal, startedAt);\n return principal;\n },\n challenge(): Response {\n const metadata = `${settings.origin}/.well-known/oauth-protected-resource${new URL(settings.resource).pathname}`;\n return Response.json(\n { error: { code: \"unauthenticated\", message: \"Sign in through OAuth first.\" } },\n {\n status: 401,\n headers: {\n \"www-authenticate\": `Bearer resource_metadata=\"${metadata}\", scope=\"${MCP_SCOPE}\"`,\n },\n },\n );\n },\n async delegate(host: HostPrincipal, turn: TurnDelegation): Promise<Delegation> {\n await ready();\n return delegate(await installed().turnKeys.keys(), host, turn, Date.now());\n },\n async delegateAgent(\n host: HostPrincipal,\n agent: AgentDelegation,\n ): Promise<Delegation> {\n await ready();\n return delegateAgent(await installed().turnKeys.keys(), host, agent, Date.now());\n },\n async hostActive(grantId: GrantId): Promise<boolean> {\n const revoked = await started().isRevoked({ kind: \"grant\", id: grantId });\n return !revoked && (await installed().grantKeys.get(grantId)) !== undefined;\n },\n async device(userId: UserId, deviceId: DeviceId): Promise<DeviceKeys | undefined> {\n const registered = await installed().devices.get(userId, deviceId);\n if (!registered) return undefined;\n const { id, name, platform, signingKey, presenceKey, vouches } = registered;\n return {\n id,\n name,\n platform,\n signingKey,\n presenceKey,\n ...(vouches ? { vouches } : {}),\n };\n },\n async account(userId: UserId): Promise<AccountProfile | undefined> {\n const { adapter } = await instance.$context;\n const user = await adapter.findOne<{ name: string; email: string }>({\n model: \"user\",\n where: [{ field: \"id\", value: userId }],\n });\n return user ? { name: user.name, email: user.email } : undefined;\n },\n revoked(principal: AuthenticatedPrincipal): AbortSignal {\n const notice =\n principal.kind === \"user\"\n ? ({ kind: \"session\", id: principal.sessionId } as const)\n : ({ kind: \"grant\", id: principal.grantId } as const);\n return started().signal([notice], authenticatedAt.get(principal));\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type AgentPrincipal,\n ANONYMOUS,\n asId,\n type AuthenticatedPrincipal,\n type DeviceId,\n type GrantId,\n type HostPrincipal,\n type KeyPrincipal,\n type Principal,\n type UserId,\n type UserPrincipal,\n} from \"@parlor/core\";\nimport { createRegistry } from \"@parlor/core/registry\";\nimport {\n type AccountProfile,\n AuthFailure,\n type AuthProvider,\n type Delegation,\n type DeviceKeys,\n type KeyVerifier,\n type PluginHost,\n REVOCATION_HORIZON_MS,\n type TurnDelegation,\n type AgentDelegation,\n} from \"@parlor/server\";\nimport { betterAuth, type BetterAuthOptions } from \"better-auth\";\nimport {\n createLocalJWKSet,\n decodeProtectedHeader,\n errors,\n type JSONWebKeySet,\n type JWTPayload,\n jwtVerify,\n} from \"jose\";\n\nimport { accountActions } from \"./account.js\";\nimport { AUDIT_KEY_MIGRATION, AUDIT_MIGRATION, createAuditLog } from \"./audit.js\";\nimport {\n AUTH_PLUGIN,\n bridgeOf,\n MCP_SCOPE,\n type ParlorAuthSettings,\n} from \"./better-auth.js\";\nimport {\n createDeviceRegistry,\n type DeviceRegistry,\n deviceAccountActions,\n DEVICE_LINKING_MIGRATION,\n DEVICES_MIGRATION,\n} from \"./devices.js\";\nimport { grantIdOf } from \"./grants.js\";\nimport {\n createGrantKeys,\n type GrantKeys,\n hostAccountActions,\n hostPrincipalOf,\n HOSTS_MIGRATION,\n hostRoutes,\n verifyHostAssertion,\n} from \"./hosts.js\";\nimport { AUTH_MIGRATIONS } from \"./migrations.js\";\nimport { RevocationSet } from \"./revocation.js\";\nimport { authRoutes } from \"./routes.js\";\nimport {\n type AgentToken,\n agentPrincipalOf,\n credentialOf,\n delegate,\n delegateAgent,\n type HostAssertion,\n outsideAgentPrincipalOf,\n type TurnToken,\n verifyAgentToken,\n verifyTurnToken,\n} from \"./tokens.js\";\nimport {\n createTurnKeyStore,\n TURN_KEYS_MIGRATION,\n type TurnKeyStore,\n} from \"./turn-keys.js\";\n\n/** The slice of a Better Auth instance Parlor relies on. */\nexport interface BetterAuthInstance {\n readonly options: BetterAuthOptions;\n handler(request: Request): Promise<Response>;\n readonly api: {\n getSession(input: { headers: Headers }): Promise<{\n readonly session: { readonly id: string; readonly userId: string };\n readonly user: {\n readonly id: string;\n readonly name: string;\n readonly email: string;\n };\n } | null>;\n };\n readonly $context: Promise<BetterAuthContext>;\n}\n\ninterface Where {\n readonly field: string;\n readonly value: string;\n}\n\nexport interface BetterAuthContext {\n readonly authCookies: { readonly sessionToken: { readonly name: string } };\n readonly adapter: {\n findMany<T>(input: { model: string; where?: Where[] }): Promise<T[]>;\n findOne<T>(input: { model: string; where: Where[] }): Promise<T | null>;\n deleteMany(input: { model: string; where: Where[] }): Promise<number>;\n };\n readonly secret: string;\n readonly internalAdapter: {\n listSessions(userId: string): Promise<StoredSession[]>;\n deleteSession(token: string): Promise<void>;\n };\n}\n\nexport interface StoredSession {\n readonly id: string;\n readonly token: string;\n readonly userId: string;\n readonly createdAt: Date;\n readonly updatedAt: Date;\n readonly expiresAt: Date;\n readonly ipAddress?: string | null | undefined;\n readonly userAgent?: string | null | undefined;\n}\n\nexport type BetterAuthProviderOptions = (\n | { readonly instance: BetterAuthInstance }\n | {\n /**\n * The options for `betterAuth()`, which the provider calls on the first request.\n * Better Auth starts querying the database as soon as it is created, and some\n * runtimes, such as Cloudflare's, allow no I/O while the app loads.\n */\n readonly options: BetterAuthOptions;\n }\n) & {\n /**\n * The app's API keys: a `Bearer` token that starts with `keys.prefix` becomes the key\n * principal `keys.verify` answers. Keys reach actions, MCP and the manifest only.\n */\n readonly keys?: KeyVerifier | undefined;\n};\n\n/** A prefix of letters and digits alone could start a Better Auth session token. */\nfunction checkKeyPrefix({ prefix }: KeyVerifier): void {\n if (!/[^A-Za-z0-9]/.test(prefix)) {\n throw new Error(\n `The API key prefix \"${prefix}\" needs a character other than a letter or digit, such as \"_\", so no session token starts with it.`,\n );\n }\n}\n\nfunction isKeyPrincipal(value: unknown): value is KeyPrincipal {\n if (typeof value !== \"object\" || value === null) return false;\n const key = value as Partial<Record<keyof KeyPrincipal, unknown>>;\n return (\n key.kind === \"key\" &&\n typeof key.keyId === \"string\" &&\n typeof key.scope === \"string\" &&\n key.scope !== \"\" &&\n typeof key.name === \"string\" &&\n typeof key.claims === \"object\" &&\n key.claims !== null\n );\n}\n\n/** Stands in for the instance until the first call needs it. */\nfunction deferredInstance(options: BetterAuthOptions): BetterAuthInstance {\n let created: BetterAuthInstance | undefined;\n const current = () =>\n (created ??= betterAuth(options) as unknown as BetterAuthInstance);\n return {\n options,\n handler: (request) => current().handler(request),\n api: { getSession: (input) => current().api.getSession(input) },\n get $context() {\n return current().$context;\n },\n };\n}\n\nfunction hasCookie(request: Request, name: string): boolean {\n const cookie = request.headers.get(\"cookie\");\n if (!cookie) return false;\n return cookie.split(\";\").some((part) => part.trim().startsWith(`${name}=`));\n}\n\n/**\n * Sessions become user principals: a cookie on the same-origin web, a bearer token in\n * native shells. Access tokens Better Auth issued to MCP clients become agent principals\n * without a turn, and the app's API keys, with `keys`, key principals.\n */\nexport function betterAuthProvider(provided: BetterAuthProviderOptions): AuthProvider {\n const instance =\n \"instance\" in provided ? provided.instance : deferredInstance(provided.options);\n const apiKeys = provided.keys;\n if (apiKeys) checkKeyPrefix(apiKeys);\n const bridge = bridgeOf(instance.options);\n const settings: ParlorAuthSettings = bridge.settings;\n let revocations: RevocationSet | undefined;\n let keys: ReturnType<typeof createLocalJWKSet> | undefined;\n let grantKeys: GrantKeys | undefined;\n let turnKeys: TurnKeyStore | undefined;\n let devices: DeviceRegistry | undefined;\n const clientNames = new Map<string, Promise<string>>();\n const authenticatedAt = new WeakMap<object, number>();\n\n const installed = () => {\n if (!grantKeys || !turnKeys || !devices) {\n throw new Error(\"The auth provider is not installed.\");\n }\n return { grantKeys, turnKeys, devices };\n };\n\n const started = () => {\n if (!revocations) throw new Error(\"The auth provider is not installed.\");\n return revocations;\n };\n\n let preparingTurnKeys = false;\n const ready = async (): Promise<void> => {\n await started().ready();\n if (!preparingTurnKeys) {\n preparingTurnKeys = true;\n installed()\n .turnKeys.keys()\n .catch(() => {\n preparingTurnKeys = false;\n });\n }\n };\n\n const loadKeys = async () => {\n const response = await instance.handler(new Request(`${settings.baseURL}/jwks`));\n if (!response.ok)\n throw new Error(`Better Auth answered /jwks with ${response.status}`);\n return createLocalJWKSet((await response.json()) as JSONWebKeySet);\n };\n\n const verify = async (token: string): Promise<JWTPayload> => {\n const options = {\n issuer: settings.baseURL,\n audience: settings.resource,\n typ: \"at+jwt\",\n };\n keys ??= await loadKeys();\n try {\n return (await jwtVerify(token, keys, options)).payload;\n } catch (error) {\n if (!(error instanceof errors.JWKSNoMatchingKey)) throw error;\n keys = await loadKeys();\n return (await jwtVerify(token, keys, options)).payload;\n }\n };\n\n const clientName = (clientId: string): Promise<string> => {\n let name = clientNames.get(clientId);\n if (!name) {\n name = instance.$context\n .then((context) =>\n context.adapter.findOne<{ name?: string | null }>({\n model: \"oauthClient\",\n where: [{ field: \"clientId\", value: clientId }],\n }),\n )\n .then((client) => client?.name || clientId);\n name.catch(() => clientNames.delete(clientId));\n clientNames.set(clientId, name);\n }\n return name;\n };\n\n const agentOf = async (token: string): Promise<AgentPrincipal> => {\n let payload: JWTPayload;\n try {\n payload = await verify(token);\n } catch (error) {\n if (error instanceof errors.JWTExpired) {\n throw new AuthFailure(\"expired\", \"The access token expired.\");\n }\n throw new AuthFailure(\"invalid\", \"The access token is invalid.\");\n }\n const { sub, iat } = payload;\n const clientId = payload.client_id;\n const scopes = typeof payload.scope === \"string\" ? payload.scope.split(\" \") : [];\n if (typeof sub !== \"string\" || typeof clientId !== \"string\" || iat === undefined) {\n throw new AuthFailure(\"invalid\", \"The access token is missing claims.\");\n }\n if (!scopes.includes(MCP_SCOPE)) {\n throw new AuthFailure(\n \"invalid\",\n `The access token lacks the \"${MCP_SCOPE}\" scope.`,\n );\n }\n const grantId = grantIdOf(sub, clientId);\n if (await started().isRevoked({ kind: \"grant\", id: grantId }, iat * 1000)) {\n throw new AuthFailure(\"revoked\", \"Access for this agent was revoked.\");\n }\n return {\n kind: \"agent\",\n userId: asId(\"user\", sub),\n grantId,\n agent: {\n name: await clientName(clientId),\n verified: clientId.startsWith(\"https://\"),\n },\n };\n };\n\n const userOf = async (request: Request): Promise<UserPrincipal | undefined> => {\n const found = await instance.api.getSession({ headers: request.headers });\n if (!found) return undefined;\n return {\n kind: \"user\",\n userId: asId(\"user\", found.user.id),\n sessionId: found.session.id,\n };\n };\n\n const publicUrlOf = (request: Request): string =>\n new URL(new URL(request.url).pathname, settings.origin).href;\n\n const hostOf = async (\n request: Request,\n assertion: HostAssertion,\n ): Promise<HostPrincipal> => {\n const grant = await verifyHostAssertion(\n assertion,\n { method: request.method, url: publicUrlOf(request) },\n installed().grantKeys,\n Date.now(),\n );\n if (await started().isRevoked({ kind: \"grant\", id: grant.grantId })) {\n throw new AuthFailure(\"revoked\", \"This computer was disconnected.\");\n }\n return hostPrincipalOf(grant);\n };\n\n const turnOf = async (token: TurnToken): Promise<AgentPrincipal> => {\n const store = installed().turnKeys;\n let turnTokenKeys = await store.keys();\n const kid = decodeProtectedHeader(token).kid;\n if (kid !== undefined && !turnTokenKeys.publicKeys.has(kid)) {\n turnTokenKeys = await store.refresh();\n }\n const claims = await verifyTurnToken(turnTokenKeys, token, Date.now());\n if (await started().isRevoked({ kind: \"grant\", id: claims.gid })) {\n throw new AuthFailure(\"revoked\", \"This computer was disconnected.\");\n }\n return agentPrincipalOf(claims);\n };\n\n const outsideAgentOf = async (token: AgentToken): Promise<AgentPrincipal> => {\n const store = installed().turnKeys;\n let turnTokenKeys = await store.keys();\n const kid = decodeProtectedHeader(token).kid;\n if (kid !== undefined && !turnTokenKeys.publicKeys.has(kid)) {\n turnTokenKeys = await store.refresh();\n }\n const claims = await verifyAgentToken(turnTokenKeys, token, Date.now());\n if (await started().isRevoked({ kind: \"grant\", id: claims.gid })) {\n throw new AuthFailure(\"revoked\", \"This computer was disconnected.\");\n }\n return outsideAgentPrincipalOf(claims);\n };\n\n const keyOf = async (secret: string, request: Request): Promise<KeyPrincipal> => {\n const key: unknown = await apiKeys?.verify(secret, request);\n if (!key) {\n throw new AuthFailure(\"invalid\", \"The API key is invalid or revoked.\", {\n challenge: false,\n });\n }\n if (!isKeyPrincipal(key)) {\n throw new TypeError(\n 'keys.verify must answer a key principal: { kind: \"key\", keyId, scope, name, claims }.',\n );\n }\n return key;\n };\n\n const authenticateRequest = async (request: Request): Promise<Principal> => {\n await ready();\n const credential = credentialOf(\n request.headers.get(\"authorization\"),\n apiKeys?.prefix,\n );\n switch (credential?.kind) {\n case \"key\":\n return keyOf(credential.secret, request);\n case \"host\":\n return hostOf(request, credential.assertion);\n case \"turn\":\n return turnOf(credential.token);\n case \"agent\":\n return outsideAgentOf(credential.token);\n case \"access\":\n return agentOf(credential.token);\n case \"session\": {\n const user = await userOf(request);\n if (!user)\n throw new AuthFailure(\"invalid\", \"The session is invalid or has ended.\");\n return user;\n }\n case undefined:\n break;\n }\n const { authCookies } = await instance.$context;\n if (!hasCookie(request, authCookies.sessionToken.name)) return ANONYMOUS;\n return (await userOf(request)) ?? ANONYMOUS;\n };\n\n return {\n name: AUTH_PLUGIN,\n migrations: [\n ...AUTH_MIGRATIONS,\n HOSTS_MIGRATION,\n DEVICES_MIGRATION,\n TURN_KEYS_MIGRATION,\n AUDIT_MIGRATION,\n DEVICE_LINKING_MIGRATION,\n AUDIT_KEY_MIGRATION,\n ],\n enforcing: true,\n setup(host: PluginHost) {\n const { database } = host;\n if (!database) throw new Error(\"The auth plugin needs a database.\");\n const set = new RevocationSet({\n database,\n horizonMs: REVOCATION_HORIZON_MS,\n });\n revocations = set;\n const auditLog = createAuditLog(database);\n bridge.revoke = (notice) =>\n database.transaction((tx) => RevocationSet.revoke(tx, notice));\n grantKeys = createGrantKeys(database);\n devices = createDeviceRegistry(database);\n turnKeys = createTurnKeyStore({\n database,\n issuer: settings.baseURL,\n secret: async () => (await instance.$context).secret,\n });\n const hostDeps = {\n host,\n settings,\n };\n return {\n actions: createRegistry({\n ...accountActions({ instance, host, revoke: bridge.revoke }).actions,\n ...hostAccountActions(hostDeps).actions,\n ...deviceAccountActions({ host, registry: devices }).actions,\n }),\n routes: [...authRoutes({ instance, settings, host }), ...hostRoutes(hostDeps)],\n audit: (record) => auditLog.record(record),\n close: async () => {\n await Promise.all([set.stop(), auditLog.stop()]);\n },\n };\n },\n async authenticate(request: Request): Promise<Principal> {\n const startedAt = Date.now();\n const principal = await authenticateRequest(request);\n if (principal.kind !== \"anonymous\") authenticatedAt.set(principal, startedAt);\n return principal;\n },\n challenge(): Response {\n const metadata = `${settings.origin}/.well-known/oauth-protected-resource${new URL(settings.resource).pathname}`;\n return Response.json(\n { error: { code: \"unauthenticated\", message: \"Sign in through OAuth first.\" } },\n {\n status: 401,\n headers: {\n \"www-authenticate\": `Bearer resource_metadata=\"${metadata}\", scope=\"${MCP_SCOPE}\"`,\n },\n },\n );\n },\n async delegate(host: HostPrincipal, turn: TurnDelegation): Promise<Delegation> {\n await ready();\n return delegate(await installed().turnKeys.keys(), host, turn, Date.now());\n },\n async delegateAgent(\n host: HostPrincipal,\n agent: AgentDelegation,\n ): Promise<Delegation> {\n await ready();\n return delegateAgent(await installed().turnKeys.keys(), host, agent, Date.now());\n },\n async hostActive(grantId: GrantId): Promise<boolean> {\n const revoked = await started().isRevoked({ kind: \"grant\", id: grantId });\n return !revoked && (await installed().grantKeys.get(grantId)) !== undefined;\n },\n async device(userId: UserId, deviceId: DeviceId): Promise<DeviceKeys | undefined> {\n const registered = await installed().devices.get(userId, deviceId);\n if (!registered) return undefined;\n const { id, name, platform, signingKey, presenceKey, vouches } = registered;\n return {\n id,\n name,\n platform,\n signingKey,\n presenceKey,\n ...(vouches ? { vouches } : {}),\n };\n },\n async account(userId: UserId): Promise<AccountProfile | undefined> {\n const { adapter } = await instance.$context;\n const user = await adapter.findOne<{ name: string; email: string }>({\n model: \"user\",\n where: [{ field: \"id\", value: userId }],\n });\n return user ? { name: user.name, email: user.email } : undefined;\n },\n revoked(principal: AuthenticatedPrincipal): AbortSignal {\n const notice =\n principal.kind === \"user\"\n ? ({ kind: \"session\", id: principal.sessionId } as const)\n : ({ kind: \"grant\", id: principal.grantId } as const);\n return started().signal([notice], authenticatedAt.get(principal));\n },\n };\n}\n"]}
|
package/dist/tokens.d.ts
CHANGED
|
@@ -42,6 +42,9 @@ export type Credential = {
|
|
|
42
42
|
} | {
|
|
43
43
|
readonly kind: "session";
|
|
44
44
|
readonly token: string;
|
|
45
|
+
} | {
|
|
46
|
+
readonly kind: "key";
|
|
47
|
+
readonly secret: string;
|
|
45
48
|
};
|
|
46
49
|
export interface TurnTokenClaims {
|
|
47
50
|
readonly aud: typeof TURN_AUDIENCE;
|
|
@@ -66,8 +69,11 @@ export interface TurnTokenKeys {
|
|
|
66
69
|
readonly privateKey: CryptoKey;
|
|
67
70
|
readonly publicKeys: ReadonlyMap<string, CryptoKey>;
|
|
68
71
|
}
|
|
69
|
-
/**
|
|
70
|
-
|
|
72
|
+
/**
|
|
73
|
+
* `ParlorHost <jws>` is a host; a `Bearer` token that starts with `keyPrefix` is an API key,
|
|
74
|
+
* whatever its shape; a `Bearer` JWS whose header says `typ: parlor-turn+jwt` is a turn.
|
|
75
|
+
*/
|
|
76
|
+
export declare function credentialOf(authorization: string | null, keyPrefix?: string): Credential | undefined;
|
|
71
77
|
/** Mints a turn token for `host`'s grant; the provider's `delegate`. */
|
|
72
78
|
export declare function delegate(keys: TurnTokenKeys, host: HostPrincipal, turn: TurnDelegation, now: number): Promise<Delegation>;
|
|
73
79
|
/** Signature, `aud`, `iss` and `exp` only; the caller then asks `RevocationSet` about `gid`. */
|
package/dist/tokens.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,cAAc,EAEnB,KAAK,aAAa,EAClB,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,KAAK,eAAe,EAEpB,KAAK,UAAU,EAEf,KAAK,cAAc,EACpB,MAAM,gBAAgB,CAAC;AAIxB,kFAAkF;AAClF,eAAO,MAAM,aAAa,gBAAgB,CAAC;AAC3C,sFAAsF;AACtF,eAAO,MAAM,aAAa,eAAe,CAAC;AAE1C,eAAO,MAAM,kBAAkB,oBAAoB,CAAC;AACpD,eAAO,MAAM,cAAc,oBAAoB,CAAC;AAChD,4FAA4F;AAC5F,eAAO,MAAM,eAAe,qBAAqB,CAAC;AAIlD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,QAAwC,CAAC;AAE3E,MAAM,MAAM,aAAa,GAAG,OAAO,aAAa,GAAG,OAAO,aAAa,CAAC;AAExE,OAAO,CAAC,MAAM,QAAQ,EAAE,OAAO,MAAM,CAAC;AAEtC,6FAA6F;AAC7F,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,aAAa,IAAI,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;CAAE,CAAC;AAC/E,MAAM,MAAM,aAAa,GAAG,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,MAAM,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC;AAClD,OAAO,CAAC,MAAM,YAAY,EAAE,OAAO,MAAM,CAAC;AAC1C,6FAA6F;AAC7F,MAAM,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,aAAa,CAAC,GAAG;IAAE,QAAQ,CAAC,CAAC,YAAY,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AAEvF,kGAAkG;AAClG,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAA;CAAE,GAC5D;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;CAAE,GACpD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"tokens.d.ts","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,cAAc,EAEnB,KAAK,aAAa,EAClB,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,KAAK,eAAe,EAEpB,KAAK,UAAU,EAEf,KAAK,cAAc,EACpB,MAAM,gBAAgB,CAAC;AAIxB,kFAAkF;AAClF,eAAO,MAAM,aAAa,gBAAgB,CAAC;AAC3C,sFAAsF;AACtF,eAAO,MAAM,aAAa,eAAe,CAAC;AAE1C,eAAO,MAAM,kBAAkB,oBAAoB,CAAC;AACpD,eAAO,MAAM,cAAc,oBAAoB,CAAC;AAChD,4FAA4F;AAC5F,eAAO,MAAM,eAAe,qBAAqB,CAAC;AAIlD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,QAAwC,CAAC;AAE3E,MAAM,MAAM,aAAa,GAAG,OAAO,aAAa,GAAG,OAAO,aAAa,CAAC;AAExE,OAAO,CAAC,MAAM,QAAQ,EAAE,OAAO,MAAM,CAAC;AAEtC,6FAA6F;AAC7F,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,aAAa,IAAI,MAAM,GAAG;IAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;CAAE,CAAC;AAC/E,MAAM,MAAM,aAAa,GAAG,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,MAAM,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC;AAClD,OAAO,CAAC,MAAM,YAAY,EAAE,OAAO,MAAM,CAAC;AAC1C,6FAA6F;AAC7F,MAAM,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,aAAa,CAAC,GAAG;IAAE,QAAQ,CAAC,CAAC,YAAY,CAAC,EAAE,IAAI,CAAA;CAAE,CAAC;AAEvF,kGAAkG;AAClG,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAA;CAAE,GAC5D;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAA;CAAE,GACpD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GACtD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,GAAG,EAAE,OAAO,aAAa,CAAC;IACnC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,cAAc;IACd,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,0DAA0D;IAC1D,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,kCAAkC;IAClC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC;IAC/B,QAAQ,CAAC,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CACrD;AAgBD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,aAAa,EAAE,MAAM,GAAG,IAAI,EAC5B,SAAS,CAAC,EAAE,MAAM,GACjB,UAAU,GAAG,SAAS,CA0BxB;AAED,wEAAwE;AACxE,wBAAsB,QAAQ,CAC5B,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,cAAc,EACpB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,UAAU,CAAC,CAqBrB;AAgBD,gGAAgG;AAChG,wBAAsB,eAAe,CACnC,IAAI,EAAE,aAAa,EACnB,KAAK,EAAE,SAAS,EAChB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,eAAe,CAAC,CAgC1B;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,eAAe,GACtB,cAAc,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAA;CAAE,CAajD;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,GAAG,EAAE,OAAO,aAAa,CAAC;IACnC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,wGAAwG;AACxG,wBAAsB,aAAa,CACjC,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,aAAa,EACnB,KAAK,EAAE,eAAe,EACtB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,UAAU,CAAC,CAmBrB;AAaD,gGAAgG;AAChG,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,aAAa,EACnB,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,gBAAgB,CAAC,CAgC3B;AAED,sGAAsG;AACtG,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,gBAAgB,GAAG,cAAc,CAOhF"}
|
package/dist/tokens.js
CHANGED
|
@@ -28,8 +28,11 @@ function typOf(jws) {
|
|
|
28
28
|
throw new AuthFailure("invalid", "The token is malformed.");
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
-
/**
|
|
32
|
-
|
|
31
|
+
/**
|
|
32
|
+
* `ParlorHost <jws>` is a host; a `Bearer` token that starts with `keyPrefix` is an API key,
|
|
33
|
+
* whatever its shape; a `Bearer` JWS whose header says `typ: parlor-turn+jwt` is a turn.
|
|
34
|
+
*/
|
|
35
|
+
export function credentialOf(authorization, keyPrefix) {
|
|
33
36
|
if (authorization === null)
|
|
34
37
|
return undefined;
|
|
35
38
|
const match = /^([A-Za-z]+)\s+(\S+)$/.exec(authorization);
|
|
@@ -44,6 +47,9 @@ export function credentialOf(authorization) {
|
|
|
44
47
|
}
|
|
45
48
|
return { kind: "host", assertion: brand(value) };
|
|
46
49
|
}
|
|
50
|
+
if (keyPrefix !== undefined && value.startsWith(keyPrefix)) {
|
|
51
|
+
return { kind: "key", secret: value };
|
|
52
|
+
}
|
|
47
53
|
if (!JWS_SHAPE.test(value))
|
|
48
54
|
return { kind: "session", token: value };
|
|
49
55
|
switch (typOf(value)) {
|
package/dist/tokens.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type AgentPrincipal,\n asId,\n type HostPrincipal,\n type TurnBinding,\n} from \"@parlor/core\";\nimport {\n type AgentDelegation,\n AuthFailure,\n type Delegation,\n REVOCATION_HORIZON_MS,\n type TurnDelegation,\n} from \"@parlor/server\";\nimport { decodeProtectedHeader, errors, jwtVerify, SignJWT } from \"jose\";\nimport { z } from \"zod\";\n\n/** A host assertion's audience: signed by the computer's own key, per request. */\nexport const HOST_AUDIENCE = \"parlor:host\";\n/** A turn token's audience: signed by the server, carried by the host's MCP proxy. */\nexport const TURN_AUDIENCE = \"parlor:mcp\";\n\nexport const HOST_ASSERTION_TYP = \"parlor-host+jwt\";\nexport const TURN_TOKEN_TYP = \"parlor-turn+jwt\";\n/** An agent on the host's computer outside any turn: Claude Code or Codex in a terminal. */\nexport const AGENT_TOKEN_TYP = \"parlor-agent+jwt\";\n\nconst CLOCK_SKEW_MS = 60_000;\n\n/**\n * A turn token never outlives the revocation horizon, or a revoked grant's token could\n * verify after `RevocationSet` forgot the revocation.\n */\nexport const MAX_TURN_TOKEN_TTL_MS = REVOCATION_HORIZON_MS - CLOCK_SKEW_MS;\n\nexport type TokenAudience = typeof HOST_AUDIENCE | typeof TURN_AUDIENCE;\n\ndeclare const audience: unique symbol;\n\n/** A compact JWS whose audience is known from the scheme it arrived under; never swapped. */\nexport type Jws<A extends TokenAudience> = string & { readonly [audience]: A };\nexport type HostAssertion = Jws<typeof HOST_AUDIENCE>;\nexport type TurnToken = Jws<typeof TURN_AUDIENCE>;\ndeclare const outsideTurns: unique symbol;\n/** Same audience as a turn token, never mistaken for one: no turn, so no screen to drive. */\nexport type AgentToken = Jws<typeof TURN_AUDIENCE> & { readonly [outsideTurns]: true };\n\n/** What an `authorization` header carries, sorted by scheme and shape before any verification. */\nexport type Credential =\n | { readonly kind: \"host\"; readonly assertion: HostAssertion }\n | { readonly kind: \"turn\"; readonly token: TurnToken }\n | { readonly kind: \"agent\"; readonly token: AgentToken }\n | { readonly kind: \"access\"; readonly token: string }\n | { readonly kind: \"session\"; readonly token: string };\n\nexport interface TurnTokenClaims {\n readonly aud: typeof TURN_AUDIENCE;\n readonly iss: string;\n /** user id */\n readonly sub: string;\n /** grant id: revoking the grant kills the token */\n readonly gid: string;\n readonly hid: string;\n readonly thr: string;\n readonly trn: string;\n /** the client the prompt came from; `ui_*` binds to it */\n readonly cid: string;\n readonly agt: string;\n readonly iat: number;\n /** as long as the turn's lease */\n readonly exp: number;\n}\n\nexport interface TurnTokenKeys {\n readonly issuer: string;\n readonly kid: string;\n readonly privateKey: CryptoKey;\n readonly publicKeys: ReadonlyMap<string, CryptoKey>;\n}\n\nconst JWS_SHAPE = /^[\\w-]+\\.[\\w-]+\\.[\\w-]+$/;\n\nfunction brand<A extends TokenAudience>(compact: string): Jws<A> {\n return compact as Jws<A>;\n}\n\nfunction typOf(jws: string): string | undefined {\n try {\n return decodeProtectedHeader(jws).typ;\n } catch {\n throw new AuthFailure(\"invalid\", \"The token is malformed.\");\n }\n}\n\n/** `ParlorHost <jws>` is a host; a `Bearer` JWS whose header says `typ: parlor-turn+jwt` is a turn. */\nexport function credentialOf(authorization: string | null): Credential | undefined {\n if (authorization === null) return undefined;\n const match = /^([A-Za-z]+)\\s+(\\S+)$/.exec(authorization);\n const scheme = match?.[1]?.toLowerCase();\n const value = match?.[2];\n if (value === undefined || (scheme !== \"bearer\" && scheme !== \"parlorhost\")) {\n throw new AuthFailure(\"invalid\", \"Use a Bearer token.\");\n }\n if (scheme === \"parlorhost\") {\n if (!JWS_SHAPE.test(value)) {\n throw new AuthFailure(\"invalid\", \"The host assertion is malformed.\");\n }\n return { kind: \"host\", assertion: brand<typeof HOST_AUDIENCE>(value) };\n }\n if (!JWS_SHAPE.test(value)) return { kind: \"session\", token: value };\n switch (typOf(value)) {\n case TURN_TOKEN_TYP:\n return { kind: \"turn\", token: brand<typeof TURN_AUDIENCE>(value) };\n case AGENT_TOKEN_TYP:\n return { kind: \"agent\", token: brand<typeof TURN_AUDIENCE>(value) as AgentToken };\n default:\n return { kind: \"access\", token: value };\n }\n}\n\n/** Mints a turn token for `host`'s grant; the provider's `delegate`. */\nexport async function delegate(\n keys: TurnTokenKeys,\n host: HostPrincipal,\n turn: TurnDelegation,\n now: number,\n): Promise<Delegation> {\n if (!(turn.ttlMs > 0)) throw new RangeError(\"A turn token needs a positive lifetime.\");\n const iat = Math.floor(now / 1000);\n const exp = iat + Math.ceil(Math.min(turn.ttlMs, MAX_TURN_TOKEN_TTL_MS) / 1000);\n const claims: TurnTokenClaims = {\n aud: TURN_AUDIENCE,\n iss: keys.issuer,\n sub: host.userId,\n gid: host.grantId,\n hid: host.hostId,\n thr: turn.threadId,\n trn: turn.turnId,\n cid: turn.clientId,\n agt: turn.agent,\n iat,\n exp,\n };\n const token = await new SignJWT({ ...claims })\n .setProtectedHeader({ alg: \"ES256\", typ: TURN_TOKEN_TYP, kid: keys.kid })\n .sign(keys.privateKey);\n return { token, expiresAt: exp * 1000 };\n}\n\nconst claimsSchema = z.object({\n aud: z.literal(TURN_AUDIENCE),\n iss: z.string().min(1),\n sub: z.string().min(1),\n gid: z.string().min(1),\n hid: z.string().min(1),\n thr: z.string().min(1),\n trn: z.string().min(1),\n cid: z.string(),\n agt: z.string().min(1),\n iat: z.number().int(),\n exp: z.number().int(),\n});\n\n/** Signature, `aud`, `iss` and `exp` only; the caller then asks `RevocationSet` about `gid`. */\nexport async function verifyTurnToken(\n keys: TurnTokenKeys,\n token: TurnToken,\n now: number,\n): Promise<TurnTokenClaims> {\n let payload: unknown;\n try {\n ({ payload } = await jwtVerify(\n token,\n (header) => {\n const key =\n header.kid === undefined ? undefined : keys.publicKeys.get(header.kid);\n if (!key) throw new errors.JWKSNoMatchingKey();\n return key;\n },\n {\n algorithms: [\"ES256\"],\n typ: TURN_TOKEN_TYP,\n issuer: keys.issuer,\n audience: TURN_AUDIENCE,\n currentDate: new Date(now),\n },\n ));\n } catch (error) {\n if (error instanceof errors.JWTExpired) {\n throw new AuthFailure(\"expired\", \"The turn token expired.\");\n }\n throw new AuthFailure(\"invalid\", \"The turn token is invalid.\");\n }\n const claims = claimsSchema.safeParse(payload);\n if (!claims.success) throw new AuthFailure(\"invalid\", \"The turn token is malformed.\");\n const { iat, exp } = claims.data;\n if (exp - iat > MAX_TURN_TOKEN_TTL_MS / 1000 || iat * 1000 > now + CLOCK_SKEW_MS) {\n throw new AuthFailure(\"invalid\", \"The turn token has an impossible lifetime.\");\n }\n return claims.data;\n}\n\nexport function agentPrincipalOf(\n claims: TurnTokenClaims,\n): AgentPrincipal & { readonly turn: TurnBinding } {\n return {\n kind: \"agent\",\n userId: asId(\"user\", claims.sub),\n grantId: asId(\"grant\", claims.gid),\n agent: { name: claims.agt, verified: true },\n turn: {\n threadId: asId(\"thread\", claims.thr),\n turnId: asId(\"turn\", claims.trn),\n hostId: asId(\"host\", claims.hid),\n clientId: claims.cid,\n },\n };\n}\n\nexport interface AgentTokenClaims {\n readonly aud: typeof TURN_AUDIENCE;\n readonly iss: string;\n readonly sub: string;\n readonly gid: string;\n readonly hid: string;\n readonly agt: string;\n readonly iat: number;\n readonly exp: number;\n}\n\n/** Mints a token for an agent on `host`'s computer outside any turn; the provider's `delegateAgent`. */\nexport async function delegateAgent(\n keys: TurnTokenKeys,\n host: HostPrincipal,\n agent: AgentDelegation,\n now: number,\n): Promise<Delegation> {\n if (!(agent.ttlMs > 0))\n throw new RangeError(\"An agent token needs a positive lifetime.\");\n const iat = Math.floor(now / 1000);\n const exp = iat + Math.ceil(Math.min(agent.ttlMs, MAX_TURN_TOKEN_TTL_MS) / 1000);\n const claims: AgentTokenClaims = {\n aud: TURN_AUDIENCE,\n iss: keys.issuer,\n sub: host.userId,\n gid: host.grantId,\n hid: host.hostId,\n agt: agent.agent,\n iat,\n exp,\n };\n const token = await new SignJWT({ ...claims })\n .setProtectedHeader({ alg: \"ES256\", typ: AGENT_TOKEN_TYP, kid: keys.kid })\n .sign(keys.privateKey);\n return { token, expiresAt: exp * 1000 };\n}\n\nconst agentClaimsSchema = z.object({\n aud: z.literal(TURN_AUDIENCE),\n iss: z.string().min(1),\n sub: z.string().min(1),\n gid: z.string().min(1),\n hid: z.string().min(1),\n agt: z.string().min(1),\n iat: z.number().int(),\n exp: z.number().int(),\n});\n\n/** Signature, `aud`, `iss` and `exp` only; the caller then asks `RevocationSet` about `gid`. */\nexport async function verifyAgentToken(\n keys: TurnTokenKeys,\n token: AgentToken,\n now: number,\n): Promise<AgentTokenClaims> {\n let payload: unknown;\n try {\n ({ payload } = await jwtVerify(\n token,\n (header) => {\n const key =\n header.kid === undefined ? undefined : keys.publicKeys.get(header.kid);\n if (!key) throw new errors.JWKSNoMatchingKey();\n return key;\n },\n {\n algorithms: [\"ES256\"],\n typ: AGENT_TOKEN_TYP,\n issuer: keys.issuer,\n audience: TURN_AUDIENCE,\n currentDate: new Date(now),\n },\n ));\n } catch (error) {\n if (error instanceof errors.JWTExpired) {\n throw new AuthFailure(\"expired\", \"The agent token expired.\");\n }\n throw new AuthFailure(\"invalid\", \"The agent token is invalid.\");\n }\n const claims = agentClaimsSchema.safeParse(payload);\n if (!claims.success) throw new AuthFailure(\"invalid\", \"The agent token is malformed.\");\n const { iat, exp } = claims.data;\n if (exp - iat > MAX_TURN_TOKEN_TTL_MS / 1000 || iat * 1000 > now + CLOCK_SKEW_MS) {\n throw new AuthFailure(\"invalid\", \"The agent token has an impossible lifetime.\");\n }\n return claims.data;\n}\n\n/** An external agent of the user: no turn, so `ui_*` reaches no screen and confirms go to the app. */\nexport function outsideAgentPrincipalOf(claims: AgentTokenClaims): AgentPrincipal {\n return {\n kind: \"agent\",\n userId: asId(\"user\", claims.sub),\n grantId: asId(\"grant\", claims.gid),\n agent: { name: claims.agt, verified: true },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../src/tokens.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type AgentPrincipal,\n asId,\n type HostPrincipal,\n type TurnBinding,\n} from \"@parlor/core\";\nimport {\n type AgentDelegation,\n AuthFailure,\n type Delegation,\n REVOCATION_HORIZON_MS,\n type TurnDelegation,\n} from \"@parlor/server\";\nimport { decodeProtectedHeader, errors, jwtVerify, SignJWT } from \"jose\";\nimport { z } from \"zod\";\n\n/** A host assertion's audience: signed by the computer's own key, per request. */\nexport const HOST_AUDIENCE = \"parlor:host\";\n/** A turn token's audience: signed by the server, carried by the host's MCP proxy. */\nexport const TURN_AUDIENCE = \"parlor:mcp\";\n\nexport const HOST_ASSERTION_TYP = \"parlor-host+jwt\";\nexport const TURN_TOKEN_TYP = \"parlor-turn+jwt\";\n/** An agent on the host's computer outside any turn: Claude Code or Codex in a terminal. */\nexport const AGENT_TOKEN_TYP = \"parlor-agent+jwt\";\n\nconst CLOCK_SKEW_MS = 60_000;\n\n/**\n * A turn token never outlives the revocation horizon, or a revoked grant's token could\n * verify after `RevocationSet` forgot the revocation.\n */\nexport const MAX_TURN_TOKEN_TTL_MS = REVOCATION_HORIZON_MS - CLOCK_SKEW_MS;\n\nexport type TokenAudience = typeof HOST_AUDIENCE | typeof TURN_AUDIENCE;\n\ndeclare const audience: unique symbol;\n\n/** A compact JWS whose audience is known from the scheme it arrived under; never swapped. */\nexport type Jws<A extends TokenAudience> = string & { readonly [audience]: A };\nexport type HostAssertion = Jws<typeof HOST_AUDIENCE>;\nexport type TurnToken = Jws<typeof TURN_AUDIENCE>;\ndeclare const outsideTurns: unique symbol;\n/** Same audience as a turn token, never mistaken for one: no turn, so no screen to drive. */\nexport type AgentToken = Jws<typeof TURN_AUDIENCE> & { readonly [outsideTurns]: true };\n\n/** What an `authorization` header carries, sorted by scheme and shape before any verification. */\nexport type Credential =\n | { readonly kind: \"host\"; readonly assertion: HostAssertion }\n | { readonly kind: \"turn\"; readonly token: TurnToken }\n | { readonly kind: \"agent\"; readonly token: AgentToken }\n | { readonly kind: \"access\"; readonly token: string }\n | { readonly kind: \"session\"; readonly token: string }\n | { readonly kind: \"key\"; readonly secret: string };\n\nexport interface TurnTokenClaims {\n readonly aud: typeof TURN_AUDIENCE;\n readonly iss: string;\n /** user id */\n readonly sub: string;\n /** grant id: revoking the grant kills the token */\n readonly gid: string;\n readonly hid: string;\n readonly thr: string;\n readonly trn: string;\n /** the client the prompt came from; `ui_*` binds to it */\n readonly cid: string;\n readonly agt: string;\n readonly iat: number;\n /** as long as the turn's lease */\n readonly exp: number;\n}\n\nexport interface TurnTokenKeys {\n readonly issuer: string;\n readonly kid: string;\n readonly privateKey: CryptoKey;\n readonly publicKeys: ReadonlyMap<string, CryptoKey>;\n}\n\nconst JWS_SHAPE = /^[\\w-]+\\.[\\w-]+\\.[\\w-]+$/;\n\nfunction brand<A extends TokenAudience>(compact: string): Jws<A> {\n return compact as Jws<A>;\n}\n\nfunction typOf(jws: string): string | undefined {\n try {\n return decodeProtectedHeader(jws).typ;\n } catch {\n throw new AuthFailure(\"invalid\", \"The token is malformed.\");\n }\n}\n\n/**\n * `ParlorHost <jws>` is a host; a `Bearer` token that starts with `keyPrefix` is an API key,\n * whatever its shape; a `Bearer` JWS whose header says `typ: parlor-turn+jwt` is a turn.\n */\nexport function credentialOf(\n authorization: string | null,\n keyPrefix?: string,\n): Credential | undefined {\n if (authorization === null) return undefined;\n const match = /^([A-Za-z]+)\\s+(\\S+)$/.exec(authorization);\n const scheme = match?.[1]?.toLowerCase();\n const value = match?.[2];\n if (value === undefined || (scheme !== \"bearer\" && scheme !== \"parlorhost\")) {\n throw new AuthFailure(\"invalid\", \"Use a Bearer token.\");\n }\n if (scheme === \"parlorhost\") {\n if (!JWS_SHAPE.test(value)) {\n throw new AuthFailure(\"invalid\", \"The host assertion is malformed.\");\n }\n return { kind: \"host\", assertion: brand<typeof HOST_AUDIENCE>(value) };\n }\n if (keyPrefix !== undefined && value.startsWith(keyPrefix)) {\n return { kind: \"key\", secret: value };\n }\n if (!JWS_SHAPE.test(value)) return { kind: \"session\", token: value };\n switch (typOf(value)) {\n case TURN_TOKEN_TYP:\n return { kind: \"turn\", token: brand<typeof TURN_AUDIENCE>(value) };\n case AGENT_TOKEN_TYP:\n return { kind: \"agent\", token: brand<typeof TURN_AUDIENCE>(value) as AgentToken };\n default:\n return { kind: \"access\", token: value };\n }\n}\n\n/** Mints a turn token for `host`'s grant; the provider's `delegate`. */\nexport async function delegate(\n keys: TurnTokenKeys,\n host: HostPrincipal,\n turn: TurnDelegation,\n now: number,\n): Promise<Delegation> {\n if (!(turn.ttlMs > 0)) throw new RangeError(\"A turn token needs a positive lifetime.\");\n const iat = Math.floor(now / 1000);\n const exp = iat + Math.ceil(Math.min(turn.ttlMs, MAX_TURN_TOKEN_TTL_MS) / 1000);\n const claims: TurnTokenClaims = {\n aud: TURN_AUDIENCE,\n iss: keys.issuer,\n sub: host.userId,\n gid: host.grantId,\n hid: host.hostId,\n thr: turn.threadId,\n trn: turn.turnId,\n cid: turn.clientId,\n agt: turn.agent,\n iat,\n exp,\n };\n const token = await new SignJWT({ ...claims })\n .setProtectedHeader({ alg: \"ES256\", typ: TURN_TOKEN_TYP, kid: keys.kid })\n .sign(keys.privateKey);\n return { token, expiresAt: exp * 1000 };\n}\n\nconst claimsSchema = z.object({\n aud: z.literal(TURN_AUDIENCE),\n iss: z.string().min(1),\n sub: z.string().min(1),\n gid: z.string().min(1),\n hid: z.string().min(1),\n thr: z.string().min(1),\n trn: z.string().min(1),\n cid: z.string(),\n agt: z.string().min(1),\n iat: z.number().int(),\n exp: z.number().int(),\n});\n\n/** Signature, `aud`, `iss` and `exp` only; the caller then asks `RevocationSet` about `gid`. */\nexport async function verifyTurnToken(\n keys: TurnTokenKeys,\n token: TurnToken,\n now: number,\n): Promise<TurnTokenClaims> {\n let payload: unknown;\n try {\n ({ payload } = await jwtVerify(\n token,\n (header) => {\n const key =\n header.kid === undefined ? undefined : keys.publicKeys.get(header.kid);\n if (!key) throw new errors.JWKSNoMatchingKey();\n return key;\n },\n {\n algorithms: [\"ES256\"],\n typ: TURN_TOKEN_TYP,\n issuer: keys.issuer,\n audience: TURN_AUDIENCE,\n currentDate: new Date(now),\n },\n ));\n } catch (error) {\n if (error instanceof errors.JWTExpired) {\n throw new AuthFailure(\"expired\", \"The turn token expired.\");\n }\n throw new AuthFailure(\"invalid\", \"The turn token is invalid.\");\n }\n const claims = claimsSchema.safeParse(payload);\n if (!claims.success) throw new AuthFailure(\"invalid\", \"The turn token is malformed.\");\n const { iat, exp } = claims.data;\n if (exp - iat > MAX_TURN_TOKEN_TTL_MS / 1000 || iat * 1000 > now + CLOCK_SKEW_MS) {\n throw new AuthFailure(\"invalid\", \"The turn token has an impossible lifetime.\");\n }\n return claims.data;\n}\n\nexport function agentPrincipalOf(\n claims: TurnTokenClaims,\n): AgentPrincipal & { readonly turn: TurnBinding } {\n return {\n kind: \"agent\",\n userId: asId(\"user\", claims.sub),\n grantId: asId(\"grant\", claims.gid),\n agent: { name: claims.agt, verified: true },\n turn: {\n threadId: asId(\"thread\", claims.thr),\n turnId: asId(\"turn\", claims.trn),\n hostId: asId(\"host\", claims.hid),\n clientId: claims.cid,\n },\n };\n}\n\nexport interface AgentTokenClaims {\n readonly aud: typeof TURN_AUDIENCE;\n readonly iss: string;\n readonly sub: string;\n readonly gid: string;\n readonly hid: string;\n readonly agt: string;\n readonly iat: number;\n readonly exp: number;\n}\n\n/** Mints a token for an agent on `host`'s computer outside any turn; the provider's `delegateAgent`. */\nexport async function delegateAgent(\n keys: TurnTokenKeys,\n host: HostPrincipal,\n agent: AgentDelegation,\n now: number,\n): Promise<Delegation> {\n if (!(agent.ttlMs > 0))\n throw new RangeError(\"An agent token needs a positive lifetime.\");\n const iat = Math.floor(now / 1000);\n const exp = iat + Math.ceil(Math.min(agent.ttlMs, MAX_TURN_TOKEN_TTL_MS) / 1000);\n const claims: AgentTokenClaims = {\n aud: TURN_AUDIENCE,\n iss: keys.issuer,\n sub: host.userId,\n gid: host.grantId,\n hid: host.hostId,\n agt: agent.agent,\n iat,\n exp,\n };\n const token = await new SignJWT({ ...claims })\n .setProtectedHeader({ alg: \"ES256\", typ: AGENT_TOKEN_TYP, kid: keys.kid })\n .sign(keys.privateKey);\n return { token, expiresAt: exp * 1000 };\n}\n\nconst agentClaimsSchema = z.object({\n aud: z.literal(TURN_AUDIENCE),\n iss: z.string().min(1),\n sub: z.string().min(1),\n gid: z.string().min(1),\n hid: z.string().min(1),\n agt: z.string().min(1),\n iat: z.number().int(),\n exp: z.number().int(),\n});\n\n/** Signature, `aud`, `iss` and `exp` only; the caller then asks `RevocationSet` about `gid`. */\nexport async function verifyAgentToken(\n keys: TurnTokenKeys,\n token: AgentToken,\n now: number,\n): Promise<AgentTokenClaims> {\n let payload: unknown;\n try {\n ({ payload } = await jwtVerify(\n token,\n (header) => {\n const key =\n header.kid === undefined ? undefined : keys.publicKeys.get(header.kid);\n if (!key) throw new errors.JWKSNoMatchingKey();\n return key;\n },\n {\n algorithms: [\"ES256\"],\n typ: AGENT_TOKEN_TYP,\n issuer: keys.issuer,\n audience: TURN_AUDIENCE,\n currentDate: new Date(now),\n },\n ));\n } catch (error) {\n if (error instanceof errors.JWTExpired) {\n throw new AuthFailure(\"expired\", \"The agent token expired.\");\n }\n throw new AuthFailure(\"invalid\", \"The agent token is invalid.\");\n }\n const claims = agentClaimsSchema.safeParse(payload);\n if (!claims.success) throw new AuthFailure(\"invalid\", \"The agent token is malformed.\");\n const { iat, exp } = claims.data;\n if (exp - iat > MAX_TURN_TOKEN_TTL_MS / 1000 || iat * 1000 > now + CLOCK_SKEW_MS) {\n throw new AuthFailure(\"invalid\", \"The agent token has an impossible lifetime.\");\n }\n return claims.data;\n}\n\n/** An external agent of the user: no turn, so `ui_*` reaches no screen and confirms go to the app. */\nexport function outsideAgentPrincipalOf(claims: AgentTokenClaims): AgentPrincipal {\n return {\n kind: \"agent\",\n userId: asId(\"user\", claims.sub),\n grantId: asId(\"grant\", claims.gid),\n agent: { name: claims.agt, verified: true },\n };\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parlor/auth",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"homepage": "https://cychien.github.io/parlor",
|
|
5
5
|
"bugs": "https://github.com/cychien/parlor/issues",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"drizzle-orm": "^0.45.4",
|
|
37
37
|
"jose": "^6.2.12",
|
|
38
38
|
"zod": "^4.6.5",
|
|
39
|
-
"@parlor/
|
|
40
|
-
"@parlor/
|
|
41
|
-
"@parlor/
|
|
42
|
-
"@parlor/server": "0.
|
|
43
|
-
"@parlor/
|
|
39
|
+
"@parlor/core": "0.4.0",
|
|
40
|
+
"@parlor/chat": "0.4.0",
|
|
41
|
+
"@parlor/client": "0.4.0",
|
|
42
|
+
"@parlor/server": "0.4.0",
|
|
43
|
+
"@parlor/capabilities": "0.4.0"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@modelcontextprotocol/client": "^2.3.1",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"pg": "^8.23.1",
|
|
51
51
|
"typescript": "^7.0.2",
|
|
52
52
|
"vitest": "^5.0.3",
|
|
53
|
-
"@parlor/data": "0.
|
|
53
|
+
"@parlor/data": "0.4.0"
|
|
54
54
|
},
|
|
55
55
|
"scripts": {
|
|
56
56
|
"build": "tsc -p tsconfig.json",
|