@inai-dev/hono 1.1.0 → 1.2.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 CHANGED
@@ -58,11 +58,16 @@ inaiAuthMiddleware({
58
58
  // Custom unauthorized handler (default: 401 JSON response)
59
59
  onUnauthorized: (c) => c.json({ error: "Please sign in" }, 401),
60
60
 
61
+ // JWKS endpoint for ES256 token verification (optional)
62
+ jwksUrl: "https://apiauth.inai.dev/.well-known/jwks.json",
63
+
61
64
  // InAIAuthClient config (optional if using env vars)
62
65
  publishableKey: "pk_live_...",
63
66
  });
64
67
  ```
65
68
 
69
+ > All tokens are cryptographically verified using ES256 (ECDSA P-256). Public keys are fetched from the JWKS endpoint and cached for 5 minutes.
70
+
66
71
  ### 2. Route Protection (RBAC)
67
72
 
68
73
  ```ts
package/dist/index.cjs CHANGED
@@ -118,6 +118,8 @@ function inaiAuthMiddleware(config = {}) {
118
118
  } = config;
119
119
  const client = new import_backend.InAIAuthClient(authClientConfig);
120
120
  const isPlatform = authMode === "platform";
121
+ const jwksUrl = authClientConfig.jwksUrl ?? `${authClientConfig.apiUrl ?? import_shared2.DEFAULT_API_URL}/.well-known/jwks.json`;
122
+ const jwksClient = new import_shared2.JWKSClient(jwksUrl);
121
123
  const defaultUnauthorized = (c) => c.json({ error: "Unauthorized" }, 401);
122
124
  const handleUnauthorized = onUnauthorized ?? defaultUnauthorized;
123
125
  return async function middleware(c, next) {
@@ -135,7 +137,7 @@ function inaiAuthMiddleware(config = {}) {
135
137
  const tokens = isPlatform ? await client.platformRefresh(refreshToken) : await client.refresh(refreshToken);
136
138
  const { data: user } = isPlatform ? await client.platformGetMe(tokens.access_token) : await client.getMe(tokens.access_token);
137
139
  setAuthCookies(c, tokens, user);
138
- const authObj2 = (0, import_backend.buildAuthObjectFromToken)(tokens.access_token);
140
+ const authObj2 = await (0, import_backend.buildAuthObjectFromToken)(tokens.access_token, jwksClient);
139
141
  c.set("inaiAuth", authObj2);
140
142
  await next();
141
143
  return;
@@ -146,7 +148,7 @@ function inaiAuthMiddleware(config = {}) {
146
148
  }
147
149
  return handleUnauthorized(c);
148
150
  }
149
- const authObj = (0, import_backend.buildAuthObjectFromToken)(token);
151
+ const authObj = await (0, import_backend.buildAuthObjectFromToken)(token, jwksClient);
150
152
  if (!authObj) {
151
153
  return handleUnauthorized(c);
152
154
  }
@@ -1 +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"]}
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, JWKSClient, DEFAULT_API_URL } 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 jwksUrl = authClientConfig.jwksUrl\n ?? `${authClientConfig.apiUrl ?? DEFAULT_API_URL}/.well-known/jwks.json`;\n const jwksClient = new JWKSClient(jwksUrl);\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 = await buildAuthObjectFromToken(tokens.access_token, jwksClient);\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 = await buildAuthObjectFromToken(token, jwksClient);\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.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/middleware.ts
2
2
  import { InAIAuthClient, buildAuthObjectFromToken } from "@inai-dev/backend";
3
- import { isTokenExpired } from "@inai-dev/shared";
3
+ import { isTokenExpired, JWKSClient, DEFAULT_API_URL } from "@inai-dev/shared";
4
4
 
5
5
  // src/helpers.ts
6
6
  import { getCookie, setCookie, deleteCookie } from "hono/cookie";
@@ -90,6 +90,8 @@ function inaiAuthMiddleware(config = {}) {
90
90
  } = config;
91
91
  const client = new InAIAuthClient(authClientConfig);
