@auth-craft/backend-sdk
v0.7.4
Published
Type-safe internal service SDK for Auth-Craft service-to-service calls
Readme
@auth-craft/backend-sdk
⚠️ Experimental / Internal Use
This package is published for convenience only.
- No stability guarantee
- Breaking changes may happen at any time
- No support
Use at your own risk.
Type-safe internal service SDK for Auth-Craft service-to-service calls. Uses Web Crypto API for edge compatibility — zero external dependencies (except ts-micro-result).
Installation
npm install @auth-craft/backend-sdkQuick Start
import { createInternalClient } from '@auth-craft/backend-sdk';
const client = createInternalClient({
baseUrl: 'https://auth.example.com',
basePath: '/system',
jwt: {
strategy: 'eddsa',
privateKey: process.env.INTERNAL_JWT_PRIVATE_KEY!, // hex string (64 chars = 32 bytes)
issuer: 'tenant-provisioning-service',
},
});
const result = await client.bootstrapTenantOwner({
tenantId: 'tenant-abc',
userId: 'user-123',
});
if (result.isOkWithData()) {
console.log(result.data);
// { message: '...', tenantId: 'tenant-abc', userId: 'user-123', role: 'owner' }
}API
createInternalClient(config)
Creates an InternalClient instance.
Parameters:
| Field | Type | Default | Description |
|---|---|---|---|
| baseUrl | string | — | Base URL of the auth service |
| basePath | string | '' | Path prefix before /internal (e.g., '/system' → /system/internal/*) |
| jwt | JwtConfig | — | Service JWT signing configuration |
| fetchImpl | typeof fetch | globalThis.fetch | Custom fetch implementation |
| timeout | number | 30000 | Request timeout in milliseconds |
| headers | Record<string, string> | {} | Custom headers for all requests |
Returns: InternalClient
JWT Signing Strategies
The SDK supports four JWT signing strategies via Web Crypto API:
// EdDSA / Ed25519 (recommended — compact, fast, edge-native)
jwt: { strategy: 'eddsa', privateKey: '...' } // hex string (64 chars) or Uint8Array (32 bytes)
// HMAC-SHA256 (symmetric — simple for same-service)
jwt: { strategy: 'hmac', secret: '...' }
// RS256 / RSA-SHA256 (asymmetric — enterprise standard)
jwt: { strategy: 'rs256', privateKey: '...' } // PEM string or JsonWebKey
// ES256 / ECDSA P-256 (asymmetric — compact, widely supported)
jwt: { strategy: 'es256', privateKey: '...' } // PEM string or JsonWebKeyCommon JWT options:
| Field | Type | Default | Description |
|---|---|---|---|
| issuer | string | — | JWT iss claim |
| audience | string | — | JWT aud claim |
| expiresInSeconds | number | 300 | Token TTL in seconds |
Tokens are auto-cached and refreshed 60 seconds before expiry.
SDK Methods
bootstrapTenantOwner(request)
Bootstrap tenant owner — assign owner role to a user for a new tenant. Typically called by tenant-provisioning service after creating a tenant.
Route: POST /internal/tenant/bootstrap-owner
const result = await client.bootstrapTenantOwner({
tenantId: 'tenant-abc',
userId: 'user-123',
});
if (result.isOkWithData()) {
console.log(result.data);
// { message: string, tenantId: string, userId: string, role: string }
}getTenantProfile(request)
Get per-tenant user profile with membership and permissions. Allows services to read tenant profiles without user authentication.
Route: POST /internal/tenant/profile
const result = await client.getTenantProfile({
tenantId: 'tenant-abc',
userId: 'user-123',
});
if (result.isOkWithData()) {
console.log(result.data);
// {
// tenantId: string,
// userId: string,
// status: string, // 'invited' | 'active' | 'suspended' | 'removed'
// role?: string,
// permMask: number, // business permission bitmask (0 = none)
// authPermMask: number, // internal auth permission bitmask (0 = none)
// isOwner: boolean,
// displayName?: string, // from per-tenant profile (may not exist yet)
// avatarUrl?: string,
// title?: string,
// bio?: string,
// metadata?: Record<string, unknown>,
// }
}Error Handling
All methods return Result<T> from ts-micro-result.
import { sdkErrors } from '@auth-craft/backend-sdk';
const result = await client.bootstrapTenantOwner({ tenantId, userId });
if (result.isError()) {
const error = result.errors[0];
switch (error?.code) {
case 'SDK_NETWORK_ERROR':
// Network request failed
break;
case 'SDK_TIMEOUT':
// Request timed out
break;
case 'SDK_INVALID_RESPONSE':
// Non-JSON response from auth service
break;
case 'SDK_JWT_SIGN_FAILED':
// Failed to sign service JWT
break;
default:
// Auth service returned an application-level error
break;
}
}Types
export type {
InternalClientConfig,
JwtConfig,
JwtHmacConfig,
JwtEddsaConfig,
JwtRs256Config,
JwtEs256Config,
BootstrapTenantOwnerRequest,
BootstrapTenantOwnerResponse,
GetTenantProfileRequest,
TenantProfileResponse,
} from '@auth-craft/backend-sdk';
export { InternalClient, sdkErrors } from '@auth-craft/backend-sdk';Changelog
0.1.0
- Breaking:
getTenantProfilenow usesPOSTinstead ofGET(body instead of query params) - Breaking:
TenantProfileResponsenow includes membership fields (status,permMask,authPermMask,isOwner).permMaskandauthPermMaskare always present (default0) - Fix: EdDSA private key import — wrap 32-byte seed in PKCS8 envelope (RFC 8410) for Node.js 20+ compatibility
License
MIT
