@silicajs/auth 0.1.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/README.md +12 -0
- package/dist/index.d.ts +61 -0
- package/dist/index.js +95 -0
- package/dist/index.js.map +1 -0
- package/package.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# @silicajs/auth
|
|
2
|
+
|
|
3
|
+
Better Auth wrapper for Silica.
|
|
4
|
+
|
|
5
|
+
Provides:
|
|
6
|
+
|
|
7
|
+
- Google provider configuration from environment variables
|
|
8
|
+
- stateless cookie-cache session configuration using JWE
|
|
9
|
+
- OAuth callback allowlist enforcement
|
|
10
|
+
- request/session helpers for generated `proxy.ts`
|
|
11
|
+
|
|
12
|
+
Silica auth is optional; sites without an `auth` config remain public.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import * as better_auth from 'better-auth';
|
|
2
|
+
import { Session, User } from 'better-auth';
|
|
3
|
+
import * as better_call from 'better-call';
|
|
4
|
+
|
|
5
|
+
type AllowlistConfig = {
|
|
6
|
+
allowedEmails?: string[];
|
|
7
|
+
allowedDomains?: string[];
|
|
8
|
+
};
|
|
9
|
+
declare function isEmailAllowed(email: string | undefined | null, config: AllowlistConfig): boolean;
|
|
10
|
+
declare function hasAllowlist(config: AllowlistConfig): boolean;
|
|
11
|
+
|
|
12
|
+
type SilicaSession = {
|
|
13
|
+
session: Session & Record<string, unknown>;
|
|
14
|
+
user: User & Record<string, unknown>;
|
|
15
|
+
updatedAt: number;
|
|
16
|
+
version?: string;
|
|
17
|
+
};
|
|
18
|
+
type SilicaSessionOptions = AllowlistConfig & {
|
|
19
|
+
secret?: string;
|
|
20
|
+
strategy?: "compact" | "jwt" | "jwe";
|
|
21
|
+
};
|
|
22
|
+
declare function getSilicaSession(request: Request | Headers, options?: SilicaSessionOptions): Promise<SilicaSession | null>;
|
|
23
|
+
declare function hasSilicaSessionCookie(request: Request | Headers): boolean;
|
|
24
|
+
declare function isSilicaRequestAllowed(request: Request | Headers, options?: SilicaSessionOptions): Promise<boolean>;
|
|
25
|
+
|
|
26
|
+
type SilicaAuthOptions = AllowlistConfig & {
|
|
27
|
+
baseURL?: string;
|
|
28
|
+
secret?: string;
|
|
29
|
+
googleClientId?: string;
|
|
30
|
+
googleClientSecret?: string;
|
|
31
|
+
};
|
|
32
|
+
declare function silicaAuth(options?: SilicaAuthOptions): better_auth.Auth<{
|
|
33
|
+
baseURL: string | undefined;
|
|
34
|
+
secret: string | undefined;
|
|
35
|
+
socialProviders: {
|
|
36
|
+
google: {
|
|
37
|
+
clientId: string;
|
|
38
|
+
clientSecret: string;
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
session: {
|
|
42
|
+
cookieCache: {
|
|
43
|
+
enabled: true;
|
|
44
|
+
maxAge: number;
|
|
45
|
+
strategy: "jwe";
|
|
46
|
+
refreshCache: true;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
account: {
|
|
50
|
+
storeAccountCookie: true;
|
|
51
|
+
storeStateStrategy: "cookie";
|
|
52
|
+
accountLinking: {
|
|
53
|
+
enabled: false;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
hooks: {
|
|
57
|
+
after: (inputContext: better_call.MiddlewareInputContext<better_call.MiddlewareOptions>) => Promise<void>;
|
|
58
|
+
};
|
|
59
|
+
}>;
|
|
60
|
+
|
|
61
|
+
export { type AllowlistConfig, type SilicaAuthOptions, type SilicaSession, type SilicaSessionOptions, getSilicaSession, hasAllowlist, hasSilicaSessionCookie, isEmailAllowed, isSilicaRequestAllowed, silicaAuth };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { betterAuth } from "better-auth";
|
|
3
|
+
import { APIError, createAuthMiddleware } from "better-auth/api";
|
|
4
|
+
|
|
5
|
+
// src/allowlist.ts
|
|
6
|
+
function isEmailAllowed(email, config) {
|
|
7
|
+
if (!email) return false;
|
|
8
|
+
const normalized = email.trim().toLowerCase();
|
|
9
|
+
const allowedEmails = new Set((config.allowedEmails ?? []).map((item) => item.trim().toLowerCase()));
|
|
10
|
+
if (allowedEmails.has(normalized)) return true;
|
|
11
|
+
return (config.allowedDomains ?? []).some((domain) => {
|
|
12
|
+
const normalizedDomain = domain.trim().replace(/^@/, "").toLowerCase();
|
|
13
|
+
return normalized.endsWith(`@${normalizedDomain}`);
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
function hasAllowlist(config) {
|
|
17
|
+
return Boolean(config.allowedEmails?.length || config.allowedDomains?.length);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// src/session.ts
|
|
21
|
+
import { getCookieCache, getSessionCookie } from "better-auth/cookies";
|
|
22
|
+
async function getSilicaSession(request, options = {}) {
|
|
23
|
+
try {
|
|
24
|
+
return await getCookieCache(request, {
|
|
25
|
+
secret: options.secret ?? process.env.BETTER_AUTH_SECRET,
|
|
26
|
+
strategy: options.strategy ?? "jwe"
|
|
27
|
+
});
|
|
28
|
+
} catch {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function hasSilicaSessionCookie(request) {
|
|
33
|
+
return Boolean(getSessionCookie(request));
|
|
34
|
+
}
|
|
35
|
+
async function isSilicaRequestAllowed(request, options = {}) {
|
|
36
|
+
const session = await getSilicaSession(request, options);
|
|
37
|
+
if (!session) return false;
|
|
38
|
+
if (!hasAllowlist(options)) return true;
|
|
39
|
+
return isEmailAllowed(session.user.email, options);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// src/index.ts
|
|
43
|
+
function silicaAuth(options = {}) {
|
|
44
|
+
const allowlist = {
|
|
45
|
+
allowedDomains: options.allowedDomains ?? [],
|
|
46
|
+
allowedEmails: options.allowedEmails ?? []
|
|
47
|
+
};
|
|
48
|
+
return betterAuth({
|
|
49
|
+
baseURL: options.baseURL ?? process.env.BETTER_AUTH_URL,
|
|
50
|
+
secret: options.secret ?? process.env.BETTER_AUTH_SECRET,
|
|
51
|
+
socialProviders: {
|
|
52
|
+
google: {
|
|
53
|
+
clientId: options.googleClientId ?? process.env.GOOGLE_CLIENT_ID ?? "",
|
|
54
|
+
clientSecret: options.googleClientSecret ?? process.env.GOOGLE_CLIENT_SECRET ?? ""
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
session: {
|
|
58
|
+
cookieCache: {
|
|
59
|
+
enabled: true,
|
|
60
|
+
maxAge: 7 * 24 * 60 * 60,
|
|
61
|
+
strategy: "jwe",
|
|
62
|
+
refreshCache: true
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
account: {
|
|
66
|
+
storeAccountCookie: true,
|
|
67
|
+
storeStateStrategy: "cookie",
|
|
68
|
+
accountLinking: {
|
|
69
|
+
enabled: false
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
hooks: {
|
|
73
|
+
after: createAuthMiddleware(async (ctx) => {
|
|
74
|
+
if (!ctx.path.includes("/callback/")) return;
|
|
75
|
+
if (!hasAllowlist(allowlist)) return;
|
|
76
|
+
const email = ctx.context.newSession?.user.email ?? "";
|
|
77
|
+
if (!isEmailAllowed(email, allowlist)) {
|
|
78
|
+
throw new APIError("FORBIDDEN", {
|
|
79
|
+
message: "Email is not allowed to access this Silica site.",
|
|
80
|
+
redirectTo: "/not-allowed"
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
export {
|
|
88
|
+
getSilicaSession,
|
|
89
|
+
hasAllowlist,
|
|
90
|
+
hasSilicaSessionCookie,
|
|
91
|
+
isEmailAllowed,
|
|
92
|
+
isSilicaRequestAllowed,
|
|
93
|
+
silicaAuth
|
|
94
|
+
};
|
|
95
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/allowlist.ts","../src/session.ts"],"sourcesContent":["import { betterAuth } from \"better-auth\";\nimport { APIError, createAuthMiddleware } from \"better-auth/api\";\nimport type { AllowlistConfig } from \"./allowlist.js\";\nimport { hasAllowlist, isEmailAllowed } from \"./allowlist.js\";\n\nexport type SilicaAuthOptions = AllowlistConfig & {\n baseURL?: string;\n secret?: string;\n googleClientId?: string;\n googleClientSecret?: string;\n};\n\nexport function silicaAuth(options: SilicaAuthOptions = {}) {\n const allowlist = {\n allowedDomains: options.allowedDomains ?? [],\n allowedEmails: options.allowedEmails ?? [],\n };\n\n return betterAuth({\n baseURL: options.baseURL ?? process.env.BETTER_AUTH_URL,\n secret: options.secret ?? process.env.BETTER_AUTH_SECRET,\n socialProviders: {\n google: {\n clientId: options.googleClientId ?? process.env.GOOGLE_CLIENT_ID ?? \"\",\n clientSecret: options.googleClientSecret ?? process.env.GOOGLE_CLIENT_SECRET ?? \"\",\n },\n },\n session: {\n cookieCache: {\n enabled: true,\n maxAge: 7 * 24 * 60 * 60,\n strategy: \"jwe\",\n refreshCache: true,\n },\n },\n account: {\n storeAccountCookie: true,\n storeStateStrategy: \"cookie\",\n accountLinking: {\n enabled: false,\n },\n },\n hooks: {\n after: createAuthMiddleware(async (ctx) => {\n if (!ctx.path.includes(\"/callback/\")) return;\n if (!hasAllowlist(allowlist)) return;\n\n const email = ctx.context.newSession?.user.email ?? \"\";\n if (!isEmailAllowed(email, allowlist)) {\n throw new APIError(\"FORBIDDEN\", {\n message: \"Email is not allowed to access this Silica site.\",\n redirectTo: \"/not-allowed\",\n });\n }\n }),\n },\n });\n}\n\nexport { hasAllowlist, isEmailAllowed };\nexport { getSilicaSession, hasSilicaSessionCookie, isSilicaRequestAllowed } from \"./session.js\";\nexport type { AllowlistConfig };\nexport type { SilicaSession, SilicaSessionOptions } from \"./session.js\";\n","export type AllowlistConfig = {\n allowedEmails?: string[];\n allowedDomains?: string[];\n};\n\nexport function isEmailAllowed(email: string | undefined | null, config: AllowlistConfig): boolean {\n if (!email) return false;\n const normalized = email.trim().toLowerCase();\n const allowedEmails = new Set((config.allowedEmails ?? []).map((item) => item.trim().toLowerCase()));\n if (allowedEmails.has(normalized)) return true;\n\n return (config.allowedDomains ?? []).some((domain) => {\n const normalizedDomain = domain.trim().replace(/^@/, \"\").toLowerCase();\n return normalized.endsWith(`@${normalizedDomain}`);\n });\n}\n\nexport function hasAllowlist(config: AllowlistConfig): boolean {\n return Boolean(config.allowedEmails?.length || config.allowedDomains?.length);\n}\n","import { getCookieCache, getSessionCookie } from \"better-auth/cookies\";\nimport type { Session, User } from \"better-auth\";\nimport type { AllowlistConfig } from \"./allowlist.js\";\nimport { hasAllowlist, isEmailAllowed } from \"./allowlist.js\";\n\nexport type SilicaSession = {\n session: Session & Record<string, unknown>;\n user: User & Record<string, unknown>;\n updatedAt: number;\n version?: string;\n};\n\nexport type SilicaSessionOptions = AllowlistConfig & {\n secret?: string;\n strategy?: \"compact\" | \"jwt\" | \"jwe\";\n};\n\nexport async function getSilicaSession(request: Request | Headers, options: SilicaSessionOptions = {}): Promise<SilicaSession | null> {\n try {\n return await getCookieCache<SilicaSession>(request, {\n secret: options.secret ?? process.env.BETTER_AUTH_SECRET,\n strategy: options.strategy ?? \"jwe\",\n });\n } catch {\n return null;\n }\n}\n\nexport function hasSilicaSessionCookie(request: Request | Headers): boolean {\n return Boolean(getSessionCookie(request));\n}\n\nexport async function isSilicaRequestAllowed(request: Request | Headers, options: SilicaSessionOptions = {}): Promise<boolean> {\n const session = await getSilicaSession(request, options);\n if (!session) return false;\n if (!hasAllowlist(options)) return true;\n return isEmailAllowed(session.user.email, options);\n}\n"],"mappings":";AAAA,SAAS,kBAAkB;AAC3B,SAAS,UAAU,4BAA4B;;;ACIxC,SAAS,eAAe,OAAkC,QAAkC;AACjG,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,aAAa,MAAM,KAAK,EAAE,YAAY;AAC5C,QAAM,gBAAgB,IAAI,KAAK,OAAO,iBAAiB,CAAC,GAAG,IAAI,CAAC,SAAS,KAAK,KAAK,EAAE,YAAY,CAAC,CAAC;AACnG,MAAI,cAAc,IAAI,UAAU,EAAG,QAAO;AAE1C,UAAQ,OAAO,kBAAkB,CAAC,GAAG,KAAK,CAAC,WAAW;AACpD,UAAM,mBAAmB,OAAO,KAAK,EAAE,QAAQ,MAAM,EAAE,EAAE,YAAY;AACrE,WAAO,WAAW,SAAS,IAAI,gBAAgB,EAAE;AAAA,EACnD,CAAC;AACH;AAEO,SAAS,aAAa,QAAkC;AAC7D,SAAO,QAAQ,OAAO,eAAe,UAAU,OAAO,gBAAgB,MAAM;AAC9E;;;ACnBA,SAAS,gBAAgB,wBAAwB;AAiBjD,eAAsB,iBAAiB,SAA4B,UAAgC,CAAC,GAAkC;AACpI,MAAI;AACF,WAAO,MAAM,eAA8B,SAAS;AAAA,MAClD,QAAQ,QAAQ,UAAU,QAAQ,IAAI;AAAA,MACtC,UAAU,QAAQ,YAAY;AAAA,IAChC,CAAC;AAAA,EACH,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,uBAAuB,SAAqC;AAC1E,SAAO,QAAQ,iBAAiB,OAAO,CAAC;AAC1C;AAEA,eAAsB,uBAAuB,SAA4B,UAAgC,CAAC,GAAqB;AAC7H,QAAM,UAAU,MAAM,iBAAiB,SAAS,OAAO;AACvD,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,CAAC,aAAa,OAAO,EAAG,QAAO;AACnC,SAAO,eAAe,QAAQ,KAAK,OAAO,OAAO;AACnD;;;AFzBO,SAAS,WAAW,UAA6B,CAAC,GAAG;AAC1D,QAAM,YAAY;AAAA,IAChB,gBAAgB,QAAQ,kBAAkB,CAAC;AAAA,IAC3C,eAAe,QAAQ,iBAAiB,CAAC;AAAA,EAC3C;AAEA,SAAO,WAAW;AAAA,IAChB,SAAS,QAAQ,WAAW,QAAQ,IAAI;AAAA,IACxC,QAAQ,QAAQ,UAAU,QAAQ,IAAI;AAAA,IACtC,iBAAiB;AAAA,MACf,QAAQ;AAAA,QACN,UAAU,QAAQ,kBAAkB,QAAQ,IAAI,oBAAoB;AAAA,QACpE,cAAc,QAAQ,sBAAsB,QAAQ,IAAI,wBAAwB;AAAA,MAClF;AAAA,IACF;AAAA,IACA,SAAS;AAAA,MACP,aAAa;AAAA,QACX,SAAS;AAAA,QACT,QAAQ,IAAI,KAAK,KAAK;AAAA,QACtB,UAAU;AAAA,QACV,cAAc;AAAA,MAChB;AAAA,IACF;AAAA,IACA,SAAS;AAAA,MACP,oBAAoB;AAAA,MACpB,oBAAoB;AAAA,MACpB,gBAAgB;AAAA,QACd,SAAS;AAAA,MACX;AAAA,IACF;AAAA,IACA,OAAO;AAAA,MACL,OAAO,qBAAqB,OAAO,QAAQ;AACzC,YAAI,CAAC,IAAI,KAAK,SAAS,YAAY,EAAG;AACtC,YAAI,CAAC,aAAa,SAAS,EAAG;AAE9B,cAAM,QAAQ,IAAI,QAAQ,YAAY,KAAK,SAAS;AACpD,YAAI,CAAC,eAAe,OAAO,SAAS,GAAG;AACrC,gBAAM,IAAI,SAAS,aAAa;AAAA,YAC9B,SAAS;AAAA,YACT,YAAY;AAAA,UACd,CAAC;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACH;","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@silicajs/auth",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Better Auth wrapper and allowlist helpers for Silica.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup",
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"lint": "tsc --noEmit"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"better-auth": "^1.6.11"
|
|
27
|
+
}
|
|
28
|
+
}
|