@inai-dev/hono 1.0.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/api-routes.cjs +175 -0
- package/dist/api-routes.cjs.map +1 -0
- package/dist/api-routes.d.cts +7 -0
- package/dist/api-routes.d.ts +7 -0
- package/dist/api-routes.js +155 -0
- package/dist/api-routes.js.map +1 -0
- package/dist/index.cjs +280 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +251 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware-CH4i5x6z.d.cts +22 -0
- package/dist/middleware-CH4i5x6z.d.ts +22 -0
- package/dist/middleware.cjs +172 -0
- package/dist/middleware.cjs.map +1 -0
- package/dist/middleware.d.cts +3 -0
- package/dist/middleware.d.ts +3 -0
- package/dist/middleware.js +151 -0
- package/dist/middleware.js.map +1 -0
- package/package.json +73 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/middleware.ts","../src/helpers.ts","../src/api-routes.ts"],"sourcesContent":["import \"./types\";\n\nexport { inaiAuthMiddleware, requireAuth } from \"./middleware\";\nexport type { InAIHonoMiddlewareConfig, RequireAuthConfig } from \"./types\";\n\nexport {\n getAuth,\n setAuthCookies,\n clearAuthCookies,\n getTokenFromContext,\n getRefreshTokenFromContext,\n} from \"./helpers\";\n\nexport { createAuthRoutes } from \"./api-routes\";\n\nexport type {\n AuthObject,\n UserResource,\n OrganizationResource,\n} from \"@inai-dev/types\";\n","import type { MiddlewareHandler } from \"hono\";\nimport type { InAIAuthConfig } from \"@inai-dev/types\";\nimport { InAIAuthClient, buildAuthObjectFromToken } from \"@inai-dev/backend\";\nimport { isTokenExpired } from \"@inai-dev/shared\";\nimport type { InAIHonoMiddlewareConfig, RequireAuthConfig } from \"./types\";\nimport {\n getTokenFromContext,\n getRefreshTokenFromContext,\n setAuthCookies,\n clearAuthCookies,\n getAuth,\n} from \"./helpers\";\n\nfunction matchesRoute(pathname: string, patterns: string[]): boolean {\n return patterns.some((pattern) => {\n if (pattern.endsWith(\"*\")) {\n return pathname.startsWith(pattern.slice(0, -1));\n }\n return pathname === pattern;\n });\n}\n\nfunction isPublicRoute(\n path: string,\n publicRoutes: string[] | ((path: string) => boolean),\n): boolean {\n if (typeof publicRoutes === \"function\") return publicRoutes(path);\n return matchesRoute(path, publicRoutes);\n}\n\nexport function inaiAuthMiddleware(\n config: InAIHonoMiddlewareConfig & InAIAuthConfig = {},\n): MiddlewareHandler {\n const {\n authMode = \"app\",\n publicRoutes = [],\n onUnauthorized,\n ...authClientConfig\n } = config;\n\n const client = new InAIAuthClient(authClientConfig);\n const isPlatform = authMode === \"platform\";\n\n const defaultUnauthorized = (c: Parameters<MiddlewareHandler>[0]) =>\n c.json({ error: \"Unauthorized\" }, 401);\n\n const handleUnauthorized = onUnauthorized ?? defaultUnauthorized;\n\n return async function middleware(c, next) {\n const path = new URL(c.req.url).pathname;\n\n if (isPublicRoute(path, publicRoutes)) {\n c.set(\"inaiAuth\", null);\n await next();\n return;\n }\n\n const token = getTokenFromContext(c);\n\n if (!token || isTokenExpired(token)) {\n const refreshToken = getRefreshTokenFromContext(c);\n\n if (refreshToken) {\n try {\n const tokens = isPlatform\n ? await client.platformRefresh(refreshToken)\n : await client.refresh(refreshToken);\n const { data: user } = isPlatform\n ? await client.platformGetMe(tokens.access_token)\n : await client.getMe(tokens.access_token);\n setAuthCookies(c, tokens, user);\n\n const authObj = buildAuthObjectFromToken(tokens.access_token);\n c.set(\"inaiAuth\", authObj);\n\n await next();\n return;\n } catch {\n clearAuthCookies(c);\n return handleUnauthorized(c);\n }\n }\n\n return handleUnauthorized(c);\n }\n\n const authObj = buildAuthObjectFromToken(token);\n if (!authObj) {\n return handleUnauthorized(c);\n }\n\n c.set(\"inaiAuth\", authObj);\n await next();\n };\n}\n\nexport function requireAuth(config: RequireAuthConfig = {}): MiddlewareHandler {\n return async function middleware(c, next) {\n const auth = getAuth(c);\n\n if (!auth?.userId) {\n return c.json({ error: \"Unauthorized\" }, 401);\n }\n\n if (config.role || config.permission) {\n const hasAccess = auth.has({\n role: config.role,\n permission: config.permission,\n });\n\n if (!hasAccess) {\n return c.json({ error: \"Forbidden\" }, 403);\n }\n }\n\n await next();\n };\n}\n","import type { Context } from \"hono\";\nimport { getCookie, setCookie, deleteCookie } from \"hono/cookie\";\nimport type { AuthObject, TokenPair, UserResource, PlatformUserResource } from \"@inai-dev/types\";\nimport {\n COOKIE_AUTH_TOKEN,\n COOKIE_REFRESH_TOKEN,\n COOKIE_AUTH_SESSION,\n decodeJWTPayload,\n} from \"@inai-dev/shared\";\n\nexport function getAuth(c: Context): AuthObject | null {\n return c.get(\"inaiAuth\") ?? null;\n}\n\nexport function getTokenFromContext(c: Context): string | null {\n const authHeader = c.req.header(\"Authorization\");\n if (authHeader?.startsWith(\"Bearer \")) {\n return authHeader.slice(7);\n }\n\n return getCookie(c, COOKIE_AUTH_TOKEN) ?? null;\n}\n\nexport function getRefreshTokenFromContext(c: Context): string | null {\n return getCookie(c, COOKIE_REFRESH_TOKEN) ?? null;\n}\n\nexport function setAuthCookies(\n c: Context,\n tokens: TokenPair,\n user: UserResource | PlatformUserResource,\n): void {\n const isProduction =\n typeof process !== \"undefined\" && process.env?.NODE_ENV === \"production\";\n const claims = decodeJWTPayload(tokens.access_token);\n const expiresAt = claims\n ? new Date(claims.exp * 1000).toISOString()\n : new Date(Date.now() + tokens.expires_in * 1000).toISOString();\n\n setCookie(c, COOKIE_AUTH_TOKEN, tokens.access_token, {\n httpOnly: true,\n secure: isProduction,\n sameSite: \"Lax\",\n path: \"/\",\n maxAge: tokens.expires_in,\n });\n\n setCookie(c, COOKIE_REFRESH_TOKEN, tokens.refresh_token, {\n httpOnly: true,\n secure: isProduction,\n sameSite: \"Strict\",\n path: \"/api/auth\",\n maxAge: 7 * 24 * 60 * 60,\n });\n\n setCookie(\n c,\n COOKIE_AUTH_SESSION,\n JSON.stringify({\n user,\n expiresAt,\n permissions: claims?.permissions ?? [],\n orgId: claims?.org_id,\n orgRole: claims?.org_role,\n appId: claims?.app_id,\n envId: claims?.env_id,\n }),\n {\n httpOnly: false,\n secure: isProduction,\n sameSite: \"Lax\",\n path: \"/\",\n maxAge: tokens.expires_in,\n },\n );\n}\n\nexport function clearAuthCookies(c: Context): void {\n deleteCookie(c, COOKIE_AUTH_TOKEN, { path: \"/\" });\n deleteCookie(c, COOKIE_REFRESH_TOKEN, { path: \"/api/auth\" });\n deleteCookie(c, COOKIE_AUTH_SESSION, { path: \"/\" });\n}\n","import { Hono } from \"hono\";\nimport type { InAIAuthConfig, TokenPair, UserResource, LoginResult } from \"@inai-dev/types\";\nimport { InAIAuthClient } from \"@inai-dev/backend\";\nimport {\n setAuthCookies,\n clearAuthCookies,\n getRefreshTokenFromContext,\n} from \"./helpers\";\n\nexport function createAuthRoutes(config: InAIAuthConfig = {}) {\n const app = new Hono();\n const client = new InAIAuthClient(config);\n\n app.post(\"/login\", async (c) => {\n try {\n const body = await c.req.json<Record<string, string>>();\n const result = await client.login({\n email: body.email,\n password: body.password,\n }) as LoginResult & { user?: UserResource };\n\n if (result.mfa_required) {\n return c.json({ mfa_required: true, mfa_token: result.mfa_token });\n }\n\n const tokens = result as unknown as TokenPair;\n const user =\n result.user ?? (await client.getMe(tokens.access_token)).data;\n setAuthCookies(c, tokens, user);\n\n return c.json({ user });\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Login failed\";\n return c.json({ error: message }, 401);\n }\n });\n\n app.post(\"/register\", async (c) => {\n try {\n const body = await c.req.json<Record<string, string>>();\n const result = await client.register({\n email: body.email,\n password: body.password,\n firstName: body.firstName,\n lastName: body.lastName,\n });\n\n if (!result.access_token) {\n return c.json({ needs_email_verification: true, user: result.user });\n }\n\n const tokens = result as unknown as TokenPair;\n const user =\n result.user ?? (await client.getMe(tokens.access_token)).data;\n setAuthCookies(c, tokens, user);\n\n return c.json({ user });\n } catch (err) {\n const message =\n err instanceof Error ? err.message : \"Registration failed\";\n return c.json({ error: message }, 400);\n }\n });\n\n app.post(\"/mfa-challenge\", async (c) => {\n try {\n const body = await c.req.json<Record<string, string>>();\n const tokens = await client.mfaChallenge({\n mfa_token: body.mfa_token,\n code: body.code,\n });\n\n const { data: user } = await client.getMe(tokens.access_token);\n setAuthCookies(c, tokens, user);\n\n return c.json({ user });\n } catch (err) {\n const message =\n err instanceof Error ? err.message : \"MFA verification failed\";\n return c.json({ error: message }, 401);\n }\n });\n\n app.post(\"/refresh\", async (c) => {\n try {\n const refreshToken = getRefreshTokenFromContext(c);\n\n if (!refreshToken) {\n clearAuthCookies(c);\n return c.json({ error: \"No refresh token\" }, 401);\n }\n\n const tokens = await client.refresh(refreshToken);\n const { data: user } = await client.getMe(tokens.access_token);\n setAuthCookies(c, tokens, user);\n\n return c.json({ user });\n } catch {\n clearAuthCookies(c);\n return c.json({ error: \"Refresh failed\" }, 401);\n }\n });\n\n app.post(\"/logout\", async (c) => {\n try {\n const refreshToken = getRefreshTokenFromContext(c);\n if (refreshToken) {\n await client.logout(refreshToken).catch(() => {});\n }\n clearAuthCookies(c);\n return c.json({ success: true });\n } catch {\n clearAuthCookies(c);\n return c.json({ success: true });\n }\n });\n\n return app;\n}\n"],"mappings":"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","names":["import_shared","authObj","import_backend"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { I as InAIHonoMiddlewareConfig, R as RequireAuthConfig, i as inaiAuthMiddleware, r as requireAuth } from './middleware-CH4i5x6z.cjs';
|
|
2
|
+
import { Context } from 'hono';
|
|
3
|
+
import { AuthObject, TokenPair, UserResource, PlatformUserResource } from '@inai-dev/types';
|
|
4
|
+
export { AuthObject, OrganizationResource, UserResource } from '@inai-dev/types';
|
|
5
|
+
export { createAuthRoutes } from './api-routes.cjs';
|
|
6
|
+
import 'hono/types';
|
|
7
|
+
|
|
8
|
+
declare function getAuth(c: Context): AuthObject | null;
|
|
9
|
+
declare function getTokenFromContext(c: Context): string | null;
|
|
10
|
+
declare function getRefreshTokenFromContext(c: Context): string | null;
|
|
11
|
+
declare function setAuthCookies(c: Context, tokens: TokenPair, user: UserResource | PlatformUserResource): void;
|
|
12
|
+
declare function clearAuthCookies(c: Context): void;
|
|
13
|
+
|
|
14
|
+
export { clearAuthCookies, getAuth, getRefreshTokenFromContext, getTokenFromContext, setAuthCookies };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export { I as InAIHonoMiddlewareConfig, R as RequireAuthConfig, i as inaiAuthMiddleware, r as requireAuth } from './middleware-CH4i5x6z.js';
|
|
2
|
+
import { Context } from 'hono';
|
|
3
|
+
import { AuthObject, TokenPair, UserResource, PlatformUserResource } from '@inai-dev/types';
|
|
4
|
+
export { AuthObject, OrganizationResource, UserResource } from '@inai-dev/types';
|
|
5
|
+
export { createAuthRoutes } from './api-routes.js';
|
|
6
|
+
import 'hono/types';
|
|
7
|
+
|
|
8
|
+
declare function getAuth(c: Context): AuthObject | null;
|
|
9
|
+
declare function getTokenFromContext(c: Context): string | null;
|
|
10
|
+
declare function getRefreshTokenFromContext(c: Context): string | null;
|
|
11
|
+
declare function setAuthCookies(c: Context, tokens: TokenPair, user: UserResource | PlatformUserResource): void;
|
|
12
|
+
declare function clearAuthCookies(c: Context): void;
|
|
13
|
+
|
|
14
|
+
export { clearAuthCookies, getAuth, getRefreshTokenFromContext, getTokenFromContext, setAuthCookies };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
// src/middleware.ts
|
|
2
|
+
import { InAIAuthClient, buildAuthObjectFromToken } from "@inai-dev/backend";
|
|
3
|
+
import { isTokenExpired } from "@inai-dev/shared";
|
|
4
|
+
|
|
5
|
+
// src/helpers.ts
|
|
6
|
+
import { getCookie, setCookie, deleteCookie } from "hono/cookie";
|
|
7
|
+
import {
|
|
8
|
+
COOKIE_AUTH_TOKEN,
|
|
9
|
+
COOKIE_REFRESH_TOKEN,
|
|
10
|
+
COOKIE_AUTH_SESSION,
|
|
11
|
+
decodeJWTPayload
|
|
12
|
+
} from "@inai-dev/shared";
|
|
13
|
+
function getAuth(c) {
|
|
14
|
+
return c.get("inaiAuth") ?? null;
|
|
15
|
+
}
|
|
16
|
+
function getTokenFromContext(c) {
|
|
17
|
+
const authHeader = c.req.header("Authorization");
|
|
18
|
+
if (authHeader?.startsWith("Bearer ")) {
|
|
19
|
+
return authHeader.slice(7);
|
|
20
|
+
}
|
|
21
|
+
return getCookie(c, COOKIE_AUTH_TOKEN) ?? null;
|
|
22
|
+
}
|
|
23
|
+
function getRefreshTokenFromContext(c) {
|
|
24
|
+
return getCookie(c, COOKIE_REFRESH_TOKEN) ?? null;
|
|
25
|
+
}
|
|
26
|
+
function setAuthCookies(c, tokens, user) {
|
|
27
|
+
const isProduction = typeof process !== "undefined" && process.env?.NODE_ENV === "production";
|
|
28
|
+
const claims = decodeJWTPayload(tokens.access_token);
|
|
29
|
+
const expiresAt = claims ? new Date(claims.exp * 1e3).toISOString() : new Date(Date.now() + tokens.expires_in * 1e3).toISOString();
|
|
30
|
+
setCookie(c, COOKIE_AUTH_TOKEN, tokens.access_token, {
|
|
31
|
+
httpOnly: true,
|
|
32
|
+
secure: isProduction,
|
|
33
|
+
sameSite: "Lax",
|
|
34
|
+
path: "/",
|
|
35
|
+
maxAge: tokens.expires_in
|
|
36
|
+
});
|
|
37
|
+
setCookie(c, COOKIE_REFRESH_TOKEN, tokens.refresh_token, {
|
|
38
|
+
httpOnly: true,
|
|
39
|
+
secure: isProduction,
|
|
40
|
+
sameSite: "Strict",
|
|
41
|
+
path: "/api/auth",
|
|
42
|
+
maxAge: 7 * 24 * 60 * 60
|
|
43
|
+
});
|
|
44
|
+
setCookie(
|
|
45
|
+
c,
|
|
46
|
+
COOKIE_AUTH_SESSION,
|
|
47
|
+
JSON.stringify({
|
|
48
|
+
user,
|
|
49
|
+
expiresAt,
|
|
50
|
+
permissions: claims?.permissions ?? [],
|
|
51
|
+
orgId: claims?.org_id,
|
|
52
|
+
orgRole: claims?.org_role,
|
|
53
|
+
appId: claims?.app_id,
|
|
54
|
+
envId: claims?.env_id
|
|
55
|
+
}),
|
|
56
|
+
{
|
|
57
|
+
httpOnly: false,
|
|
58
|
+
secure: isProduction,
|
|
59
|
+
sameSite: "Lax",
|
|
60
|
+
path: "/",
|
|
61
|
+
maxAge: tokens.expires_in
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
function clearAuthCookies(c) {
|
|
66
|
+
deleteCookie(c, COOKIE_AUTH_TOKEN, { path: "/" });
|
|
67
|
+
deleteCookie(c, COOKIE_REFRESH_TOKEN, { path: "/api/auth" });
|
|
68
|
+
deleteCookie(c, COOKIE_AUTH_SESSION, { path: "/" });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// src/middleware.ts
|
|
72
|
+
function matchesRoute(pathname, patterns) {
|
|
73
|
+
return patterns.some((pattern) => {
|
|
74
|
+
if (pattern.endsWith("*")) {
|
|
75
|
+
return pathname.startsWith(pattern.slice(0, -1));
|
|
76
|
+
}
|
|
77
|
+
return pathname === pattern;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
function isPublicRoute(path, publicRoutes) {
|
|
81
|
+
if (typeof publicRoutes === "function") return publicRoutes(path);
|
|
82
|
+
return matchesRoute(path, publicRoutes);
|
|
83
|
+
}
|
|
84
|
+
function inaiAuthMiddleware(config = {}) {
|
|
85
|
+
const {
|
|
86
|
+
authMode = "app",
|
|
87
|
+
publicRoutes = [],
|
|
88
|
+
onUnauthorized,
|
|
89
|
+
...authClientConfig
|
|
90
|
+
} = config;
|
|
91
|
+
const client = new InAIAuthClient(authClientConfig);
|
|
92
|
+
const isPlatform = authMode === "platform";
|
|
93
|
+
const defaultUnauthorized = (c) => c.json({ error: "Unauthorized" }, 401);
|
|
94
|
+
const handleUnauthorized = onUnauthorized ?? defaultUnauthorized;
|
|
95
|
+
return async function middleware(c, next) {
|
|
96
|
+
const path = new URL(c.req.url).pathname;
|
|
97
|
+
if (isPublicRoute(path, publicRoutes)) {
|
|
98
|
+
c.set("inaiAuth", null);
|
|
99
|
+
await next();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const token = getTokenFromContext(c);
|
|
103
|
+
if (!token || isTokenExpired(token)) {
|
|
104
|
+
const refreshToken = getRefreshTokenFromContext(c);
|
|
105
|
+
if (refreshToken) {
|
|
106
|
+
try {
|
|
107
|
+
const tokens = isPlatform ? await client.platformRefresh(refreshToken) : await client.refresh(refreshToken);
|
|
108
|
+
const { data: user } = isPlatform ? await client.platformGetMe(tokens.access_token) : await client.getMe(tokens.access_token);
|
|
109
|
+
setAuthCookies(c, tokens, user);
|
|
110
|
+
const authObj2 = buildAuthObjectFromToken(tokens.access_token);
|
|
111
|
+
c.set("inaiAuth", authObj2);
|
|
112
|
+
await next();
|
|
113
|
+
return;
|
|
114
|
+
} catch {
|
|
115
|
+
clearAuthCookies(c);
|
|
116
|
+
return handleUnauthorized(c);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return handleUnauthorized(c);
|
|
120
|
+
}
|
|
121
|
+
const authObj = buildAuthObjectFromToken(token);
|
|
122
|
+
if (!authObj) {
|
|
123
|
+
return handleUnauthorized(c);
|
|
124
|
+
}
|
|
125
|
+
c.set("inaiAuth", authObj);
|
|
126
|
+
await next();
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function requireAuth(config = {}) {
|
|
130
|
+
return async function middleware(c, next) {
|
|
131
|
+
const auth = getAuth(c);
|
|
132
|
+
if (!auth?.userId) {
|
|
133
|
+
return c.json({ error: "Unauthorized" }, 401);
|
|
134
|
+
}
|
|
135
|
+
if (config.role || config.permission) {
|
|
136
|
+
const hasAccess = auth.has({
|
|
137
|
+
role: config.role,
|
|
138
|
+
permission: config.permission
|
|
139
|
+
});
|
|
140
|
+
if (!hasAccess) {
|
|
141
|
+
return c.json({ error: "Forbidden" }, 403);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
await next();
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// src/api-routes.ts
|
|
149
|
+
import { Hono } from "hono";
|
|
150
|
+
import { InAIAuthClient as InAIAuthClient2 } from "@inai-dev/backend";
|
|
151
|
+
function createAuthRoutes(config = {}) {
|
|
152
|
+
const app = new Hono();
|
|
153
|
+
const client = new InAIAuthClient2(config);
|
|
154
|
+
app.post("/login", async (c) => {
|
|
155
|
+
try {
|
|
156
|
+
const body = await c.req.json();
|
|
157
|
+
const result = await client.login({
|
|
158
|
+
email: body.email,
|
|
159
|
+
password: body.password
|
|
160
|
+
});
|
|
161
|
+
if (result.mfa_required) {
|
|
162
|
+
return c.json({ mfa_required: true, mfa_token: result.mfa_token });
|
|
163
|
+
}
|
|
164
|
+
const tokens = result;
|
|
165
|
+
const user = result.user ?? (await client.getMe(tokens.access_token)).data;
|
|
166
|
+
setAuthCookies(c, tokens, user);
|
|
167
|
+
return c.json({ user });
|
|
168
|
+
} catch (err) {
|
|
169
|
+
const message = err instanceof Error ? err.message : "Login failed";
|
|
170
|
+
return c.json({ error: message }, 401);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
app.post("/register", async (c) => {
|
|
174
|
+
try {
|
|
175
|
+
const body = await c.req.json();
|
|
176
|
+
const result = await client.register({
|
|
177
|
+
email: body.email,
|
|
178
|
+
password: body.password,
|
|
179
|
+
firstName: body.firstName,
|
|
180
|
+
lastName: body.lastName
|
|
181
|
+
});
|
|
182
|
+
if (!result.access_token) {
|
|
183
|
+
return c.json({ needs_email_verification: true, user: result.user });
|
|
184
|
+
}
|
|
185
|
+
const tokens = result;
|
|
186
|
+
const user = result.user ?? (await client.getMe(tokens.access_token)).data;
|
|
187
|
+
setAuthCookies(c, tokens, user);
|
|
188
|
+
return c.json({ user });
|
|
189
|
+
} catch (err) {
|
|
190
|
+
const message = err instanceof Error ? err.message : "Registration failed";
|
|
191
|
+
return c.json({ error: message }, 400);
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
app.post("/mfa-challenge", async (c) => {
|
|
195
|
+
try {
|
|
196
|
+
const body = await c.req.json();
|
|
197
|
+
const tokens = await client.mfaChallenge({
|
|
198
|
+
mfa_token: body.mfa_token,
|
|
199
|
+
code: body.code
|
|
200
|
+
});
|
|
201
|
+
const { data: user } = await client.getMe(tokens.access_token);
|
|
202
|
+
setAuthCookies(c, tokens, user);
|
|
203
|
+
return c.json({ user });
|
|
204
|
+
} catch (err) {
|
|
205
|
+
const message = err instanceof Error ? err.message : "MFA verification failed";
|
|
206
|
+
return c.json({ error: message }, 401);
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
app.post("/refresh", async (c) => {
|
|
210
|
+
try {
|
|
211
|
+
const refreshToken = getRefreshTokenFromContext(c);
|
|
212
|
+
if (!refreshToken) {
|
|
213
|
+
clearAuthCookies(c);
|
|
214
|
+
return c.json({ error: "No refresh token" }, 401);
|
|
215
|
+
}
|
|
216
|
+
const tokens = await client.refresh(refreshToken);
|
|
217
|
+
const { data: user } = await client.getMe(tokens.access_token);
|
|
218
|
+
setAuthCookies(c, tokens, user);
|
|
219
|
+
return c.json({ user });
|
|
220
|
+
} catch {
|
|
221
|
+
clearAuthCookies(c);
|
|
222
|
+
return c.json({ error: "Refresh failed" }, 401);
|
|
223
|
+
}
|
|
224
|
+
});
|
|
225
|
+
app.post("/logout", async (c) => {
|
|
226
|
+
try {
|
|
227
|
+
const refreshToken = getRefreshTokenFromContext(c);
|
|
228
|
+
if (refreshToken) {
|
|
229
|
+
await client.logout(refreshToken).catch(() => {
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
clearAuthCookies(c);
|
|
233
|
+
return c.json({ success: true });
|
|
234
|
+
} catch {
|
|
235
|
+
clearAuthCookies(c);
|
|
236
|
+
return c.json({ success: true });
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
return app;
|
|
240
|
+
}
|
|
241
|
+
export {
|
|
242
|
+
clearAuthCookies,
|
|
243
|
+
createAuthRoutes,
|
|
244
|
+
getAuth,
|
|
245
|
+
getRefreshTokenFromContext,
|
|
246
|
+
getTokenFromContext,
|
|
247
|
+
inaiAuthMiddleware,
|
|
248
|
+
requireAuth,
|
|
249
|
+
setAuthCookies
|
|
250
|
+
};
|
|
251
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/middleware.ts","../src/helpers.ts","../src/api-routes.ts"],"sourcesContent":["import type { MiddlewareHandler } from \"hono\";\nimport type { InAIAuthConfig } from \"@inai-dev/types\";\nimport { InAIAuthClient, buildAuthObjectFromToken } from \"@inai-dev/backend\";\nimport { isTokenExpired } from \"@inai-dev/shared\";\nimport type { InAIHonoMiddlewareConfig, RequireAuthConfig } from \"./types\";\nimport {\n getTokenFromContext,\n getRefreshTokenFromContext,\n setAuthCookies,\n clearAuthCookies,\n getAuth,\n} from \"./helpers\";\n\nfunction matchesRoute(pathname: string, patterns: string[]): boolean {\n return patterns.some((pattern) => {\n if (pattern.endsWith(\"*\")) {\n return pathname.startsWith(pattern.slice(0, -1));\n }\n return pathname === pattern;\n });\n}\n\nfunction isPublicRoute(\n path: string,\n publicRoutes: string[] | ((path: string) => boolean),\n): boolean {\n if (typeof publicRoutes === \"function\") return publicRoutes(path);\n return matchesRoute(path, publicRoutes);\n}\n\nexport function inaiAuthMiddleware(\n config: InAIHonoMiddlewareConfig & InAIAuthConfig = {},\n): MiddlewareHandler {\n const {\n authMode = \"app\",\n publicRoutes = [],\n onUnauthorized,\n ...authClientConfig\n } = config;\n\n const client = new InAIAuthClient(authClientConfig);\n const isPlatform = authMode === \"platform\";\n\n const defaultUnauthorized = (c: Parameters<MiddlewareHandler>[0]) =>\n c.json({ error: \"Unauthorized\" }, 401);\n\n const handleUnauthorized = onUnauthorized ?? defaultUnauthorized;\n\n return async function middleware(c, next) {\n const path = new URL(c.req.url).pathname;\n\n if (isPublicRoute(path, publicRoutes)) {\n c.set(\"inaiAuth\", null);\n await next();\n return;\n }\n\n const token = getTokenFromContext(c);\n\n if (!token || isTokenExpired(token)) {\n const refreshToken = getRefreshTokenFromContext(c);\n\n if (refreshToken) {\n try {\n const tokens = isPlatform\n ? await client.platformRefresh(refreshToken)\n : await client.refresh(refreshToken);\n const { data: user } = isPlatform\n ? await client.platformGetMe(tokens.access_token)\n : await client.getMe(tokens.access_token);\n setAuthCookies(c, tokens, user);\n\n const authObj = buildAuthObjectFromToken(tokens.access_token);\n c.set(\"inaiAuth\", authObj);\n\n await next();\n return;\n } catch {\n clearAuthCookies(c);\n return handleUnauthorized(c);\n }\n }\n\n return handleUnauthorized(c);\n }\n\n const authObj = buildAuthObjectFromToken(token);\n if (!authObj) {\n return handleUnauthorized(c);\n }\n\n c.set(\"inaiAuth\", authObj);\n await next();\n };\n}\n\nexport function requireAuth(config: RequireAuthConfig = {}): MiddlewareHandler {\n return async function middleware(c, next) {\n const auth = getAuth(c);\n\n if (!auth?.userId) {\n return c.json({ error: \"Unauthorized\" }, 401);\n }\n\n if (config.role || config.permission) {\n const hasAccess = auth.has({\n role: config.role,\n permission: config.permission,\n });\n\n if (!hasAccess) {\n return c.json({ error: \"Forbidden\" }, 403);\n }\n }\n\n await next();\n };\n}\n","import type { Context } from \"hono\";\nimport { getCookie, setCookie, deleteCookie } from \"hono/cookie\";\nimport type { AuthObject, TokenPair, UserResource, PlatformUserResource } from \"@inai-dev/types\";\nimport {\n COOKIE_AUTH_TOKEN,\n COOKIE_REFRESH_TOKEN,\n COOKIE_AUTH_SESSION,\n decodeJWTPayload,\n} from \"@inai-dev/shared\";\n\nexport function getAuth(c: Context): AuthObject | null {\n return c.get(\"inaiAuth\") ?? null;\n}\n\nexport function getTokenFromContext(c: Context): string | null {\n const authHeader = c.req.header(\"Authorization\");\n if (authHeader?.startsWith(\"Bearer \")) {\n return authHeader.slice(7);\n }\n\n return getCookie(c, COOKIE_AUTH_TOKEN) ?? null;\n}\n\nexport function getRefreshTokenFromContext(c: Context): string | null {\n return getCookie(c, COOKIE_REFRESH_TOKEN) ?? null;\n}\n\nexport function setAuthCookies(\n c: Context,\n tokens: TokenPair,\n user: UserResource | PlatformUserResource,\n): void {\n const isProduction =\n typeof process !== \"undefined\" && process.env?.NODE_ENV === \"production\";\n const claims = decodeJWTPayload(tokens.access_token);\n const expiresAt = claims\n ? new Date(claims.exp * 1000).toISOString()\n : new Date(Date.now() + tokens.expires_in * 1000).toISOString();\n\n setCookie(c, COOKIE_AUTH_TOKEN, tokens.access_token, {\n httpOnly: true,\n secure: isProduction,\n sameSite: \"Lax\",\n path: \"/\",\n maxAge: tokens.expires_in,\n });\n\n setCookie(c, COOKIE_REFRESH_TOKEN, tokens.refresh_token, {\n httpOnly: true,\n secure: isProduction,\n sameSite: \"Strict\",\n path: \"/api/auth\",\n maxAge: 7 * 24 * 60 * 60,\n });\n\n setCookie(\n c,\n COOKIE_AUTH_SESSION,\n JSON.stringify({\n user,\n expiresAt,\n permissions: claims?.permissions ?? [],\n orgId: claims?.org_id,\n orgRole: claims?.org_role,\n appId: claims?.app_id,\n envId: claims?.env_id,\n }),\n {\n httpOnly: false,\n secure: isProduction,\n sameSite: \"Lax\",\n path: \"/\",\n maxAge: tokens.expires_in,\n },\n );\n}\n\nexport function clearAuthCookies(c: Context): void {\n deleteCookie(c, COOKIE_AUTH_TOKEN, { path: \"/\" });\n deleteCookie(c, COOKIE_REFRESH_TOKEN, { path: \"/api/auth\" });\n deleteCookie(c, COOKIE_AUTH_SESSION, { path: \"/\" });\n}\n","import { Hono } from \"hono\";\nimport type { InAIAuthConfig, TokenPair, UserResource, LoginResult } from \"@inai-dev/types\";\nimport { InAIAuthClient } from \"@inai-dev/backend\";\nimport {\n setAuthCookies,\n clearAuthCookies,\n getRefreshTokenFromContext,\n} from \"./helpers\";\n\nexport function createAuthRoutes(config: InAIAuthConfig = {}) {\n const app = new Hono();\n const client = new InAIAuthClient(config);\n\n app.post(\"/login\", async (c) => {\n try {\n const body = await c.req.json<Record<string, string>>();\n const result = await client.login({\n email: body.email,\n password: body.password,\n }) as LoginResult & { user?: UserResource };\n\n if (result.mfa_required) {\n return c.json({ mfa_required: true, mfa_token: result.mfa_token });\n }\n\n const tokens = result as unknown as TokenPair;\n const user =\n result.user ?? (await client.getMe(tokens.access_token)).data;\n setAuthCookies(c, tokens, user);\n\n return c.json({ user });\n } catch (err) {\n const message = err instanceof Error ? err.message : \"Login failed\";\n return c.json({ error: message }, 401);\n }\n });\n\n app.post(\"/register\", async (c) => {\n try {\n const body = await c.req.json<Record<string, string>>();\n const result = await client.register({\n email: body.email,\n password: body.password,\n firstName: body.firstName,\n lastName: body.lastName,\n });\n\n if (!result.access_token) {\n return c.json({ needs_email_verification: true, user: result.user });\n }\n\n const tokens = result as unknown as TokenPair;\n const user =\n result.user ?? (await client.getMe(tokens.access_token)).data;\n setAuthCookies(c, tokens, user);\n\n return c.json({ user });\n } catch (err) {\n const message =\n err instanceof Error ? err.message : \"Registration failed\";\n return c.json({ error: message }, 400);\n }\n });\n\n app.post(\"/mfa-challenge\", async (c) => {\n try {\n const body = await c.req.json<Record<string, string>>();\n const tokens = await client.mfaChallenge({\n mfa_token: body.mfa_token,\n code: body.code,\n });\n\n const { data: user } = await client.getMe(tokens.access_token);\n setAuthCookies(c, tokens, user);\n\n return c.json({ user });\n } catch (err) {\n const message =\n err instanceof Error ? err.message : \"MFA verification failed\";\n return c.json({ error: message }, 401);\n }\n });\n\n app.post(\"/refresh\", async (c) => {\n try {\n const refreshToken = getRefreshTokenFromContext(c);\n\n if (!refreshToken) {\n clearAuthCookies(c);\n return c.json({ error: \"No refresh token\" }, 401);\n }\n\n const tokens = await client.refresh(refreshToken);\n const { data: user } = await client.getMe(tokens.access_token);\n setAuthCookies(c, tokens, user);\n\n return c.json({ user });\n } catch {\n clearAuthCookies(c);\n return c.json({ error: \"Refresh failed\" }, 401);\n }\n });\n\n app.post(\"/logout\", async (c) => {\n try {\n const refreshToken = getRefreshTokenFromContext(c);\n if (refreshToken) {\n await client.logout(refreshToken).catch(() => {});\n }\n clearAuthCookies(c);\n return c.json({ success: true });\n } catch {\n clearAuthCookies(c);\n return c.json({ success: true });\n }\n });\n\n return app;\n}\n"],"mappings":"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","names":["authObj","InAIAuthClient","InAIAuthClient"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Context, MiddlewareHandler } from 'hono';
|
|
2
|
+
import { AuthObject, InAIAuthConfig } from '@inai-dev/types';
|
|
3
|
+
|
|
4
|
+
declare module "hono" {
|
|
5
|
+
interface ContextVariableMap {
|
|
6
|
+
inaiAuth: AuthObject | null;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
interface InAIHonoMiddlewareConfig {
|
|
10
|
+
authMode?: "app" | "platform";
|
|
11
|
+
publicRoutes?: string[] | ((path: string) => boolean);
|
|
12
|
+
onUnauthorized?: (c: Context) => Response | Promise<Response>;
|
|
13
|
+
}
|
|
14
|
+
interface RequireAuthConfig {
|
|
15
|
+
role?: string;
|
|
16
|
+
permission?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare function inaiAuthMiddleware(config?: InAIHonoMiddlewareConfig & InAIAuthConfig): MiddlewareHandler;
|
|
20
|
+
declare function requireAuth(config?: RequireAuthConfig): MiddlewareHandler;
|
|
21
|
+
|
|
22
|
+
export { type InAIHonoMiddlewareConfig as I, type RequireAuthConfig as R, inaiAuthMiddleware as i, requireAuth as r };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Context, MiddlewareHandler } from 'hono';
|
|
2
|
+
import { AuthObject, InAIAuthConfig } from '@inai-dev/types';
|
|
3
|
+
|
|
4
|
+
declare module "hono" {
|
|
5
|
+
interface ContextVariableMap {
|
|
6
|
+
inaiAuth: AuthObject | null;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
interface InAIHonoMiddlewareConfig {
|
|
10
|
+
authMode?: "app" | "platform";
|
|
11
|
+
publicRoutes?: string[] | ((path: string) => boolean);
|
|
12
|
+
onUnauthorized?: (c: Context) => Response | Promise<Response>;
|
|
13
|
+
}
|
|
14
|
+
interface RequireAuthConfig {
|
|
15
|
+
role?: string;
|
|
16
|
+
permission?: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare function inaiAuthMiddleware(config?: InAIHonoMiddlewareConfig & InAIAuthConfig): MiddlewareHandler;
|
|
20
|
+
declare function requireAuth(config?: RequireAuthConfig): MiddlewareHandler;
|
|
21
|
+
|
|
22
|
+
export { type InAIHonoMiddlewareConfig as I, type RequireAuthConfig as R, inaiAuthMiddleware as i, requireAuth as r };
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/middleware.ts
|
|
21
|
+
var middleware_exports = {};
|
|
22
|
+
__export(middleware_exports, {
|
|
23
|
+
inaiAuthMiddleware: () => inaiAuthMiddleware,
|
|
24
|
+
requireAuth: () => requireAuth
|
|
25
|
+
});
|
|
26
|
+
module.exports = __toCommonJS(middleware_exports);
|
|
27
|
+
var import_backend = require("@inai-dev/backend");
|
|
28
|
+
var import_shared2 = require("@inai-dev/shared");
|
|
29
|
+
|
|
30
|
+
// src/helpers.ts
|
|
31
|
+
var import_cookie = require("hono/cookie");
|
|
32
|
+
var import_shared = require("@inai-dev/shared");
|
|
33
|
+
function getAuth(c) {
|
|
34
|
+
return c.get("inaiAuth") ?? null;
|
|
35
|
+
}
|
|
36
|
+
function getTokenFromContext(c) {
|
|
37
|
+
const authHeader = c.req.header("Authorization");
|
|
38
|
+
if (authHeader?.startsWith("Bearer ")) {
|
|
39
|
+
return authHeader.slice(7);
|
|
40
|
+
}
|
|
41
|
+
return (0, import_cookie.getCookie)(c, import_shared.COOKIE_AUTH_TOKEN) ?? null;
|
|
42
|
+
}
|
|
43
|
+
function getRefreshTokenFromContext(c) {
|
|
44
|
+
return (0, import_cookie.getCookie)(c, import_shared.COOKIE_REFRESH_TOKEN) ?? null;
|
|
45
|
+
}
|
|
46
|
+
function setAuthCookies(c, tokens, user) {
|
|
47
|
+
const isProduction = typeof process !== "undefined" && process.env?.NODE_ENV === "production";
|
|
48
|
+
const claims = (0, import_shared.decodeJWTPayload)(tokens.access_token);
|
|
49
|
+
const expiresAt = claims ? new Date(claims.exp * 1e3).toISOString() : new Date(Date.now() + tokens.expires_in * 1e3).toISOString();
|
|
50
|
+
(0, import_cookie.setCookie)(c, import_shared.COOKIE_AUTH_TOKEN, tokens.access_token, {
|
|
51
|
+
httpOnly: true,
|
|
52
|
+
secure: isProduction,
|
|
53
|
+
sameSite: "Lax",
|
|
54
|
+
path: "/",
|
|
55
|
+
maxAge: tokens.expires_in
|
|
56
|
+
});
|
|
57
|
+
(0, import_cookie.setCookie)(c, import_shared.COOKIE_REFRESH_TOKEN, tokens.refresh_token, {
|
|
58
|
+
httpOnly: true,
|
|
59
|
+
secure: isProduction,
|
|
60
|
+
sameSite: "Strict",
|
|
61
|
+
path: "/api/auth",
|
|
62
|
+
maxAge: 7 * 24 * 60 * 60
|
|
63
|
+
});
|
|
64
|
+
(0, import_cookie.setCookie)(
|
|
65
|
+
c,
|
|
66
|
+
import_shared.COOKIE_AUTH_SESSION,
|
|
67
|
+
JSON.stringify({
|
|
68
|
+
user,
|
|
69
|
+
expiresAt,
|
|
70
|
+
permissions: claims?.permissions ?? [],
|
|
71
|
+
orgId: claims?.org_id,
|
|
72
|
+
orgRole: claims?.org_role,
|
|
73
|
+
appId: claims?.app_id,
|
|
74
|
+
envId: claims?.env_id
|
|
75
|
+
}),
|
|
76
|
+
{
|
|
77
|
+
httpOnly: false,
|
|
78
|
+
secure: isProduction,
|
|
79
|
+
sameSite: "Lax",
|
|
80
|
+
path: "/",
|
|
81
|
+
maxAge: tokens.expires_in
|
|
82
|
+
}
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
function clearAuthCookies(c) {
|
|
86
|
+
(0, import_cookie.deleteCookie)(c, import_shared.COOKIE_AUTH_TOKEN, { path: "/" });
|
|
87
|
+
(0, import_cookie.deleteCookie)(c, import_shared.COOKIE_REFRESH_TOKEN, { path: "/api/auth" });
|
|
88
|
+
(0, import_cookie.deleteCookie)(c, import_shared.COOKIE_AUTH_SESSION, { path: "/" });
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// src/middleware.ts
|
|
92
|
+
function matchesRoute(pathname, patterns) {
|
|
93
|
+
return patterns.some((pattern) => {
|
|
94
|
+
if (pattern.endsWith("*")) {
|
|
95
|
+
return pathname.startsWith(pattern.slice(0, -1));
|
|
96
|
+
}
|
|
97
|
+
return pathname === pattern;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function isPublicRoute(path, publicRoutes) {
|
|
101
|
+
if (typeof publicRoutes === "function") return publicRoutes(path);
|
|
102
|
+
return matchesRoute(path, publicRoutes);
|
|
103
|
+
}
|
|
104
|
+
function inaiAuthMiddleware(config = {}) {
|
|
105
|
+
const {
|
|
106
|
+
authMode = "app",
|
|
107
|
+
publicRoutes = [],
|
|
108
|
+
onUnauthorized,
|
|
109
|
+
...authClientConfig
|
|
110
|
+
} = config;
|
|
111
|
+
const client = new import_backend.InAIAuthClient(authClientConfig);
|
|
112
|
+
const isPlatform = authMode === "platform";
|
|
113
|
+
const defaultUnauthorized = (c) => c.json({ error: "Unauthorized" }, 401);
|
|
114
|
+
const handleUnauthorized = onUnauthorized ?? defaultUnauthorized;
|
|
115
|
+
return async function middleware(c, next) {
|
|
116
|
+
const path = new URL(c.req.url).pathname;
|
|
117
|
+
if (isPublicRoute(path, publicRoutes)) {
|
|
118
|
+
c.set("inaiAuth", null);
|
|
119
|
+
await next();
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const token = getTokenFromContext(c);
|
|
123
|
+
if (!token || (0, import_shared2.isTokenExpired)(token)) {
|
|
124
|
+
const refreshToken = getRefreshTokenFromContext(c);
|
|
125
|
+
if (refreshToken) {
|
|
126
|
+
try {
|
|
127
|
+
const tokens = isPlatform ? await client.platformRefresh(refreshToken) : await client.refresh(refreshToken);
|
|
128
|
+
const { data: user } = isPlatform ? await client.platformGetMe(tokens.access_token) : await client.getMe(tokens.access_token);
|
|
129
|
+
setAuthCookies(c, tokens, user);
|
|
130
|
+
const authObj2 = (0, import_backend.buildAuthObjectFromToken)(tokens.access_token);
|
|
131
|
+
c.set("inaiAuth", authObj2);
|
|
132
|
+
await next();
|
|
133
|
+
return;
|
|
134
|
+
} catch {
|
|
135
|
+
clearAuthCookies(c);
|
|
136
|
+
return handleUnauthorized(c);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return handleUnauthorized(c);
|
|
140
|
+
}
|
|
141
|
+
const authObj = (0, import_backend.buildAuthObjectFromToken)(token);
|
|
142
|
+
if (!authObj) {
|
|
143
|
+
return handleUnauthorized(c);
|
|
144
|
+
}
|
|
145
|
+
c.set("inaiAuth", authObj);
|
|
146
|
+
await next();
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
function requireAuth(config = {}) {
|
|
150
|
+
return async function middleware(c, next) {
|
|
151
|
+
const auth = getAuth(c);
|
|
152
|
+
if (!auth?.userId) {
|
|
153
|
+
return c.json({ error: "Unauthorized" }, 401);
|
|
154
|
+
}
|
|
155
|
+
if (config.role || config.permission) {
|
|
156
|
+
const hasAccess = auth.has({
|
|
157
|
+
role: config.role,
|
|
158
|
+
permission: config.permission
|
|
159
|
+
});
|
|
160
|
+
if (!hasAccess) {
|
|
161
|
+
return c.json({ error: "Forbidden" }, 403);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
await next();
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
168
|
+
0 && (module.exports = {
|
|
169
|
+
inaiAuthMiddleware,
|
|
170
|
+
requireAuth
|
|
171
|
+
});
|
|
172
|
+
//# sourceMappingURL=middleware.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/middleware.ts","../src/helpers.ts"],"sourcesContent":["import type { MiddlewareHandler } from \"hono\";\nimport type { InAIAuthConfig } from \"@inai-dev/types\";\nimport { InAIAuthClient, buildAuthObjectFromToken } from \"@inai-dev/backend\";\nimport { isTokenExpired } from \"@inai-dev/shared\";\nimport type { InAIHonoMiddlewareConfig, RequireAuthConfig } from \"./types\";\nimport {\n getTokenFromContext,\n getRefreshTokenFromContext,\n setAuthCookies,\n clearAuthCookies,\n getAuth,\n} from \"./helpers\";\n\nfunction matchesRoute(pathname: string, patterns: string[]): boolean {\n return patterns.some((pattern) => {\n if (pattern.endsWith(\"*\")) {\n return pathname.startsWith(pattern.slice(0, -1));\n }\n return pathname === pattern;\n });\n}\n\nfunction isPublicRoute(\n path: string,\n publicRoutes: string[] | ((path: string) => boolean),\n): boolean {\n if (typeof publicRoutes === \"function\") return publicRoutes(path);\n return matchesRoute(path, publicRoutes);\n}\n\nexport function inaiAuthMiddleware(\n config: InAIHonoMiddlewareConfig & InAIAuthConfig = {},\n): MiddlewareHandler {\n const {\n authMode = \"app\",\n publicRoutes = [],\n onUnauthorized,\n ...authClientConfig\n } = config;\n\n const client = new InAIAuthClient(authClientConfig);\n const isPlatform = authMode === \"platform\";\n\n const defaultUnauthorized = (c: Parameters<MiddlewareHandler>[0]) =>\n c.json({ error: \"Unauthorized\" }, 401);\n\n const handleUnauthorized = onUnauthorized ?? defaultUnauthorized;\n\n return async function middleware(c, next) {\n const path = new URL(c.req.url).pathname;\n\n if (isPublicRoute(path, publicRoutes)) {\n c.set(\"inaiAuth\", null);\n await next();\n return;\n }\n\n const token = getTokenFromContext(c);\n\n if (!token || isTokenExpired(token)) {\n const refreshToken = getRefreshTokenFromContext(c);\n\n if (refreshToken) {\n try {\n const tokens = isPlatform\n ? await client.platformRefresh(refreshToken)\n : await client.refresh(refreshToken);\n const { data: user } = isPlatform\n ? await client.platformGetMe(tokens.access_token)\n : await client.getMe(tokens.access_token);\n setAuthCookies(c, tokens, user);\n\n const authObj = buildAuthObjectFromToken(tokens.access_token);\n c.set(\"inaiAuth\", authObj);\n\n await next();\n return;\n } catch {\n clearAuthCookies(c);\n return handleUnauthorized(c);\n }\n }\n\n return handleUnauthorized(c);\n }\n\n const authObj = buildAuthObjectFromToken(token);\n if (!authObj) {\n return handleUnauthorized(c);\n }\n\n c.set(\"inaiAuth\", authObj);\n await next();\n };\n}\n\nexport function requireAuth(config: RequireAuthConfig = {}): MiddlewareHandler {\n return async function middleware(c, next) {\n const auth = getAuth(c);\n\n if (!auth?.userId) {\n return c.json({ error: \"Unauthorized\" }, 401);\n }\n\n if (config.role || config.permission) {\n const hasAccess = auth.has({\n role: config.role,\n permission: config.permission,\n });\n\n if (!hasAccess) {\n return c.json({ error: \"Forbidden\" }, 403);\n }\n }\n\n await next();\n };\n}\n","import type { Context } from \"hono\";\nimport { getCookie, setCookie, deleteCookie } from \"hono/cookie\";\nimport type { AuthObject, TokenPair, UserResource, PlatformUserResource } from \"@inai-dev/types\";\nimport {\n COOKIE_AUTH_TOKEN,\n COOKIE_REFRESH_TOKEN,\n COOKIE_AUTH_SESSION,\n decodeJWTPayload,\n} from \"@inai-dev/shared\";\n\nexport function getAuth(c: Context): AuthObject | null {\n return c.get(\"inaiAuth\") ?? null;\n}\n\nexport function getTokenFromContext(c: Context): string | null {\n const authHeader = c.req.header(\"Authorization\");\n if (authHeader?.startsWith(\"Bearer \")) {\n return authHeader.slice(7);\n }\n\n return getCookie(c, COOKIE_AUTH_TOKEN) ?? null;\n}\n\nexport function getRefreshTokenFromContext(c: Context): string | null {\n return getCookie(c, COOKIE_REFRESH_TOKEN) ?? null;\n}\n\nexport function setAuthCookies(\n c: Context,\n tokens: TokenPair,\n user: UserResource | PlatformUserResource,\n): void {\n const isProduction =\n typeof process !== \"undefined\" && process.env?.NODE_ENV === \"production\";\n const claims = decodeJWTPayload(tokens.access_token);\n const expiresAt = claims\n ? new Date(claims.exp * 1000).toISOString()\n : new Date(Date.now() + tokens.expires_in * 1000).toISOString();\n\n setCookie(c, COOKIE_AUTH_TOKEN, tokens.access_token, {\n httpOnly: true,\n secure: isProduction,\n sameSite: \"Lax\",\n path: \"/\",\n maxAge: tokens.expires_in,\n });\n\n setCookie(c, COOKIE_REFRESH_TOKEN, tokens.refresh_token, {\n httpOnly: true,\n secure: isProduction,\n sameSite: \"Strict\",\n path: \"/api/auth\",\n maxAge: 7 * 24 * 60 * 60,\n });\n\n setCookie(\n c,\n COOKIE_AUTH_SESSION,\n JSON.stringify({\n user,\n expiresAt,\n permissions: claims?.permissions ?? [],\n orgId: claims?.org_id,\n orgRole: claims?.org_role,\n appId: claims?.app_id,\n envId: claims?.env_id,\n }),\n {\n httpOnly: false,\n secure: isProduction,\n sameSite: \"Lax\",\n path: \"/\",\n maxAge: tokens.expires_in,\n },\n );\n}\n\nexport function clearAuthCookies(c: Context): void {\n deleteCookie(c, COOKIE_AUTH_TOKEN, { path: \"/\" });\n deleteCookie(c, COOKIE_REFRESH_TOKEN, { path: \"/api/auth\" });\n deleteCookie(c, COOKIE_AUTH_SESSION, { path: \"/\" });\n}\n"],"mappings":"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","names":["import_shared","authObj"]}
|