92
92
  const isPlatform = authMode === "platform";
93
+ const jwksUrl = authClientConfig.jwksUrl ?? `${authClientConfig.apiUrl ?? DEFAULT_API_URL}/.well-known/jwks.json`;
94
+ const jwksClient = new JWKSClient(jwksUrl);
93
95
  const defaultUnauthorized = (c) => c.json({ error: "Unauthorized" }, 401);
94
96
  const handleUnauthorized = onUnauthorized ?? defaultUnauthorized;
95
97
  return async function middleware(c, next) {
@@ -107,7 +109,7 @@ function inaiAuthMiddleware(config = {}) {
107
109
  const tokens = isPlatform ? await client.platformRefresh(refreshToken) : await client.refresh(refreshToken);
108
110
  const { data: user } = isPlatform ? await client.platformGetMe(tokens.access_token) : await client.getMe(tokens.access_token);
109
111
  setAuthCookies(c, tokens, user);
110
- const authObj2 = buildAuthObjectFromToken(tokens.access_token);
112
+ const authObj2 = await buildAuthObjectFromToken(tokens.access_token, jwksClient);
111
113
  c.set("inaiAuth", authObj2);
112
114
  await next();
113
115
  return;
@@ -118,7 +120,7 @@ function inaiAuthMiddleware(config = {}) {
118
120
  }
119
121
  return handleUnauthorized(c);
120
122
  }
121
- const authObj = buildAuthObjectFromToken(token);
123
+ const authObj = await buildAuthObjectFromToken(token, jwksClient);
122
124
  if (!authObj) {
123
125
  return handleUnauthorized(c);
124
126
  }
package/dist/index.js.map CHANGED
@@ -1 +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"]}
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, JWKSClient, DEFAULT_API_URL } 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 jwksUrl = authClientConfig.jwksUrl\n ?? `${authClientConfig.apiUrl ?? DEFAULT_API_URL}/.well-known/jwks.json`;\n const jwksClient = new JWKSClient(jwksUrl);\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 = await buildAuthObjectFromToken(tokens.access_token, jwksClient);\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 = await buildAuthObjectFromToken(token, jwksClient);\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"]}
@@ -110,6 +110,8 @@ function inaiAuthMiddleware(config = {}) {
110
110
  } = config;
111
111
  const client = new import_backend.InAIAuthClient(authClientConfig);
112
112
  const isPlatform = authMode === "platform";
113
+ const jwksUrl = authClientConfig.jwksUrl ?? `${authClientConfig.apiUrl ?? import_shared2.DEFAULT_API_URL}/.well-known/jwks.json`;
114
+ const jwksClient = new import_shared2.JWKSClient(jwksUrl);
113
115
  const defaultUnauthorized = (c) => c.json({ error: "Unauthorized" }, 401);
114
116
  const handleUnauthorized = onUnauthorized ?? defaultUnauthorized;
115
117
  return async function middleware(c, next) {
@@ -127,7 +129,7 @@ function inaiAuthMiddleware(config = {}) {
127
129
  const tokens = isPlatform ? await client.platformRefresh(refreshToken) : await client.refresh(refreshToken);
128
130
  const { data: user } = isPlatform ? await client.platformGetMe(tokens.access_token) : await client.getMe(tokens.access_token);
129
131
  setAuthCookies(c, tokens, user);
130
- const authObj2 = (0, import_backend.buildAuthObjectFromToken)(tokens.access_token);
132
+ const authObj2 = await (0, import_backend.buildAuthObjectFromToken)(tokens.access_token, jwksClient);
131
133
  c.set("inaiAuth", authObj2);
132
134
  await next();
133
135
  return;
@@ -138,7 +140,7 @@ function inaiAuthMiddleware(config = {}) {
138
140
  }
139
141
  return handleUnauthorized(c);
140
142
  }
141
- const authObj = (0, import_backend.buildAuthObjectFromToken)(token);
143
+ const authObj = await (0, import_backend.buildAuthObjectFromToken)(token, jwksClient);
142
144
  if (!authObj) {
143
145
  return handleUnauthorized(c);
144
146
  }
@@ -1 +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"]}
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, JWKSClient, DEFAULT_API_URL } 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 jwksUrl = authClientConfig.jwksUrl\n ?? `${authClientConfig.apiUrl ?? DEFAULT_API_URL}/.well-known/jwks.json`;\n const jwksClient = new JWKSClient(jwksUrl);\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 = await buildAuthObjectFromToken(tokens.access_token, jwksClient);\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 = await buildAuthObjectFromToken(token, jwksClient);\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"]}
@@ -1,6 +1,6 @@
1
1
  // src/middleware.ts
