@drmhse/authos-node
v0.1.6
Published
Node.js server adapter for AuthOS authentication - Express middleware and token verification
Downloads
94
Maintainers
Readme
@drmhse/authos-node
Node.js server adapter for AuthOS - the multi-tenant authentication platform. Provides JWT verification, webhook signature validation, and Express middleware.
Installation
npm install @drmhse/authos-nodeFor Express middleware:
npm install @drmhse/authos-node expressQuick Start
JWT Token Verification
Verify JWT tokens issued by AuthOS:
import { createTokenVerifier } from '@drmhse/authos-node';
const verifier = createTokenVerifier({
baseURL: 'https://sso.example.com'
});
// Verify a token
const verified = await verifier.verifyToken(token);
console.log(verified.claims);
// {
// sub: 'user_123',
// email: '[email protected]',
// is_platform_owner: false,
// org: 'acme-corp',
// permissions: ['users:read', 'users:write']
// }TypeScript Integration
The req.auth type is automatically augmented when you import from @drmhse/authos-node/express. No manual setup required!
import { createAuthMiddleware } from '@drmhse/authos-node/express';
// TypeScript knows about req.auth automatically
app.get('/profile', requireAuth(), (req, res) => {
const userId = req.auth?.claims.sub; // ✓ Typed correctly
res.json({ userId });
});If you need access to the token claims type directly:
import { TokenClaims, VerifiedToken } from '@drmhse/authos-node';
function processUser(auth: VerifiedToken) {
console.log(auth.claims.email);
}Express Middleware
Protect your Express routes with AuthOS authentication:
import { createAuthMiddleware } from '@drmhse/authos-node/express';
import express from 'express';
const app = express();
const { requireAuth, requirePermission } = createAuthMiddleware({
baseURL: process.env.AUTHOS_URL!
});
// Public route
app.get('/', (req, res) => {
res.json({ message: 'Hello world' });
});
// Protected route - requires valid JWT
app.get('/profile', requireAuth(), (req, res) => {
// req.auth contains verified token info
res.json({ user: req.auth?.claims });
});
// Protected route - requires specific permission
app.delete('/users/:id',
requireAuth(),
requirePermission('users:delete'),
(req, res) => {
res.json({ message: 'User deleted' });
}
);
app.listen(3000);The middleware looks for a Bearer token in the Authorization header:
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...Middleware Reference
requireAuth(options?)
Requires a valid JWT token. Adds req.auth with verified token info.
app.get('/protected', requireAuth(), (req, res) => {
const userId = req.auth?.claims.sub;
res.json({ userId });
});Options:
| Option | Type | Description |
|--------|------|-------------|
| getToken | (req) => string | Custom token extractor |
requirePermission(permission, options?)
Requires the user to have a specific permission.
app.post('/admin/users',
requireAuth(),
requirePermission('users:create'),
(req, res) => { ... }
);Options:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| message | string | "Insufficient permissions" | Custom error message |
requireAnyPermission(permissions, options?)
Requires the user to have at least one of the specified permissions.
app.get('/reports',
requireAuth(),
requireAnyPermission(['reports:read', 'reports:admin']),
(req, res) => { ... }
);requireAllPermissions(permissions, options?)
Requires the user to have all of the specified permissions.
app.post('/admin/settings',
requireAuth(),
requireAllPermissions(['admin:access', 'settings:write']),
(req, res) => { ... }
);requirePlatformOwner(options?)
Requires the user to be a platform owner.
app.get('/platform/settings',
requireAuth(),
requirePlatformOwner(),
(req, res) => { ... }
);requireOrganization(slug, options?)
Requires the user to belong to a specific organization.
app.get('/org/:slug/data',
requireAuth(),
requireOrganization((req) => req.params.slug),
(req, res) => { ... }
);requireService(slug, options?)
Requires the user's JWT to have a matching service claim. Use this for service-scoped endpoints.
app.get('/services/:slug/data',
requireAuth(),
requireService((req) => req.params.slug),
(req, res) => { ... }
);requireTenant(orgSlug, serviceSlug, options?)
Requires the user to belong to a specific org AND service. Provides complete tenant isolation.
app.get('/orgs/:org/services/:service/data',
requireAuth(),
requireTenant(
(req) => req.params.org,
(req) => req.params.service
),
(req, res) => { ... }
);Understanding JWT Context
The middleware functions check claims embedded in the JWT by the client SDK during login:
| SDK Initialization | JWT Claims | Middleware to Use |
|-------------------|-----------|------------------|
| Platform-level (baseURL only) | is_platform_owner: true | requirePlatformOwner() |
| Org-level (baseURL + org) | org: 'slug' | requireOrganization() |
| Service-level (baseURL + org + service) | org: 'slug', service: 'app' | requireTenant() or requireService() |
| With permissions | permissions: ['users:write', ...] | requirePermission() |
How It Works
- Client-side: User logs in via
@drmhse/sso-sdkor@drmhse/authos-react - JWT issued: AuthOS embeds context (
org,service,is_platform_owner) in claims - Server-side: This package verifies the JWT and middleware checks the claims
// Example: Route for tenant-specific data
app.get('/orgs/:org/services/:service/data',
requireAuth(), // 1. Verify JWT signature
requireTenant( // 2. Check org + service claims
(req) => req.params.org,
(req) => req.params.service
),
(req, res) => {
// User is authenticated AND belongs to this org+service
res.json({
org: req.auth?.claims.org,
service: req.auth?.claims.service
});
}
);
// Example: Route for platform owners only
app.get('/platform/analytics',
requireAuth(), // 1. Verify JWT signature
requirePlatformOwner(), // 2. Check is_platform_owner: true
(req, res) => {
// User is a platform owner
res.json({ data: '...' });
}
);Webhook Verification
Verify webhooks from AuthOS:
import { verifyWebhookSignature } from '@drmhse/authos-node';
app.post('/webhooks/authos', (req, res) => {
const signature = req.headers['x-authos-signature'];
const payload = JSON.stringify(req.body);
try {
const isValid = verifyWebhookSignature(payload, signature, {
secret: process.env.WEBHOOK_SECRET!
});
if (!isValid) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process webhook
res.json({ received: true });
} catch (err) {
res.status(400).json({ error: 'Webhook verification failed' });
}
});Creating Webhook Signatures
If you need to verify webhooks from your own services:
import { createWebhookSignature } from '@drmhse/authos-node';
const payload = JSON.stringify({ event: 'user.created' });
const signature = createWebhookSignature(payload, 'your_secret');API Reference
createTokenVerifier(options)
Creates a JWT token verifier that fetches JWKS from AuthOS.
import { createTokenVerifier, clearJWKSCache } from '@drmhse/authos-node';
const verifier = createTokenVerifier({
baseURL: 'https://sso.example.com',
// Optional: cache time in seconds
cacheTimeSeconds: 300
});
const verified = await verifier.verifyToken(token);
// Clear cache to force JWKS refresh
clearJWKSCache();Returns:
verifyToken(token)- Verifies a JWT and returns claims- Claims include:
sub,email,is_platform_owner,org,permissions
Error Codes
| Code | Description |
|------|-------------|
| MISSING_TOKEN | No Bearer token provided |
| INVALID_TOKEN | Token is malformed or expired |
| NOT_AUTHENTICATED | No auth info on request |
| PERMISSION_DENIED | User lacks required permission |
| NOT_PLATFORM_OWNER | User is not a platform owner |
| WRONG_ORGANIZATION | User is not in required organization |
License
MIT © DRM HSE
