transit-kit 0.4.0 → 0.4.2
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 +125 -0
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.js +2 -1
- package/dist/server/middleware/auth.js +4 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -158,6 +158,131 @@ server.registerApiEndpoint(createUserEndpoint);
|
|
|
158
158
|
server.start();
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
+
## Authentication
|
|
162
|
+
|
|
163
|
+
Transit-kit includes a simple, composable authentication mechanism based on `Authorization` headers. You declare one or more `SecurityScheme`s on an endpoint, and the framework will:
|
|
164
|
+
|
|
165
|
+
- Apply an authentication middleware for that endpoint
|
|
166
|
+
- Try all declared schemes in order and pick the first successful one
|
|
167
|
+
- Return `401 Unauthorized` automatically when authentication fails
|
|
168
|
+
- Inject the authenticated `caller` into your endpoint handler
|
|
169
|
+
|
|
170
|
+
### Basic Auth
|
|
171
|
+
|
|
172
|
+
Supports `Authorization: Basic <base64(username:password)>`.
|
|
173
|
+
|
|
174
|
+
```typescript
|
|
175
|
+
import {
|
|
176
|
+
createApiEndpointHandler,
|
|
177
|
+
createServer,
|
|
178
|
+
} from "transit-kit/server";
|
|
179
|
+
import { createBasicAuthSchema } from "transit-kit/server/security/basicAuth";
|
|
180
|
+
import z from "zod";
|
|
181
|
+
|
|
182
|
+
// Define the shape of the authenticated caller
|
|
183
|
+
type Caller = { id: string; role: "admin" | "user" };
|
|
184
|
+
|
|
185
|
+
// Your validation logic (DB lookup, etc.)
|
|
186
|
+
const basicAuth = createBasicAuthSchema<Caller>(
|
|
187
|
+
"basic",
|
|
188
|
+
async (username, password) => {
|
|
189
|
+
const user = await findUserByUsername(username);
|
|
190
|
+
if (!user) return null;
|
|
191
|
+
const ok = await verifyPassword(password, user.passwordHash);
|
|
192
|
+
return ok ? { id: user.id, role: user.role } : null;
|
|
193
|
+
},
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
const getProfile = createApiEndpointHandler(
|
|
197
|
+
{
|
|
198
|
+
meta: { name: "Get Profile", description: "Returns caller profile", group: "Auth" },
|
|
199
|
+
method: "get",
|
|
200
|
+
path: "/me",
|
|
201
|
+
responseSchemas: {
|
|
202
|
+
200: {
|
|
203
|
+
dataType: "application/json",
|
|
204
|
+
dataSchema: z.object({ id: z.string(), role: z.enum(["admin", "user"]) }),
|
|
205
|
+
},
|
|
206
|
+
401: {},
|
|
207
|
+
},
|
|
208
|
+
// Enable authentication for this endpoint
|
|
209
|
+
securitySchemes: [basicAuth],
|
|
210
|
+
},
|
|
211
|
+
async (_req, { caller }) => {
|
|
212
|
+
// `caller` is typed from your security scheme
|
|
213
|
+
return { code: 200, dataType: "application/json", json: caller };
|
|
214
|
+
},
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
const server = createServer({ port: 3000, inDevMode: true, logger: true });
|
|
218
|
+
server.registerApiEndpoint(getProfile);
|
|
219
|
+
server.start();
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Bearer Token Auth
|
|
223
|
+
|
|
224
|
+
Supports `Authorization: Bearer <token>`.
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
import { createBearerAuthSchema } from "transit-kit/server/security/bearerAuth";
|
|
228
|
+
|
|
229
|
+
type Caller = { id: string; scopes: string[] };
|
|
230
|
+
|
|
231
|
+
const bearerAuth = createBearerAuthSchema<Caller>(
|
|
232
|
+
"bearer",
|
|
233
|
+
async (token) => {
|
|
234
|
+
const payload = await verifyJwt(token); // or call your token introspection service
|
|
235
|
+
return payload ? { id: payload.sub, scopes: payload.scopes } : null;
|
|
236
|
+
},
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
const getSecret = createApiEndpointHandler(
|
|
240
|
+
{
|
|
241
|
+
meta: { name: "Get Secret", description: "Protected resource", group: "Auth" },
|
|
242
|
+
method: "get",
|
|
243
|
+
path: "/secret",
|
|
244
|
+
responseSchemas: {
|
|
245
|
+
200: { dataType: "application/json", dataSchema: z.object({ secret: z.string() }) },
|
|
246
|
+
401: {},
|
|
247
|
+
},
|
|
248
|
+
securitySchemes: [bearerAuth],
|
|
249
|
+
},
|
|
250
|
+
async (_req, { caller }) => {
|
|
251
|
+
// Use `caller.scopes` for authorization decisions
|
|
252
|
+
return { code: 200, dataType: "application/json", json: { secret: "shh" } };
|
|
253
|
+
},
|
|
254
|
+
);
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Multiple Schemes per Endpoint
|
|
258
|
+
|
|
259
|
+
You can allow multiple authentication methods on the same endpoint. The framework tries them in the order you specify and picks the first successful scheme.
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
const endpoint = createApiEndpointHandler(
|
|
263
|
+
{
|
|
264
|
+
meta: { name: "Hybrid Auth", description: "Basic or Bearer", group: "Auth" },
|
|
265
|
+
method: "get",
|
|
266
|
+
path: "/hybrid",
|
|
267
|
+
responseSchemas: { 200: { dataType: "application/json", dataSchema: z.object({ ok: z.boolean() }) }, 401: {} },
|
|
268
|
+
securitySchemes: [basicAuth, bearerAuth],
|
|
269
|
+
},
|
|
270
|
+
async (_req, { caller }) => {
|
|
271
|
+
// `caller` resolves from whichever scheme authenticated successfully
|
|
272
|
+
return { code: 200, dataType: "application/json", json: { ok: true } };
|
|
273
|
+
},
|
|
274
|
+
);
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
### How It Works
|
|
278
|
+
|
|
279
|
+
- Authentication middleware is built automatically per-endpoint when `securitySchemes` are present.
|
|
280
|
+
- Internals use `authenticate()` from [src/server/security/SecuritySchema.ts](src/server/security/SecuritySchema.ts) to try each scheme.
|
|
281
|
+
- Basic auth reads and decodes the header in [src/server/security/basicAuth.ts](src/server/security/basicAuth.ts).
|
|
282
|
+
- Bearer auth reads the header in [src/server/security/bearerAuth.ts](src/server/security/bearerAuth.ts).
|
|
283
|
+
- On success, the authenticated `caller` is stored and passed to your handler as `extractedRequestData.caller`.
|
|
284
|
+
- On failure, the framework responds with `401` and a JSON `{ message: "Unauthorized" }` from [src/server/middleware/auth.ts](src/server/middleware/auth.ts).
|
|
285
|
+
|
|
161
286
|
## Response Types
|
|
162
287
|
|
|
163
288
|
### JSON Response
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { createApiEndpointHandler } from "./handlers/api/createApiHandler";
|
|
2
|
-
export {
|
|
2
|
+
export { createBasicAuthSchema } from "./security/basicAuth";
|
|
3
|
+
export { createBearerAuthSchema } from "./security/bearerAuth";
|
|
3
4
|
export { createServer, type Server, type ServerConfig } from "./server";
|
|
4
5
|
declare const _default: {};
|
|
5
6
|
export default _default;
|
package/dist/server/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { createApiEndpointHandler } from "./handlers/api/createApiHandler";
|
|
2
|
-
export {
|
|
2
|
+
export { createBasicAuthSchema } from "./security/basicAuth";
|
|
3
|
+
export { createBearerAuthSchema } from "./security/bearerAuth";
|
|
3
4
|
export { createServer } from "./server";
|
|
4
5
|
export default {};
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import expressAsyncHandler from "express-async-handler";
|
|
2
|
+
import { HttpStatusCodes } from "../constants/HttpStatusCodes";
|
|
2
3
|
import { authenticate } from "../security/SecuritySchema";
|
|
3
4
|
export function buildAuthenticationMiddleware(schemes) {
|
|
4
5
|
return expressAsyncHandler(async (request, response, next) => {
|
|
5
6
|
const caller = await authenticate(schemes, request);
|
|
6
7
|
if (caller == null) {
|
|
7
|
-
response
|
|
8
|
+
response
|
|
9
|
+
.status(HttpStatusCodes.Unauthorized_401)
|
|
10
|
+
.json({ message: "Unauthorized" });
|
|
8
11
|
return;
|
|
9
12
|
}
|
|
10
13
|
response.locals.caller = caller;
|