@inai-dev/hono 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +313 -0
  2. package/package.json +4 -4
package/README.md ADDED
@@ -0,0 +1,313 @@
1
+ # @inai-dev/hono
2
+
3
+ Full Hono integration for InAI Auth. Includes middleware with automatic token refresh, route protection with RBAC, and API route handlers. Works on Cloudflare Workers, Node.js, Deno, and Bun.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @inai-dev/hono
9
+ ```
10
+
11
+ ## Environment Variables
12
+
13
+ ```env
14
+ # Required — your publishable key
15
+ INAI_PUBLISHABLE_KEY=pk_live_...
16
+ ```
17
+
18
+ > On Cloudflare Workers, set this as a secret: `wrangler secret put INAI_PUBLISHABLE_KEY`
19
+
20
+ ## Setup
21
+
22
+ ### 1. Middleware
23
+
24
+ ```ts
25
+ import { Hono } from "hono";
26
+ import { inaiAuthMiddleware } from "@inai-dev/hono/middleware";
27
+
28
+ const app = new Hono();
29
+
30
+ app.use(
31
+ "*",
32
+ inaiAuthMiddleware({
33
+ publicRoutes: ["/", "/health", "/api/public/*"],
34
+ })
35
+ );
36
+ ```
37
+
38
+ The middleware automatically:
39
+ - Skips public routes (supports glob patterns with `*`)
40
+ - Validates the auth token from `Authorization: Bearer <token>` header or cookies
41
+ - Refreshes expired tokens when a refresh token exists in cookies
42
+ - Sets `c.get("inaiAuth")` with the `AuthObject` for authenticated requests
43
+ - Returns `401 Unauthorized` for unauthenticated requests on protected routes
44
+ - Uses `hono/cookie` for cookie parsing (works across all runtimes)
45
+
46
+ #### Configuration
47
+
48
+ ```ts
49
+ inaiAuthMiddleware({
50
+ // Auth mode: "app" (default) or "platform" (admin panel auth)
51
+ authMode: "app",
52
+
53
+ // Routes that don't require authentication
54
+ publicRoutes: ["/", "/health", "/api/public/*"],
55
+ // Or use a function for dynamic matching
56
+ publicRoutes: (path) => path.startsWith("/public"),
57
+
58
+ // Custom unauthorized handler (default: 401 JSON response)
59
+ onUnauthorized: (c) => c.json({ error: "Please sign in" }, 401),
60
+
61
+ // InAIAuthClient config (optional if using env vars)
62
+ publishableKey: "pk_live_...",
63
+ });
64
+ ```
65
+
66
+ ### 2. Route Protection (RBAC)
67
+
68
+ ```ts
69
+ import { requireAuth } from "@inai-dev/hono/middleware";
70
+
71
+ // Require any authenticated user
72
+ app.get("/api/profile", requireAuth(), (c) => {
73
+ const auth = c.get("inaiAuth");
74
+ return c.json({ userId: auth!.userId });
75
+ });
76
+
77
+ // Require a specific role
78
+ app.get("/api/admin", requireAuth({ role: "admin" }), (c) => {
79
+ return c.json({ message: "Admin area" });
80
+ });
81
+
82
+ // Require a specific permission
83
+ app.post("/api/posts", requireAuth({ permission: "posts:write" }), (c) => {
84
+ return c.json({ message: "Post created" });
85
+ });
86
+ ```
87
+
88
+ `requireAuth()` returns:
89
+ - `401` if no auth or no `userId`
90
+ - `403` if the user lacks the required `role` or `permission`
91
+
92
+ ### 3. API Routes
93
+
94
+ ```ts
95
+ import { createAuthRoutes } from "@inai-dev/hono/api-routes";
96
+
97
+ const authApp = createAuthRoutes({
98
+ publishableKey: "pk_live_...",
99
+ });
100
+
101
+ app.route("/api/auth", authApp);
102
+ ```
103
+
104
+ Handles the following endpoints automatically:
105
+ - `POST /api/auth/login` — User login (returns `{ user }` or `{ mfa_required, mfa_token }`)
106
+ - `POST /api/auth/register` — User registration
107
+ - `POST /api/auth/mfa-challenge` — MFA verification
108
+ - `POST /api/auth/refresh` — Token refresh
109
+ - `POST /api/auth/logout` — User logout
110
+
111
+ ### 4. Auth Helpers
112
+
113
+ #### `getAuth(c)`
114
+
115
+ Returns the `AuthObject` from the context (populated by middleware).
116
+
117
+ ```ts
118
+ import { getAuth } from "@inai-dev/hono";
119
+
120
+ app.get("/api/me", (c) => {
121
+ const auth = getAuth(c);
122
+ if (!auth?.userId) {
123
+ return c.json({ error: "Not signed in" }, 401);
124
+ }
125
+ return c.json({ userId: auth.userId, orgId: auth.orgId });
126
+ });
127
+ ```
128
+
129
+ **`AuthObject`:**
130
+
131
+ | Property | Type | Description |
132
+ |---|---|---|
133
+ | `userId` | `string \| null` | Current user ID |
134
+ | `tenantId` | `string \| null` | Tenant ID |
135
+ | `appId` | `string \| null` | Application ID |
136
+ | `envId` | `string \| null` | Environment ID |
137
+ | `orgId` | `string \| null` | Active organization ID |
138
+ | `orgRole` | `string \| null` | Role in active organization |
139
+ | `sessionId` | `string \| null` | Session ID |
140
+ | `getToken()` | `() => Promise<string \| null>` | Get the access token |
141
+ | `has(params)` | `({ role?, permission? }) => boolean` | Check role or permission |
142
+
143
+ #### Cookie Helpers
144
+
145
+ For advanced use cases (custom auth flows, manual token management):
146
+
147
+ ```ts
148
+ import { setAuthCookies, clearAuthCookies } from "@inai-dev/hono";
149
+
150
+ // Set auth cookies after manual authentication
151
+ setAuthCookies(c, tokens, user);
152
+
153
+ // Clear all auth cookies (manual logout)
154
+ clearAuthCookies(c);
155
+ ```
156
+
157
+ #### Token Extraction
158
+
159
+ ```ts
160
+ import { getTokenFromContext, getRefreshTokenFromContext } from "@inai-dev/hono";
161
+
162
+ // Get access token from Authorization header or cookies
163
+ const token = getTokenFromContext(c);
164
+
165
+ // Get refresh token from cookies
166
+ const refreshToken = getRefreshTokenFromContext(c);
167
+ ```
168
+
169
+ ## Full Example
170
+
171
+ ```ts
172
+ import { Hono } from "hono";
173
+ import {
174
+ inaiAuthMiddleware,
175
+ requireAuth,
176
+ createAuthRoutes,
177
+ getAuth,
178
+ } from "@inai-dev/hono";
179
+
180
+ const app = new Hono();
181
+
182
+ // Auth middleware — protects all routes except public ones
183
+ app.use(
184
+ "*",
185
+ inaiAuthMiddleware({
186
+ publicRoutes: ["/", "/health", "/api/auth/*"],
187
+ })
188
+ );
189
+
190
+ // Auth API routes
191
+ app.route("/api/auth", createAuthRoutes());
192
+
193
+ // Public route
194
+ app.get("/health", (c) => c.json({ status: "ok" }));
195
+
196
+ // Protected route — any authenticated user
197
+ app.get("/api/profile", (c) => {
198
+ const auth = getAuth(c);
199
+ return c.json({ userId: auth?.userId });
200
+ });
201
+
202
+ // Protected route — admin only
203
+ app.get("/api/admin", requireAuth({ role: "admin" }), (c) => {
204
+ return c.json({ message: "Welcome, admin" });
205
+ });
206
+
207
+ export default app;
208
+ ```
209
+
210
+ ### Cloudflare Workers
211
+
212
+ ```ts
213
+ // src/index.ts
214
+ import { Hono } from "hono";
215
+ import { inaiAuthMiddleware, createAuthRoutes } from "@inai-dev/hono";
216
+
217
+ const app = new Hono();
218
+
219
+ app.use(
220
+ "*",
221
+ inaiAuthMiddleware({
222
+ publicRoutes: ["/", "/api/auth/*"],
223
+ publishableKey: "pk_live_...",
224
+ })
225
+ );
226
+
227
+ app.route("/api/auth", createAuthRoutes());
228
+
229
+ app.get("/api/hello", (c) => {
230
+ const auth = c.get("inaiAuth");
231
+ return c.json({ userId: auth?.userId });
232
+ });
233
+
234
+ export default app;
235
+ ```
236
+
237
+ ## Platform Mode (Admin Panel)
238
+
239
+ For admin panels that authenticate against the InAI platform API:
240
+
241
+ ```ts
242
+ app.use(
243
+ "*",
244
+ inaiAuthMiddleware({
245
+ authMode: "platform",
246
+ publicRoutes: ["/login"],
247
+ })
248
+ );
249
+ ```
250
+
251
+ In platform mode, the middleware uses `platformRefresh()` and `platformGetMe()` for token refresh, targeting the platform auth endpoints instead of app user endpoints.
252
+
253
+ ## Type Augmentation
254
+
255
+ The package augments Hono's `ContextVariableMap` so `c.get("inaiAuth")` is fully typed:
256
+
257
+ ```ts
258
+ // Automatic — just import the package
259
+ import "@inai-dev/hono";
260
+
261
+ // c.get("inaiAuth") is typed as AuthObject | null
262
+ ```
263
+
264
+ ## Exports Reference
265
+
266
+ ### `@inai-dev/hono`
267
+
268
+ | Export | Kind | Description |
269
+ |---|---|---|
270
+ | `inaiAuthMiddleware` | Function | Auth middleware |
271
+ | `requireAuth` | Function | RBAC route guard |
272
+ | `createAuthRoutes` | Function | Auth API route handlers |
273
+ | `getAuth` | Function | Get `AuthObject` from context |
274
+ | `setAuthCookies` | Function | Set auth cookies |
275
+ | `clearAuthCookies` | Function | Clear auth cookies |
276
+ | `getTokenFromContext` | Function | Extract access token |
277
+ | `getRefreshTokenFromContext` | Function | Extract refresh token |
278
+
279
+ ### `@inai-dev/hono/middleware`
280
+
281
+ | Export | Kind | Description |
282
+ |---|---|---|
283
+ | `inaiAuthMiddleware` | Function | Auth middleware with token refresh |
284
+ | `requireAuth` | Function | RBAC route guard |
285
+
286
+ ### `@inai-dev/hono/api-routes`
287
+
288
+ | Export | Kind | Description |
289
+ |---|---|---|
290
+ | `createAuthRoutes` | Function | Create Hono sub-app with auth endpoints |
291
+
292
+ ## Exported Types
293
+
294
+ ```ts
295
+ import type {
296
+ InAIHonoMiddlewareConfig,
297
+ RequireAuthConfig,
298
+ } from "@inai-dev/hono";
299
+
300
+ import type {
301
+ AuthObject,
302
+ UserResource,
303
+ OrganizationResource,
304
+ } from "@inai-dev/hono";
305
+ ```
306
+
307
+ ## Questions & Support
308
+
309
+ Visit [https://inai.dev](https://inai.dev) for documentation, guides, and support.
310
+
311
+ ## License
312
+
313
+ [MIT](../../LICENSE)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inai-dev/hono",
3
- "version": "1.0.0",
3
+ "version": "1.1.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.1.0",
39
- "@inai-dev/shared": "^1.1.0",
40
- "@inai-dev/backend": "^1.2.0"
38
+ "@inai-dev/types": "^1.2.0",
39
+ "@inai-dev/shared": "^1.2.0",
40
+ "@inai-dev/backend": "^1.3.0"
41
41
  },
42
42
  "peerDependencies": {
43
43
  "hono": ">=4.0.0"