@~lyre/auth 0.0.6 → 0.0.8
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/{chunk-RADVGFYQ.js → chunk-2FSPKJAC.js} +44 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.js +7 -1
- package/dist/sveltekit.d.ts +18 -2
- package/dist/sveltekit.js +38 -5
- package/package.json +1 -1
|
@@ -242,6 +242,46 @@ function readCookie(cookieHeader, name) {
|
|
|
242
242
|
}
|
|
243
243
|
return null;
|
|
244
244
|
}
|
|
245
|
+
function serviceKeyFromRequest(request) {
|
|
246
|
+
const explicit = request.headers.get("x-api-key");
|
|
247
|
+
if (explicit && explicit.trim()) return explicit.trim();
|
|
248
|
+
const auth = request.headers.get("authorization");
|
|
249
|
+
if (auth && auth.startsWith("Bearer ")) {
|
|
250
|
+
const token = auth.slice(7).trim();
|
|
251
|
+
if (token.startsWith("sk_")) return token;
|
|
252
|
+
}
|
|
253
|
+
return null;
|
|
254
|
+
}
|
|
255
|
+
async function introspectServiceKey(input) {
|
|
256
|
+
const base = normalizeOptionalString(input.config.baseUrl);
|
|
257
|
+
if (!input.key || !base) return null;
|
|
258
|
+
const fetchImpl = input.fetchImpl ?? fetch;
|
|
259
|
+
try {
|
|
260
|
+
const res = await fetchImpl(new URL("/api/auth/service-keys/introspect", base), {
|
|
261
|
+
method: "POST",
|
|
262
|
+
headers: { "x-api-key": input.key, accept: "application/json" }
|
|
263
|
+
});
|
|
264
|
+
if (!res.ok) return null;
|
|
265
|
+
const data = await res.json();
|
|
266
|
+
if (!data.valid || !data.keyId) return null;
|
|
267
|
+
const accessibleApps = (data.accessibleApps ?? []).filter(
|
|
268
|
+
(a) => Boolean(a) && typeof a.id === "string" && typeof a.slug === "string"
|
|
269
|
+
).map((a) => ({ id: a.id, slug: a.slug, name: a.name }));
|
|
270
|
+
return {
|
|
271
|
+
keyId: data.keyId,
|
|
272
|
+
tenantId: data.tenantId ?? null,
|
|
273
|
+
scopes: Array.isArray(data.scopes) ? data.scopes : [],
|
|
274
|
+
accessibleApps,
|
|
275
|
+
expiresAt: data.expiresAt ?? null
|
|
276
|
+
};
|
|
277
|
+
} catch {
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
function scopeSatisfied(granted, required) {
|
|
282
|
+
if (!granted || granted.length === 0) return false;
|
|
283
|
+
return granted.includes(required);
|
|
284
|
+
}
|
|
245
285
|
|
|
246
286
|
export {
|
|
247
287
|
createAccountsClientConfig,
|
|
@@ -253,5 +293,8 @@ export {
|
|
|
253
293
|
identityPassthroughSync,
|
|
254
294
|
resolveActiveTenant,
|
|
255
295
|
readPlatformSessionCookie,
|
|
256
|
-
clearPlatformSessionCookie
|
|
296
|
+
clearPlatformSessionCookie,
|
|
297
|
+
serviceKeyFromRequest,
|
|
298
|
+
introspectServiceKey,
|
|
299
|
+
scopeSatisfied
|
|
257
300
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -142,5 +142,26 @@ type CookieOptions = {
|
|
|
142
142
|
secure?: boolean;
|
|
143
143
|
};
|
|
144
144
|
declare function clearPlatformSessionCookie(opts?: CookieOptions): string;
|
|
145
|
+
type ServiceKeyApp = {
|
|
146
|
+
id: string;
|
|
147
|
+
slug: string;
|
|
148
|
+
name?: string;
|
|
149
|
+
};
|
|
150
|
+
type ServiceKeyContext = {
|
|
151
|
+
keyId: string;
|
|
152
|
+
tenantId: string | null;
|
|
153
|
+
/** Scopes granted to this key (opaque strings owned by the consuming app). */
|
|
154
|
+
scopes: string[];
|
|
155
|
+
/** Apps this key may act on (auth resolves these from the key's app grant). */
|
|
156
|
+
accessibleApps: ServiceKeyApp[];
|
|
157
|
+
expiresAt: string | null;
|
|
158
|
+
};
|
|
159
|
+
declare function serviceKeyFromRequest(request: Request): string | null;
|
|
160
|
+
declare function introspectServiceKey(input: {
|
|
161
|
+
config: Pick<AccountsClientConfig, 'baseUrl'>;
|
|
162
|
+
key: string;
|
|
163
|
+
fetchImpl?: typeof fetch;
|
|
164
|
+
}): Promise<ServiceKeyContext | null>;
|
|
165
|
+
declare function scopeSatisfied(granted: string[] | undefined, required: string): boolean;
|
|
145
166
|
|
|
146
|
-
export { type AccountsClientConfig, type AccountsIdentity, type AccountsTokenResponse, type AuthenticatedPrincipal, type AuthorizationState, type CookieOptions, type LocalUser, type PermissionSet, type PlatformSession, type SyncAccountsUser, type SyncAccountsUserResult, type TenantAccessContext, type TenantContext, type TenantMembership, beginAccountsLoginRedirect, clearPlatformSessionCookie, createAccountsClientConfig, createPlatformAuth, exchangeAuthorizationCode, handleAccountsCallback, identityPassthroughSync, readPlatformSessionCookie, resolveActiveTenant, syncAccountsUser };
|
|
167
|
+
export { type AccountsClientConfig, type AccountsIdentity, type AccountsTokenResponse, type AuthenticatedPrincipal, type AuthorizationState, type CookieOptions, type LocalUser, type PermissionSet, type PlatformSession, type ServiceKeyApp, type ServiceKeyContext, type SyncAccountsUser, type SyncAccountsUserResult, type TenantAccessContext, type TenantContext, type TenantMembership, beginAccountsLoginRedirect, clearPlatformSessionCookie, createAccountsClientConfig, createPlatformAuth, exchangeAuthorizationCode, handleAccountsCallback, identityPassthroughSync, introspectServiceKey, readPlatformSessionCookie, resolveActiveTenant, scopeSatisfied, serviceKeyFromRequest, syncAccountsUser };
|
package/dist/index.js
CHANGED
|
@@ -6,10 +6,13 @@ import {
|
|
|
6
6
|
exchangeAuthorizationCode,
|
|
7
7
|
handleAccountsCallback,
|
|
8
8
|
identityPassthroughSync,
|
|
9
|
+
introspectServiceKey,
|
|
9
10
|
readPlatformSessionCookie,
|
|
10
11
|
resolveActiveTenant,
|
|
12
|
+
scopeSatisfied,
|
|
13
|
+
serviceKeyFromRequest,
|
|
11
14
|
syncAccountsUser
|
|
12
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-2FSPKJAC.js";
|
|
13
16
|
export {
|
|
14
17
|
beginAccountsLoginRedirect,
|
|
15
18
|
clearPlatformSessionCookie,
|
|
@@ -18,7 +21,10 @@ export {
|
|
|
18
21
|
exchangeAuthorizationCode,
|
|
19
22
|
handleAccountsCallback,
|
|
20
23
|
identityPassthroughSync,
|
|
24
|
+
introspectServiceKey,
|
|
21
25
|
readPlatformSessionCookie,
|
|
22
26
|
resolveActiveTenant,
|
|
27
|
+
scopeSatisfied,
|
|
28
|
+
serviceKeyFromRequest,
|
|
23
29
|
syncAccountsUser
|
|
24
30
|
};
|
package/dist/sveltekit.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RequestEvent, Handle } from '@sveltejs/kit';
|
|
2
|
-
import { PlatformSession, AccountsClientConfig, SyncAccountsUser, CookieOptions } from './index.js';
|
|
2
|
+
import { PlatformSession, AccountsClientConfig, ServiceKeyContext, SyncAccountsUser, CookieOptions } from './index.js';
|
|
3
3
|
export { clearPlatformSessionCookie } from './index.js';
|
|
4
4
|
|
|
5
5
|
type SvelteKitAuthOptions = {
|
|
@@ -35,5 +35,21 @@ type PlatformLocals = {
|
|
|
35
35
|
principal: PlatformSession['principal'];
|
|
36
36
|
};
|
|
37
37
|
declare function createAuthHandle(opts: SvelteKitAuthOptions): Handle;
|
|
38
|
+
type ServiceKeyHandleOptions = {
|
|
39
|
+
config: AccountsClientConfig;
|
|
40
|
+
fetchImpl?: typeof fetch;
|
|
41
|
+
/** Which requests to attempt key auth on. Default: paths starting with `/api`. */
|
|
42
|
+
match?: (event: RequestEvent) => boolean;
|
|
43
|
+
/** Introspection cache TTL in ms. Default 60_000; set 0 to disable caching. */
|
|
44
|
+
cacheTtlMs?: number;
|
|
45
|
+
/** Map the resolved key grant onto app locals. Called only for a valid key. */
|
|
46
|
+
onResolved?: (event: RequestEvent, ctx: ServiceKeyContext) => void;
|
|
47
|
+
/** Observe a present-but-invalid key (e.g. logging) before the 401 is returned. */
|
|
48
|
+
onInvalid?: (event: RequestEvent) => void;
|
|
49
|
+
};
|
|
50
|
+
type ServiceKeyLocals = {
|
|
51
|
+
serviceKey?: ServiceKeyContext | null;
|
|
52
|
+
};
|
|
53
|
+
declare function createServiceKeyHandle(opts: ServiceKeyHandleOptions): Handle;
|
|
38
54
|
|
|
39
|
-
export { type PlatformLocals, type SvelteKitAuthOptions, createAuthHandle };
|
|
55
|
+
export { type PlatformLocals, type ServiceKeyHandleOptions, type ServiceKeyLocals, type SvelteKitAuthOptions, createAuthHandle, createServiceKeyHandle };
|
package/dist/sveltekit.js
CHANGED
|
@@ -3,11 +3,13 @@ import {
|
|
|
3
3
|
clearPlatformSessionCookie,
|
|
4
4
|
handleAccountsCallback,
|
|
5
5
|
identityPassthroughSync,
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
introspectServiceKey,
|
|
7
|
+
readPlatformSessionCookie,
|
|
8
|
+
serviceKeyFromRequest
|
|
9
|
+
} from "./chunk-2FSPKJAC.js";
|
|
8
10
|
|
|
9
11
|
// src/sveltekit.ts
|
|
10
|
-
import {
|
|
12
|
+
import { createHash } from "crypto";
|
|
11
13
|
var STATE_COOKIE = "accounts_auth_state";
|
|
12
14
|
function redirectWithCookies(location, cookies) {
|
|
13
15
|
const headers = new Headers({ location });
|
|
@@ -65,12 +67,43 @@ function createAuthHandle(opts) {
|
|
|
65
67
|
headers: { "content-type": "application/json" }
|
|
66
68
|
});
|
|
67
69
|
}
|
|
68
|
-
|
|
70
|
+
return redirectWithCookies(`${loginPath}?next=${encodeURIComponent(path + event.url.search)}`, []);
|
|
69
71
|
}
|
|
70
72
|
return resolve(event);
|
|
71
73
|
};
|
|
72
74
|
}
|
|
75
|
+
function createServiceKeyHandle(opts) {
|
|
76
|
+
const match = opts.match ?? ((event) => event.url.pathname.startsWith("/api"));
|
|
77
|
+
const ttl = opts.cacheTtlMs ?? 6e4;
|
|
78
|
+
const cache = /* @__PURE__ */ new Map();
|
|
79
|
+
return async ({ event, resolve }) => {
|
|
80
|
+
if (!match(event)) return resolve(event);
|
|
81
|
+
const key = serviceKeyFromRequest(event.request);
|
|
82
|
+
if (!key) return resolve(event);
|
|
83
|
+
const hash = createHash("sha256").update(key).digest("hex");
|
|
84
|
+
const now = Date.now();
|
|
85
|
+
let ctx;
|
|
86
|
+
const cached = ttl > 0 ? cache.get(hash) : void 0;
|
|
87
|
+
if (cached && cached.expires > now) {
|
|
88
|
+
ctx = cached.value;
|
|
89
|
+
} else {
|
|
90
|
+
ctx = await introspectServiceKey({ config: opts.config, key, fetchImpl: opts.fetchImpl });
|
|
91
|
+
if (ttl > 0) cache.set(hash, { value: ctx, expires: now + ttl });
|
|
92
|
+
}
|
|
93
|
+
if (ctx) {
|
|
94
|
+
event.locals.serviceKey = ctx;
|
|
95
|
+
opts.onResolved?.(event, ctx);
|
|
96
|
+
return resolve(event);
|
|
97
|
+
}
|
|
98
|
+
opts.onInvalid?.(event);
|
|
99
|
+
return new Response(JSON.stringify({ message: "Invalid or expired API key." }), {
|
|
100
|
+
status: 401,
|
|
101
|
+
headers: { "content-type": "application/json" }
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
}
|
|
73
105
|
export {
|
|
74
106
|
clearPlatformSessionCookie,
|
|
75
|
-
createAuthHandle
|
|
107
|
+
createAuthHandle,
|
|
108
|
+
createServiceKeyHandle
|
|
76
109
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@~lyre/auth",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.8",
|
|
4
4
|
"description": "Shared Axis Accounts auth SDK — framework-agnostic session/identity core (HMAC-signed cookies, accounts login/callback/logout) plus an optional turnkey SvelteKit adapter.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"sideEffects": false,
|