@drmhse/authos-node 0.1.3 → 0.1.5
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 +72 -0
- package/dist/express.d.mts +2 -0
- package/dist/express.d.ts +2 -0
- package/dist/express.js +64 -1
- package/dist/express.mjs +64 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -192,6 +192,78 @@ app.get('/org/:slug/data',
|
|
|
192
192
|
);
|
|
193
193
|
```
|
|
194
194
|
|
|
195
|
+
### requireService(slug, options?)
|
|
196
|
+
|
|
197
|
+
Requires the user's JWT to have a matching service claim. Use this for service-scoped endpoints.
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
app.get('/services/:slug/data',
|
|
201
|
+
requireAuth(),
|
|
202
|
+
requireService((req) => req.params.slug),
|
|
203
|
+
(req, res) => { ... }
|
|
204
|
+
);
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### requireTenant(orgSlug, serviceSlug, options?)
|
|
208
|
+
|
|
209
|
+
Requires the user to belong to a specific org AND service. Provides complete tenant isolation.
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
app.get('/orgs/:org/services/:service/data',
|
|
213
|
+
requireAuth(),
|
|
214
|
+
requireTenant(
|
|
215
|
+
(req) => req.params.org,
|
|
216
|
+
(req) => req.params.service
|
|
217
|
+
),
|
|
218
|
+
(req, res) => { ... }
|
|
219
|
+
);
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
## Understanding JWT Context
|
|
223
|
+
|
|
224
|
+
The middleware functions check claims embedded in the JWT by the client SDK during login:
|
|
225
|
+
|
|
226
|
+
| SDK Initialization | JWT Claims | Middleware to Use |
|
|
227
|
+
|-------------------|-----------|------------------|
|
|
228
|
+
| Platform-level (`baseURL` only) | `is_platform_owner: true` | `requirePlatformOwner()` |
|
|
229
|
+
| Org-level (`baseURL` + `org`) | `org: 'slug'` | `requireOrganization()` |
|
|
230
|
+
| Service-level (`baseURL` + `org` + `service`) | `org: 'slug'`, `service: 'app'` | `requireTenant()` or `requireService()` |
|
|
231
|
+
| With permissions | `permissions: ['users:write', ...]` | `requirePermission()` |
|
|
232
|
+
|
|
233
|
+
### How It Works
|
|
234
|
+
|
|
235
|
+
1. **Client-side**: User logs in via `@drmhse/sso-sdk` or `@drmhse/authos-react`
|
|
236
|
+
2. **JWT issued**: AuthOS embeds context (`org`, `service`, `is_platform_owner`) in claims
|
|
237
|
+
3. **Server-side**: This package verifies the JWT and middleware checks the claims
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
// Example: Route for tenant-specific data
|
|
241
|
+
app.get('/orgs/:org/services/:service/data',
|
|
242
|
+
requireAuth(), // 1. Verify JWT signature
|
|
243
|
+
requireTenant( // 2. Check org + service claims
|
|
244
|
+
(req) => req.params.org,
|
|
245
|
+
(req) => req.params.service
|
|
246
|
+
),
|
|
247
|
+
(req, res) => {
|
|
248
|
+
// User is authenticated AND belongs to this org+service
|
|
249
|
+
res.json({
|
|
250
|
+
org: req.auth?.claims.org,
|
|
251
|
+
service: req.auth?.claims.service
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
// Example: Route for platform owners only
|
|
257
|
+
app.get('/platform/analytics',
|
|
258
|
+
requireAuth(), // 1. Verify JWT signature
|
|
259
|
+
requirePlatformOwner(), // 2. Check is_platform_owner: true
|
|
260
|
+
(req, res) => {
|
|
261
|
+
// User is a platform owner
|
|
262
|
+
res.json({ data: '...' });
|
|
263
|
+
}
|
|
264
|
+
);
|
|
265
|
+
```
|
|
266
|
+
|
|
195
267
|
## Webhook Verification
|
|
196
268
|
|
|
197
269
|
Verify webhooks from AuthOS:
|
package/dist/express.d.mts
CHANGED
|
@@ -19,6 +19,8 @@ declare function createAuthMiddleware(options: AuthOSNodeOptions): {
|
|
|
19
19
|
requireAllPermissions: (permissions: string[], permOptions?: RequirePermissionOptions) => RequestHandler;
|
|
20
20
|
requirePlatformOwner: (permOptions?: RequirePermissionOptions) => RequestHandler;
|
|
21
21
|
requireOrganization: (getOrgSlug: string | ((req: Request) => string), permOptions?: RequirePermissionOptions) => RequestHandler;
|
|
22
|
+
requireService: (getServiceSlug: string | ((req: Request) => string), permOptions?: RequirePermissionOptions) => RequestHandler;
|
|
23
|
+
requireTenant: (getOrgSlug: string | ((req: Request) => string), getServiceSlug: string | ((req: Request) => string), permOptions?: RequirePermissionOptions) => RequestHandler;
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
export { createAuthMiddleware };
|
package/dist/express.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ declare function createAuthMiddleware(options: AuthOSNodeOptions): {
|
|
|
19
19
|
requireAllPermissions: (permissions: string[], permOptions?: RequirePermissionOptions) => RequestHandler;
|
|
20
20
|
requirePlatformOwner: (permOptions?: RequirePermissionOptions) => RequestHandler;
|
|
21
21
|
requireOrganization: (getOrgSlug: string | ((req: Request) => string), permOptions?: RequirePermissionOptions) => RequestHandler;
|
|
22
|
+
requireService: (getServiceSlug: string | ((req: Request) => string), permOptions?: RequirePermissionOptions) => RequestHandler;
|
|
23
|
+
requireTenant: (getOrgSlug: string | ((req: Request) => string), getServiceSlug: string | ((req: Request) => string), permOptions?: RequirePermissionOptions) => RequestHandler;
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
export { createAuthMiddleware };
|
package/dist/express.js
CHANGED
|
@@ -382,13 +382,76 @@ function createAuthMiddleware(options) {
|
|
|
382
382
|
next();
|
|
383
383
|
};
|
|
384
384
|
}
|
|
385
|
+
function requireService(getServiceSlug, permOptions = {}) {
|
|
386
|
+
const { message = "Service access required" } = permOptions;
|
|
387
|
+
return (req, res, next) => {
|
|
388
|
+
if (!req.auth) {
|
|
389
|
+
res.status(401).json({
|
|
390
|
+
error: "Unauthorized",
|
|
391
|
+
message: "Authentication required",
|
|
392
|
+
code: "NOT_AUTHENTICATED"
|
|
393
|
+
});
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
const requiredService = typeof getServiceSlug === "function" ? getServiceSlug(req) : getServiceSlug;
|
|
397
|
+
const userService = req.auth.claims.service;
|
|
398
|
+
if (!userService || userService !== requiredService) {
|
|
399
|
+
res.status(403).json({
|
|
400
|
+
error: "Forbidden",
|
|
401
|
+
message,
|
|
402
|
+
code: "WRONG_SERVICE",
|
|
403
|
+
required: requiredService
|
|
404
|
+
});
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
next();
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
function requireTenant(getOrgSlug, getServiceSlug, permOptions = {}) {
|
|
411
|
+
const { message = "Tenant access required" } = permOptions;
|
|
412
|
+
return (req, res, next) => {
|
|
413
|
+
if (!req.auth) {
|
|
414
|
+
res.status(401).json({
|
|
415
|
+
error: "Unauthorized",
|
|
416
|
+
message: "Authentication required",
|
|
417
|
+
code: "NOT_AUTHENTICATED"
|
|
418
|
+
});
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
const requiredOrg = typeof getOrgSlug === "function" ? getOrgSlug(req) : getOrgSlug;
|
|
422
|
+
const requiredService = typeof getServiceSlug === "function" ? getServiceSlug(req) : getServiceSlug;
|
|
423
|
+
const userOrg = req.auth.claims.org;
|
|
424
|
+
const userService = req.auth.claims.service;
|
|
425
|
+
if (!userOrg || userOrg !== requiredOrg) {
|
|
426
|
+
res.status(403).json({
|
|
427
|
+
error: "Forbidden",
|
|
428
|
+
message,
|
|
429
|
+
code: "WRONG_ORGANIZATION",
|
|
430
|
+
required: { org: requiredOrg, service: requiredService }
|
|
431
|
+
});
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
if (!userService || userService !== requiredService) {
|
|
435
|
+
res.status(403).json({
|
|
436
|
+
error: "Forbidden",
|
|
437
|
+
message,
|
|
438
|
+
code: "WRONG_SERVICE",
|
|
439
|
+
required: { org: requiredOrg, service: requiredService }
|
|
440
|
+
});
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
next();
|
|
444
|
+
};
|
|
445
|
+
}
|
|
385
446
|
return {
|
|
386
447
|
requireAuth,
|
|
387
448
|
requirePermission,
|
|
388
449
|
requireAnyPermission,
|
|
389
450
|
requireAllPermissions,
|
|
390
451
|
requirePlatformOwner,
|
|
391
|
-
requireOrganization
|
|
452
|
+
requireOrganization,
|
|
453
|
+
requireService,
|
|
454
|
+
requireTenant
|
|
392
455
|
};
|
|
393
456
|
}
|
|
394
457
|
|
package/dist/express.mjs
CHANGED
|
@@ -360,13 +360,76 @@ function createAuthMiddleware(options) {
|
|
|
360
360
|
next();
|
|
361
361
|
};
|
|
362
362
|
}
|
|
363
|
+
function requireService(getServiceSlug, permOptions = {}) {
|
|
364
|
+
const { message = "Service access required" } = permOptions;
|
|
365
|
+
return (req, res, next) => {
|
|
366
|
+
if (!req.auth) {
|
|
367
|
+
res.status(401).json({
|
|
368
|
+
error: "Unauthorized",
|
|
369
|
+
message: "Authentication required",
|
|
370
|
+
code: "NOT_AUTHENTICATED"
|
|
371
|
+
});
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
const requiredService = typeof getServiceSlug === "function" ? getServiceSlug(req) : getServiceSlug;
|
|
375
|
+
const userService = req.auth.claims.service;
|
|
376
|
+
if (!userService || userService !== requiredService) {
|
|
377
|
+
res.status(403).json({
|
|
378
|
+
error: "Forbidden",
|
|
379
|
+
message,
|
|
380
|
+
code: "WRONG_SERVICE",
|
|
381
|
+
required: requiredService
|
|
382
|
+
});
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
next();
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
function requireTenant(getOrgSlug, getServiceSlug, permOptions = {}) {
|
|
389
|
+
const { message = "Tenant access required" } = permOptions;
|
|
390
|
+
return (req, res, next) => {
|
|
391
|
+
if (!req.auth) {
|
|
392
|
+
res.status(401).json({
|
|
393
|
+
error: "Unauthorized",
|
|
394
|
+
message: "Authentication required",
|
|
395
|
+
code: "NOT_AUTHENTICATED"
|
|
396
|
+
});
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
const requiredOrg = typeof getOrgSlug === "function" ? getOrgSlug(req) : getOrgSlug;
|
|
400
|
+
const requiredService = typeof getServiceSlug === "function" ? getServiceSlug(req) : getServiceSlug;
|
|
401
|
+
const userOrg = req.auth.claims.org;
|
|
402
|
+
const userService = req.auth.claims.service;
|
|
403
|
+
if (!userOrg || userOrg !== requiredOrg) {
|
|
404
|
+
res.status(403).json({
|
|
405
|
+
error: "Forbidden",
|
|
406
|
+
message,
|
|
407
|
+
code: "WRONG_ORGANIZATION",
|
|
408
|
+
required: { org: requiredOrg, service: requiredService }
|
|
409
|
+
});
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
if (!userService || userService !== requiredService) {
|
|
413
|
+
res.status(403).json({
|
|
414
|
+
error: "Forbidden",
|
|
415
|
+
message,
|
|
416
|
+
code: "WRONG_SERVICE",
|
|
417
|
+
required: { org: requiredOrg, service: requiredService }
|
|
418
|
+
});
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
next();
|
|
422
|
+
};
|
|
423
|
+
}
|
|
363
424
|
return {
|
|
364
425
|
requireAuth,
|
|
365
426
|
requirePermission,
|
|
366
427
|
requireAnyPermission,
|
|
367
428
|
requireAllPermissions,
|
|
368
429
|
requirePlatformOwner,
|
|
369
|
-
requireOrganization
|
|
430
|
+
requireOrganization,
|
|
431
|
+
requireService,
|
|
432
|
+
requireTenant
|
|
370
433
|
};
|
|
371
434
|
}
|
|
372
435
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@drmhse/authos-node",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Node.js server adapter for AuthOS authentication - Express middleware and token verification",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -58,7 +58,7 @@
|
|
|
58
58
|
}
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
|
-
"@drmhse/sso-sdk": "^0.3.
|
|
61
|
+
"@drmhse/sso-sdk": "^0.3.10"
|
|
62
62
|
},
|
|
63
63
|
"devDependencies": {
|
|
64
64
|
"@types/express": "^5.0.0",
|