2
2
  import { InAIAuthClient, buildAuthObjectFromToken } from "@inai-dev/backend";
3
- import { isTokenExpired } from "@inai-dev/shared";
3
+ import { isTokenExpired, JWKSClient, DEFAULT_API_URL } from "@inai-dev/shared";
4
4
 
5
5
  // src/helpers.ts
6
6
  import { getCookie, setCookie, deleteCookie } from "hono/cookie";
@@ -90,6 +90,8 @@ function inaiAuthMiddleware(config = {}) {
90
90
  } = config;
91
91
  const client = new InAIAuthClient(authClientConfig);
92
92
  const isPlatform = authMode === "platform";
93
+ const jwksUrl = authClientConfig.jwksUrl ?? `${authClientConfig.apiUrl ?? DEFAULT_API_URL}/.well-known/jwks.json`;
94
+ const jwksClient = new JWKSClient(jwksUrl);
93
95
  const defaultUnauthorized = (c) => c.json({ error: "Unauthorized" }, 401);
94
96
  const handleUnauthorized = onUnauthorized ?? defaultUnauthorized;
95
97
  return async function middleware(c, next) {
@@ -107,7 +109,7 @@ function inaiAuthMiddleware(config = {}) {
107
109
  const tokens = isPlatform ? await client.platformRefresh(refreshToken) : await client.refresh(refreshToken);
108
110
  const { data: user } = isPlatform ? await client.platformGetMe(tokens.access_token) : await client.getMe(tokens.access_token);
109
111
  setAuthCookies(c, tokens, user);
110
- const authObj2 = buildAuthObjectFromToken(tokens.access_token);
112
+ const authObj2 = await buildAuthObjectFromToken(tokens.access_token, jwksClient);
111
113
  c.set("inaiAuth", authObj2);
112
114
  await next();
113
115
  return;
@@ -118,7 +120,7 @@ function inaiAuthMiddleware(config = {}) {
118
120
  }
119
121
  return handleUnauthorized(c);
120
122
  }
121
- const authObj = buildAuthObjectFromToken(token);
123
+ const authObj = await buildAuthObjectFromToken(token, jwksClient);
122
124
  if (!authObj) {
123
125
  return handleUnauthorized(c);
124
126
  }
@@ -1 +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":["authObj"]}
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, JWKSClient, DEFAULT_API_URL } 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 jwksUrl = authClientConfig.jwksUrl\n ?? `${authClientConfig.apiUrl ?? DEFAULT_API_URL}/.well-known/jwks.json`;\n const jwksClient = new JWKSClient(jwksUrl);\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 = await buildAuthObjectFromToken(tokens.access_token, jwksClient);\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 = await buildAuthObjectFromToken(token, jwksClient);\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":["authObj"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inai-dev/hono",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Hono integration for InAI Auth SDK",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -35,9 +35,9 @@
35
35
  "prepublishOnly": "npm run build"
36
36
  },
37
37
  "dependencies": {
38
- "@inai-dev/types": "^1.2.0",
39
- "@inai-dev/shared": "^1.2.0",
40
- "@inai-dev/backend": "^1.3.0"
38
+ "@inai-dev/types": "^1.3.0",
39
+ "@inai-dev/shared": "^1.3.0",
40
+ "@inai-dev/backend": "^1.4.0"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "hono": ">=4.0.0"