@auth-craft/backend-sdk 0.0.1
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 +184 -0
- package/dist/index.cjs +317 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +140 -0
- package/dist/index.d.ts +140 -0
- package/dist/index.js +317 -0
- package/dist/index.js.map +1 -0
- package/package.json +32 -0
package/README.md
ADDED
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# @auth-craft/backend-sdk
|
|
2
|
+
|
|
3
|
+
> ⚠️ **Experimental / Internal Use**
|
|
4
|
+
>
|
|
5
|
+
> This package is published for convenience only.
|
|
6
|
+
>
|
|
7
|
+
> - No stability guarantee
|
|
8
|
+
> - Breaking changes may happen at any time
|
|
9
|
+
> - No documentation
|
|
10
|
+
> - No support
|
|
11
|
+
>
|
|
12
|
+
> Use at your own risk.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
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`).
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @auth-craft/backend-sdk
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { createInternalClient } from '@auth-craft/backend-sdk';
|
|
28
|
+
|
|
29
|
+
const client = createInternalClient({
|
|
30
|
+
baseUrl: 'https://auth.example.com',
|
|
31
|
+
basePath: '/system',
|
|
32
|
+
jwt: {
|
|
33
|
+
strategy: 'hmac',
|
|
34
|
+
secret: process.env.INTERNAL_JWT_SECRET!,
|
|
35
|
+
issuer: 'tenant-provisioning-service',
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const result = await client.bootstrapTenantOwner({
|
|
40
|
+
tenantId: 'tenant-abc',
|
|
41
|
+
userId: 'user-123',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (result.isOkWithData()) {
|
|
45
|
+
console.log(result.data);
|
|
46
|
+
// { message: '...', tenantId: 'tenant-abc', userId: 'user-123', role: 'owner' }
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## API
|
|
51
|
+
|
|
52
|
+
### `createInternalClient(config)`
|
|
53
|
+
|
|
54
|
+
Creates an `InternalClient` instance.
|
|
55
|
+
|
|
56
|
+
**Parameters:**
|
|
57
|
+
|
|
58
|
+
| Field | Type | Default | Description |
|
|
59
|
+
|---|---|---|---|
|
|
60
|
+
| `baseUrl` | `string` | — | Base URL of the auth service |
|
|
61
|
+
| `basePath` | `string` | `''` | Path prefix before `/internal` (e.g., `'/system'` → `/system/internal/*`) |
|
|
62
|
+
| `jwt` | `JwtConfig` | — | Service JWT signing configuration |
|
|
63
|
+
| `fetchImpl` | `typeof fetch` | `globalThis.fetch` | Custom fetch implementation |
|
|
64
|
+
| `timeout` | `number` | `30000` | Request timeout in milliseconds |
|
|
65
|
+
| `headers` | `Record<string, string>` | `{}` | Custom headers for all requests |
|
|
66
|
+
|
|
67
|
+
**Returns:** `InternalClient`
|
|
68
|
+
|
|
69
|
+
### JWT Signing Strategies
|
|
70
|
+
|
|
71
|
+
The SDK supports four JWT signing strategies via Web Crypto API:
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
// HMAC-SHA256 (symmetric)
|
|
75
|
+
jwt: { strategy: 'hmac', secret: '...' }
|
|
76
|
+
|
|
77
|
+
// EdDSA / Ed25519 (asymmetric)
|
|
78
|
+
jwt: { strategy: 'eddsa', privateKey: '...' } // hex string or Uint8Array
|
|
79
|
+
|
|
80
|
+
// RS256 / RSA-SHA256 (asymmetric)
|
|
81
|
+
jwt: { strategy: 'rs256', privateKey: '...' } // PEM string or JsonWebKey
|
|
82
|
+
|
|
83
|
+
// ES256 / ECDSA P-256 (asymmetric)
|
|
84
|
+
jwt: { strategy: 'es256', privateKey: '...' } // PEM string or JsonWebKey
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Common JWT options:
|
|
88
|
+
|
|
89
|
+
| Field | Type | Default | Description |
|
|
90
|
+
|---|---|---|---|
|
|
91
|
+
| `issuer` | `string` | — | JWT `iss` claim |
|
|
92
|
+
| `audience` | `string` | — | JWT `aud` claim |
|
|
93
|
+
| `expiresInSeconds` | `number` | `300` | Token TTL in seconds |
|
|
94
|
+
|
|
95
|
+
Tokens are auto-cached and refreshed 60 seconds before expiry.
|
|
96
|
+
|
|
97
|
+
### SDK Methods
|
|
98
|
+
|
|
99
|
+
#### `bootstrapTenantOwner(request)`
|
|
100
|
+
|
|
101
|
+
Bootstrap tenant owner — assign owner role to a user for a new tenant. Typically called by tenant-provisioning service after creating a tenant.
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
const result = await client.bootstrapTenantOwner({
|
|
105
|
+
tenantId: 'tenant-abc',
|
|
106
|
+
userId: 'user-123',
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
if (result.isOkWithData()) {
|
|
110
|
+
console.log(result.data);
|
|
111
|
+
// { message: string, tenantId: string, userId: string, role: string }
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### `getTenantProfile(request)`
|
|
116
|
+
|
|
117
|
+
Get per-tenant user profile (internal). Allows services to read tenant profiles without user authentication.
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
const result = await client.getTenantProfile({
|
|
121
|
+
tenantId: 'tenant-abc',
|
|
122
|
+
userId: 'user-123',
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
if (result.isOkWithData()) {
|
|
126
|
+
console.log(result.data);
|
|
127
|
+
// { userId, tenantId, displayName?, avatarUrl?, title?, bio?, metadata? }
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Error Handling
|
|
132
|
+
|
|
133
|
+
All methods return `Result<T>` from `ts-micro-result`.
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import { sdkErrors } from '@auth-craft/backend-sdk';
|
|
137
|
+
|
|
138
|
+
const result = await client.bootstrapTenantOwner({ tenantId, userId });
|
|
139
|
+
|
|
140
|
+
if (result.isError()) {
|
|
141
|
+
const error = result.errors[0];
|
|
142
|
+
|
|
143
|
+
switch (error?.code) {
|
|
144
|
+
case 'SDK_NETWORK_ERROR':
|
|
145
|
+
// Network request failed
|
|
146
|
+
break;
|
|
147
|
+
case 'SDK_TIMEOUT':
|
|
148
|
+
// Request timed out
|
|
149
|
+
break;
|
|
150
|
+
case 'SDK_INVALID_RESPONSE':
|
|
151
|
+
// Non-JSON response from auth service
|
|
152
|
+
break;
|
|
153
|
+
case 'SDK_JWT_SIGN_FAILED':
|
|
154
|
+
// Failed to sign service JWT
|
|
155
|
+
break;
|
|
156
|
+
default:
|
|
157
|
+
// Auth service returned an application-level error
|
|
158
|
+
break;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Types
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
export type {
|
|
167
|
+
InternalClientConfig,
|
|
168
|
+
JwtConfig,
|
|
169
|
+
JwtHmacConfig,
|
|
170
|
+
JwtEddsaConfig,
|
|
171
|
+
JwtRs256Config,
|
|
172
|
+
JwtEs256Config,
|
|
173
|
+
BootstrapTenantOwnerRequest,
|
|
174
|
+
BootstrapTenantOwnerResponse,
|
|
175
|
+
GetTenantProfileRequest,
|
|
176
|
+
TenantProfileResponse,
|
|
177
|
+
} from '@auth-craft/backend-sdk';
|
|
178
|
+
|
|
179
|
+
export { InternalClient, sdkErrors } from '@auth-craft/backend-sdk';
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## License
|
|
183
|
+
|
|
184
|
+
MIT
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class;// src/http-client.ts
|
|
2
|
+
var _tsmicroresult = require('ts-micro-result');
|
|
3
|
+
|
|
4
|
+
// src/jwt-signer.ts
|
|
5
|
+
function base64urlEncode(data) {
|
|
6
|
+
let binary = "";
|
|
7
|
+
for (let i = 0; i < data.length; i++) {
|
|
8
|
+
binary += String.fromCharCode(data[i]);
|
|
9
|
+
}
|
|
10
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
11
|
+
}
|
|
12
|
+
function hexToUint8Array(hex) {
|
|
13
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
14
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
15
|
+
bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);
|
|
16
|
+
}
|
|
17
|
+
return bytes;
|
|
18
|
+
}
|
|
19
|
+
function parsePemToSpki(pem) {
|
|
20
|
+
const pemBody = pem.replace(/-----BEGIN PRIVATE KEY-----/g, "").replace(/-----END PRIVATE KEY-----/g, "").replace(/\s/g, "");
|
|
21
|
+
const binary = atob(pemBody);
|
|
22
|
+
const bytes = new Uint8Array(binary.length);
|
|
23
|
+
for (let i = 0; i < binary.length; i++) {
|
|
24
|
+
bytes[i] = binary.charCodeAt(i);
|
|
25
|
+
}
|
|
26
|
+
return bytes;
|
|
27
|
+
}
|
|
28
|
+
async function importHmacSigningKey(secret) {
|
|
29
|
+
const encoder = new TextEncoder();
|
|
30
|
+
const keyData = encoder.encode(secret);
|
|
31
|
+
return crypto.subtle.importKey(
|
|
32
|
+
"raw",
|
|
33
|
+
keyData.buffer,
|
|
34
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
35
|
+
false,
|
|
36
|
+
["sign"]
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
async function importEdDSAPrivateKey(privateKey) {
|
|
40
|
+
const keyBytes = typeof privateKey === "string" ? hexToUint8Array(privateKey) : privateKey;
|
|
41
|
+
return crypto.subtle.importKey(
|
|
42
|
+
"raw",
|
|
43
|
+
keyBytes.buffer,
|
|
44
|
+
{ name: "Ed25519" },
|
|
45
|
+
false,
|
|
46
|
+
["sign"]
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
async function importRsaPrivateKey(privateKey) {
|
|
50
|
+
if (typeof privateKey === "object") {
|
|
51
|
+
return crypto.subtle.importKey(
|
|
52
|
+
"jwk",
|
|
53
|
+
privateKey,
|
|
54
|
+
{ name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
|
|
55
|
+
false,
|
|
56
|
+
["sign"]
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
const pkcs8Bytes = parsePemToSpki(privateKey);
|
|
60
|
+
return crypto.subtle.importKey(
|
|
61
|
+
"pkcs8",
|
|
62
|
+
pkcs8Bytes.buffer,
|
|
63
|
+
{ name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
|
|
64
|
+
false,
|
|
65
|
+
["sign"]
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
async function importEcdsaPrivateKey(privateKey) {
|
|
69
|
+
if (typeof privateKey === "object") {
|
|
70
|
+
return crypto.subtle.importKey(
|
|
71
|
+
"jwk",
|
|
72
|
+
privateKey,
|
|
73
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
74
|
+
false,
|
|
75
|
+
["sign"]
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
const pkcs8Bytes = parsePemToSpki(privateKey);
|
|
79
|
+
return crypto.subtle.importKey(
|
|
80
|
+
"pkcs8",
|
|
81
|
+
pkcs8Bytes.buffer,
|
|
82
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
83
|
+
false,
|
|
84
|
+
["sign"]
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
async function resolveSignKey(config) {
|
|
88
|
+
const strategy = config.strategy;
|
|
89
|
+
switch (strategy) {
|
|
90
|
+
case "hmac": {
|
|
91
|
+
const c = config;
|
|
92
|
+
return {
|
|
93
|
+
key: await importHmacSigningKey(c.secret),
|
|
94
|
+
jwtAlgorithm: "HS256",
|
|
95
|
+
cryptoAlgorithm: "HMAC"
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
case "eddsa": {
|
|
99
|
+
const c = config;
|
|
100
|
+
return {
|
|
101
|
+
key: await importEdDSAPrivateKey(c.privateKey),
|
|
102
|
+
jwtAlgorithm: "EdDSA",
|
|
103
|
+
cryptoAlgorithm: { name: "Ed25519" }
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
case "rs256": {
|
|
107
|
+
const c = config;
|
|
108
|
+
return {
|
|
109
|
+
key: await importRsaPrivateKey(c.privateKey),
|
|
110
|
+
jwtAlgorithm: "RS256",
|
|
111
|
+
cryptoAlgorithm: "RSASSA-PKCS1-v1_5"
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
case "es256": {
|
|
115
|
+
const c = config;
|
|
116
|
+
return {
|
|
117
|
+
key: await importEcdsaPrivateKey(c.privateKey),
|
|
118
|
+
jwtAlgorithm: "ES256",
|
|
119
|
+
cryptoAlgorithm: { name: "ECDSA", hash: "SHA-256" }
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
var REFRESH_BUFFER_SECONDS = 60;
|
|
125
|
+
var JwtSigner = (_class = class {
|
|
126
|
+
constructor(config) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);
|
|
127
|
+
this.config = config;
|
|
128
|
+
}
|
|
129
|
+
__init() {this.cachedKeyInfo = null}
|
|
130
|
+
__init2() {this.cachedToken = null}
|
|
131
|
+
__init3() {this.cachedExp = 0}
|
|
132
|
+
/**
|
|
133
|
+
* Get a valid service JWT token.
|
|
134
|
+
* Automatically signs a new token when the current one is about to expire.
|
|
135
|
+
*/
|
|
136
|
+
async getToken() {
|
|
137
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
138
|
+
if (this.cachedToken && nowSeconds < this.cachedExp - REFRESH_BUFFER_SECONDS) {
|
|
139
|
+
return this.cachedToken;
|
|
140
|
+
}
|
|
141
|
+
return this.signNewToken();
|
|
142
|
+
}
|
|
143
|
+
async signNewToken() {
|
|
144
|
+
const keyInfo = await this.getKeyInfo();
|
|
145
|
+
const encoder = new TextEncoder();
|
|
146
|
+
const expiresInSeconds = _nullishCoalesce(this.config.expiresInSeconds, () => ( 300));
|
|
147
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
148
|
+
const header = base64urlEncode(
|
|
149
|
+
encoder.encode(JSON.stringify({ alg: keyInfo.jwtAlgorithm, typ: "JWT" }))
|
|
150
|
+
);
|
|
151
|
+
const payload = {
|
|
152
|
+
iat: nowSeconds,
|
|
153
|
+
exp: nowSeconds + expiresInSeconds
|
|
154
|
+
};
|
|
155
|
+
if (this.config.issuer !== void 0) {
|
|
156
|
+
payload.iss = this.config.issuer;
|
|
157
|
+
}
|
|
158
|
+
if (this.config.audience !== void 0) {
|
|
159
|
+
payload.aud = this.config.audience;
|
|
160
|
+
}
|
|
161
|
+
const payloadB64 = base64urlEncode(encoder.encode(JSON.stringify(payload)));
|
|
162
|
+
const signData = encoder.encode(`${header}.${payloadB64}`);
|
|
163
|
+
const signatureBytes = new Uint8Array(
|
|
164
|
+
await crypto.subtle.sign(
|
|
165
|
+
keyInfo.cryptoAlgorithm,
|
|
166
|
+
keyInfo.key,
|
|
167
|
+
signData.buffer
|
|
168
|
+
)
|
|
169
|
+
);
|
|
170
|
+
const signature = base64urlEncode(signatureBytes);
|
|
171
|
+
const token = `${header}.${payloadB64}.${signature}`;
|
|
172
|
+
this.cachedToken = token;
|
|
173
|
+
this.cachedExp = nowSeconds + expiresInSeconds;
|
|
174
|
+
return token;
|
|
175
|
+
}
|
|
176
|
+
async getKeyInfo() {
|
|
177
|
+
if (!this.cachedKeyInfo) {
|
|
178
|
+
this.cachedKeyInfo = await resolveSignKey(this.config);
|
|
179
|
+
}
|
|
180
|
+
return this.cachedKeyInfo;
|
|
181
|
+
}
|
|
182
|
+
}, _class);
|
|
183
|
+
|
|
184
|
+
// src/errors.ts
|
|
185
|
+
|
|
186
|
+
var sdkErrors = {
|
|
187
|
+
NETWORK_ERROR: _tsmicroresult.defineError.call(void 0, "SDK_NETWORK_ERROR", "Network request failed"),
|
|
188
|
+
TIMEOUT: _tsmicroresult.defineError.call(void 0, "SDK_TIMEOUT", "Request timed out"),
|
|
189
|
+
INVALID_RESPONSE: _tsmicroresult.defineError.call(void 0, "SDK_INVALID_RESPONSE", "Invalid response from auth service"),
|
|
190
|
+
JWT_SIGN_FAILED: _tsmicroresult.defineError.call(void 0, "SDK_JWT_SIGN_FAILED", "Failed to sign service JWT")
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// src/http-client.ts
|
|
194
|
+
var HttpClient = class {
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
constructor(config) {
|
|
202
|
+
this.signer = new JwtSigner(config.jwt);
|
|
203
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
204
|
+
this.basePath = _nullishCoalesce(config.basePath, () => ( ""));
|
|
205
|
+
this.fetchFn = _nullishCoalesce(config.fetchImpl, () => ( globalThis.fetch));
|
|
206
|
+
this.timeout = _nullishCoalesce(config.timeout, () => ( 3e4));
|
|
207
|
+
this.customHeaders = _nullishCoalesce(config.headers, () => ( {}));
|
|
208
|
+
}
|
|
209
|
+
async request(method, path, options) {
|
|
210
|
+
try {
|
|
211
|
+
let token;
|
|
212
|
+
try {
|
|
213
|
+
token = await this.signer.getToken();
|
|
214
|
+
} catch (signError) {
|
|
215
|
+
const message = signError instanceof Error ? signError.message : String(signError);
|
|
216
|
+
return _tsmicroresult.err.call(void 0, sdkErrors.JWT_SIGN_FAILED({ message }));
|
|
217
|
+
}
|
|
218
|
+
const url = this.buildUrl(path, _optionalChain([options, 'optionalAccess', _ => _.query]));
|
|
219
|
+
const headers = {
|
|
220
|
+
"Content-Type": "application/json",
|
|
221
|
+
"Authorization": `Bearer ${token}`,
|
|
222
|
+
...this.customHeaders
|
|
223
|
+
};
|
|
224
|
+
const controller = new AbortController();
|
|
225
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
226
|
+
let response;
|
|
227
|
+
try {
|
|
228
|
+
response = await this.fetchFn(url, {
|
|
229
|
+
method,
|
|
230
|
+
headers,
|
|
231
|
+
body: _optionalChain([options, 'optionalAccess', _2 => _2.body]) !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
232
|
+
signal: controller.signal
|
|
233
|
+
});
|
|
234
|
+
} finally {
|
|
235
|
+
clearTimeout(timeoutId);
|
|
236
|
+
}
|
|
237
|
+
let envelope;
|
|
238
|
+
try {
|
|
239
|
+
envelope = await response.json();
|
|
240
|
+
} catch (e) {
|
|
241
|
+
return _tsmicroresult.err.call(void 0,
|
|
242
|
+
sdkErrors.INVALID_RESPONSE({ message: `HTTP ${response.status}: non-JSON response` }),
|
|
243
|
+
void 0,
|
|
244
|
+
response.status
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
if (envelope.ok && envelope.data !== void 0) {
|
|
248
|
+
return _tsmicroresult.ok.call(void 0, envelope.data, envelope.meta);
|
|
249
|
+
}
|
|
250
|
+
const errors = _nullishCoalesce(envelope.errors, () => ( [{ code: "UNKNOWN_ERROR", message: `HTTP ${response.status}` }]));
|
|
251
|
+
return _tsmicroresult.err.call(void 0, errors, envelope.meta, response.status);
|
|
252
|
+
} catch (error) {
|
|
253
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
254
|
+
return _tsmicroresult.err.call(void 0, sdkErrors.TIMEOUT({ message: `Request timed out after ${this.timeout}ms` }), void 0, 408);
|
|
255
|
+
}
|
|
256
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
257
|
+
return _tsmicroresult.err.call(void 0, sdkErrors.NETWORK_ERROR({ message }), void 0, 0);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
buildUrl(path, query) {
|
|
261
|
+
let url = `${this.baseUrl}${this.basePath}/internal${path}`;
|
|
262
|
+
if (query) {
|
|
263
|
+
const entries = Object.entries(query).filter(([, v]) => v !== void 0);
|
|
264
|
+
if (entries.length > 0) {
|
|
265
|
+
const params = new URLSearchParams(entries);
|
|
266
|
+
url += `?${params.toString()}`;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return url;
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
// src/client.ts
|
|
274
|
+
var InternalClient = class {
|
|
275
|
+
|
|
276
|
+
constructor(config) {
|
|
277
|
+
this.http = new HttpClient(config);
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Bootstrap tenant owner (assign owner role to a user for a new tenant).
|
|
281
|
+
* Typically called by tenant-provisioning service after creating a tenant.
|
|
282
|
+
*/
|
|
283
|
+
async bootstrapTenantOwner(request) {
|
|
284
|
+
return this.http.request(
|
|
285
|
+
"POST",
|
|
286
|
+
"/tenant/bootstrap-owner",
|
|
287
|
+
{ body: request }
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Get per-tenant user profile (internal).
|
|
292
|
+
* Allows services to read tenant profiles without user authentication.
|
|
293
|
+
*/
|
|
294
|
+
async getTenantProfile(request) {
|
|
295
|
+
return this.http.request(
|
|
296
|
+
"GET",
|
|
297
|
+
"/tenant/profile",
|
|
298
|
+
{
|
|
299
|
+
query: {
|
|
300
|
+
tenantId: request.tenantId,
|
|
301
|
+
userId: request.userId
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
// src/index.ts
|
|
309
|
+
function createInternalClient(config) {
|
|
310
|
+
return new InternalClient(config);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
exports.InternalClient = InternalClient; exports.createInternalClient = createInternalClient; exports.sdkErrors = sdkErrors;
|
|
317
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["d:\\NodeJS_Projects\\auth-craft\\packages\\backend-sdk\\dist\\index.cjs"],"names":[],"mappings":"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A;AACA,QAAA;AACA,MAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,MAAA;AACA,QAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,MAAA;AACA,QAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,QAAA;AACA,MAAA;AACA,IAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA,EAAA;AACA,EAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA,EAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA,EAAA;AACA,IAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACA,QAAA;AACA,UAAA;AACA,UAAA;AACA,QAAA;AACA,MAAA;AACA,IAAA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA,EAAA;AACA;AACA;AACA;AACA;AACA;AACA","file":"D:\\NodeJS_Projects\\auth-craft\\packages\\backend-sdk\\dist\\index.cjs","sourcesContent":[null]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import * as ts_micro_result from 'ts-micro-result';
|
|
2
|
+
import { Result } from 'ts-micro-result';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Backend SDK Types
|
|
6
|
+
* Configuration, request, and response types for internal service-to-service calls
|
|
7
|
+
*/
|
|
8
|
+
/** HMAC-SHA256 symmetric signing */
|
|
9
|
+
interface JwtHmacConfig {
|
|
10
|
+
strategy: 'hmac';
|
|
11
|
+
/** Shared HMAC secret. MUST be different from user-facing JWT secret. */
|
|
12
|
+
secret: string;
|
|
13
|
+
}
|
|
14
|
+
/** EdDSA (Ed25519) asymmetric signing */
|
|
15
|
+
interface JwtEddsaConfig {
|
|
16
|
+
strategy: 'eddsa';
|
|
17
|
+
/** Ed25519 private key as hex string or raw bytes */
|
|
18
|
+
privateKey: string | Uint8Array;
|
|
19
|
+
}
|
|
20
|
+
/** RS256 (RSA-SHA256) asymmetric signing */
|
|
21
|
+
interface JwtRs256Config {
|
|
22
|
+
strategy: 'rs256';
|
|
23
|
+
/** RSA private key in PEM or JWK format */
|
|
24
|
+
privateKey: string | JsonWebKey;
|
|
25
|
+
}
|
|
26
|
+
/** ES256 (ECDSA P-256) asymmetric signing */
|
|
27
|
+
interface JwtEs256Config {
|
|
28
|
+
strategy: 'es256';
|
|
29
|
+
/** ECDSA P-256 private key in PEM or JWK format */
|
|
30
|
+
privateKey: string | JsonWebKey;
|
|
31
|
+
}
|
|
32
|
+
type JwtConfig = (JwtHmacConfig | JwtEddsaConfig | JwtRs256Config | JwtEs256Config) & {
|
|
33
|
+
/** JWT issuer claim (e.g., 'tenant-provisioning-service') */
|
|
34
|
+
issuer?: string;
|
|
35
|
+
/** JWT audience claim (e.g., 'auth-service') */
|
|
36
|
+
audience?: string;
|
|
37
|
+
/** Token TTL in seconds @default 300 (5 minutes) */
|
|
38
|
+
expiresInSeconds?: number;
|
|
39
|
+
};
|
|
40
|
+
interface InternalClientConfig {
|
|
41
|
+
/** Base URL of the auth service (e.g., 'https://auth.example.com') */
|
|
42
|
+
baseUrl: string;
|
|
43
|
+
/**
|
|
44
|
+
* Base path prefix before /internal (e.g., '/system' → /system/internal/*)
|
|
45
|
+
* @default ''
|
|
46
|
+
*/
|
|
47
|
+
basePath?: string;
|
|
48
|
+
/** Service JWT signing configuration */
|
|
49
|
+
jwt: JwtConfig;
|
|
50
|
+
/** Custom fetch implementation (for testing or middleware) */
|
|
51
|
+
fetchImpl?: typeof fetch;
|
|
52
|
+
/** Request timeout in milliseconds @default 30000 */
|
|
53
|
+
timeout?: number;
|
|
54
|
+
/** Custom headers to include in all requests */
|
|
55
|
+
headers?: Record<string, string>;
|
|
56
|
+
}
|
|
57
|
+
interface BootstrapTenantOwnerRequest {
|
|
58
|
+
tenantId: string;
|
|
59
|
+
userId: string;
|
|
60
|
+
}
|
|
61
|
+
interface GetTenantProfileRequest {
|
|
62
|
+
tenantId: string;
|
|
63
|
+
userId: string;
|
|
64
|
+
}
|
|
65
|
+
interface BootstrapTenantOwnerResponse {
|
|
66
|
+
message: string;
|
|
67
|
+
tenantId: string;
|
|
68
|
+
userId: string;
|
|
69
|
+
role: string;
|
|
70
|
+
}
|
|
71
|
+
interface TenantProfileResponse {
|
|
72
|
+
userId: string;
|
|
73
|
+
tenantId: string;
|
|
74
|
+
displayName?: string;
|
|
75
|
+
avatarUrl?: string;
|
|
76
|
+
title?: string;
|
|
77
|
+
bio?: string;
|
|
78
|
+
metadata?: Record<string, unknown>;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Internal Client
|
|
83
|
+
* Type-safe client for auth service internal (service-to-service) API.
|
|
84
|
+
*/
|
|
85
|
+
|
|
86
|
+
declare class InternalClient {
|
|
87
|
+
private readonly http;
|
|
88
|
+
constructor(config: InternalClientConfig);
|
|
89
|
+
/**
|
|
90
|
+
* Bootstrap tenant owner (assign owner role to a user for a new tenant).
|
|
91
|
+
* Typically called by tenant-provisioning service after creating a tenant.
|
|
92
|
+
*/
|
|
93
|
+
bootstrapTenantOwner(request: BootstrapTenantOwnerRequest): Promise<Result<BootstrapTenantOwnerResponse>>;
|
|
94
|
+
/**
|
|
95
|
+
* Get per-tenant user profile (internal).
|
|
96
|
+
* Allows services to read tenant profiles without user authentication.
|
|
97
|
+
*/
|
|
98
|
+
getTenantProfile(request: GetTenantProfileRequest): Promise<Result<TenantProfileResponse>>;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Backend SDK Error Definitions
|
|
103
|
+
*/
|
|
104
|
+
declare const sdkErrors: {
|
|
105
|
+
readonly NETWORK_ERROR: (params?: ts_micro_result.BaseErrorParams) => ts_micro_result.ErrorDetail;
|
|
106
|
+
readonly TIMEOUT: (params?: ts_micro_result.BaseErrorParams) => ts_micro_result.ErrorDetail;
|
|
107
|
+
readonly INVALID_RESPONSE: (params?: ts_micro_result.BaseErrorParams) => ts_micro_result.ErrorDetail;
|
|
108
|
+
readonly JWT_SIGN_FAILED: (params?: ts_micro_result.BaseErrorParams) => ts_micro_result.ErrorDetail;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @auth-craft/backend-sdk
|
|
113
|
+
* Type-safe internal service SDK for Auth-Craft service-to-service calls.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```ts
|
|
117
|
+
* import { createInternalClient } from '@auth-craft/backend-sdk';
|
|
118
|
+
*
|
|
119
|
+
* const client = createInternalClient({
|
|
120
|
+
* baseUrl: 'https://auth.example.com',
|
|
121
|
+
* basePath: '/system',
|
|
122
|
+
* jwt: {
|
|
123
|
+
* strategy: 'hmac',
|
|
124
|
+
* secret: process.env.INTERNAL_JWT_SECRET!,
|
|
125
|
+
* issuer: 'tenant-provisioning-service',
|
|
126
|
+
* },
|
|
127
|
+
* });
|
|
128
|
+
*
|
|
129
|
+
* const result = await client.bootstrapTenantOwner({ tenantId, userId });
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Create an internal service client for Auth-Craft.
|
|
135
|
+
*
|
|
136
|
+
* The client auto-signs service JWTs and refreshes them before expiry.
|
|
137
|
+
*/
|
|
138
|
+
declare function createInternalClient(config: InternalClientConfig): InternalClient;
|
|
139
|
+
|
|
140
|
+
export { type BootstrapTenantOwnerRequest, type BootstrapTenantOwnerResponse, type GetTenantProfileRequest, InternalClient, type InternalClientConfig, type JwtConfig, type JwtEddsaConfig, type JwtEs256Config, type JwtHmacConfig, type JwtRs256Config, type TenantProfileResponse, createInternalClient, sdkErrors };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import * as ts_micro_result from 'ts-micro-result';
|
|
2
|
+
import { Result } from 'ts-micro-result';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Backend SDK Types
|
|
6
|
+
* Configuration, request, and response types for internal service-to-service calls
|
|
7
|
+
*/
|
|
8
|
+
/** HMAC-SHA256 symmetric signing */
|
|
9
|
+
interface JwtHmacConfig {
|
|
10
|
+
strategy: 'hmac';
|
|
11
|
+
/** Shared HMAC secret. MUST be different from user-facing JWT secret. */
|
|
12
|
+
secret: string;
|
|
13
|
+
}
|
|
14
|
+
/** EdDSA (Ed25519) asymmetric signing */
|
|
15
|
+
interface JwtEddsaConfig {
|
|
16
|
+
strategy: 'eddsa';
|
|
17
|
+
/** Ed25519 private key as hex string or raw bytes */
|
|
18
|
+
privateKey: string | Uint8Array;
|
|
19
|
+
}
|
|
20
|
+
/** RS256 (RSA-SHA256) asymmetric signing */
|
|
21
|
+
interface JwtRs256Config {
|
|
22
|
+
strategy: 'rs256';
|
|
23
|
+
/** RSA private key in PEM or JWK format */
|
|
24
|
+
privateKey: string | JsonWebKey;
|
|
25
|
+
}
|
|
26
|
+
/** ES256 (ECDSA P-256) asymmetric signing */
|
|
27
|
+
interface JwtEs256Config {
|
|
28
|
+
strategy: 'es256';
|
|
29
|
+
/** ECDSA P-256 private key in PEM or JWK format */
|
|
30
|
+
privateKey: string | JsonWebKey;
|
|
31
|
+
}
|
|
32
|
+
type JwtConfig = (JwtHmacConfig | JwtEddsaConfig | JwtRs256Config | JwtEs256Config) & {
|
|
33
|
+
/** JWT issuer claim (e.g., 'tenant-provisioning-service') */
|
|
34
|
+
issuer?: string;
|
|
35
|
+
/** JWT audience claim (e.g., 'auth-service') */
|
|
36
|
+
audience?: string;
|
|
37
|
+
/** Token TTL in seconds @default 300 (5 minutes) */
|
|
38
|
+
expiresInSeconds?: number;
|
|
39
|
+
};
|
|
40
|
+
interface InternalClientConfig {
|
|
41
|
+
/** Base URL of the auth service (e.g., 'https://auth.example.com') */
|
|
42
|
+
baseUrl: string;
|
|
43
|
+
/**
|
|
44
|
+
* Base path prefix before /internal (e.g., '/system' → /system/internal/*)
|
|
45
|
+
* @default ''
|
|
46
|
+
*/
|
|
47
|
+
basePath?: string;
|
|
48
|
+
/** Service JWT signing configuration */
|
|
49
|
+
jwt: JwtConfig;
|
|
50
|
+
/** Custom fetch implementation (for testing or middleware) */
|
|
51
|
+
fetchImpl?: typeof fetch;
|
|
52
|
+
/** Request timeout in milliseconds @default 30000 */
|
|
53
|
+
timeout?: number;
|
|
54
|
+
/** Custom headers to include in all requests */
|
|
55
|
+
headers?: Record<string, string>;
|
|
56
|
+
}
|
|
57
|
+
interface BootstrapTenantOwnerRequest {
|
|
58
|
+
tenantId: string;
|
|
59
|
+
userId: string;
|
|
60
|
+
}
|
|
61
|
+
interface GetTenantProfileRequest {
|
|
62
|
+
tenantId: string;
|
|
63
|
+
userId: string;
|
|
64
|
+
}
|
|
65
|
+
interface BootstrapTenantOwnerResponse {
|
|
66
|
+
message: string;
|
|
67
|
+
tenantId: string;
|
|
68
|
+
userId: string;
|
|
69
|
+
role: string;
|
|
70
|
+
}
|
|
71
|
+
interface TenantProfileResponse {
|
|
72
|
+
userId: string;
|
|
73
|
+
tenantId: string;
|
|
74
|
+
displayName?: string;
|
|
75
|
+
avatarUrl?: string;
|
|
76
|
+
title?: string;
|
|
77
|
+
bio?: string;
|
|
78
|
+
metadata?: Record<string, unknown>;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Internal Client
|
|
83
|
+
* Type-safe client for auth service internal (service-to-service) API.
|
|
84
|
+
*/
|
|
85
|
+
|
|
86
|
+
declare class InternalClient {
|
|
87
|
+
private readonly http;
|
|
88
|
+
constructor(config: InternalClientConfig);
|
|
89
|
+
/**
|
|
90
|
+
* Bootstrap tenant owner (assign owner role to a user for a new tenant).
|
|
91
|
+
* Typically called by tenant-provisioning service after creating a tenant.
|
|
92
|
+
*/
|
|
93
|
+
bootstrapTenantOwner(request: BootstrapTenantOwnerRequest): Promise<Result<BootstrapTenantOwnerResponse>>;
|
|
94
|
+
/**
|
|
95
|
+
* Get per-tenant user profile (internal).
|
|
96
|
+
* Allows services to read tenant profiles without user authentication.
|
|
97
|
+
*/
|
|
98
|
+
getTenantProfile(request: GetTenantProfileRequest): Promise<Result<TenantProfileResponse>>;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Backend SDK Error Definitions
|
|
103
|
+
*/
|
|
104
|
+
declare const sdkErrors: {
|
|
105
|
+
readonly NETWORK_ERROR: (params?: ts_micro_result.BaseErrorParams) => ts_micro_result.ErrorDetail;
|
|
106
|
+
readonly TIMEOUT: (params?: ts_micro_result.BaseErrorParams) => ts_micro_result.ErrorDetail;
|
|
107
|
+
readonly INVALID_RESPONSE: (params?: ts_micro_result.BaseErrorParams) => ts_micro_result.ErrorDetail;
|
|
108
|
+
readonly JWT_SIGN_FAILED: (params?: ts_micro_result.BaseErrorParams) => ts_micro_result.ErrorDetail;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* @auth-craft/backend-sdk
|
|
113
|
+
* Type-safe internal service SDK for Auth-Craft service-to-service calls.
|
|
114
|
+
*
|
|
115
|
+
* @example
|
|
116
|
+
* ```ts
|
|
117
|
+
* import { createInternalClient } from '@auth-craft/backend-sdk';
|
|
118
|
+
*
|
|
119
|
+
* const client = createInternalClient({
|
|
120
|
+
* baseUrl: 'https://auth.example.com',
|
|
121
|
+
* basePath: '/system',
|
|
122
|
+
* jwt: {
|
|
123
|
+
* strategy: 'hmac',
|
|
124
|
+
* secret: process.env.INTERNAL_JWT_SECRET!,
|
|
125
|
+
* issuer: 'tenant-provisioning-service',
|
|
126
|
+
* },
|
|
127
|
+
* });
|
|
128
|
+
*
|
|
129
|
+
* const result = await client.bootstrapTenantOwner({ tenantId, userId });
|
|
130
|
+
* ```
|
|
131
|
+
*/
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Create an internal service client for Auth-Craft.
|
|
135
|
+
*
|
|
136
|
+
* The client auto-signs service JWTs and refreshes them before expiry.
|
|
137
|
+
*/
|
|
138
|
+
declare function createInternalClient(config: InternalClientConfig): InternalClient;
|
|
139
|
+
|
|
140
|
+
export { type BootstrapTenantOwnerRequest, type BootstrapTenantOwnerResponse, type GetTenantProfileRequest, InternalClient, type InternalClientConfig, type JwtConfig, type JwtEddsaConfig, type JwtEs256Config, type JwtHmacConfig, type JwtRs256Config, type TenantProfileResponse, createInternalClient, sdkErrors };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
// src/http-client.ts
|
|
2
|
+
import { ok, err } from "ts-micro-result";
|
|
3
|
+
|
|
4
|
+
// src/jwt-signer.ts
|
|
5
|
+
function base64urlEncode(data) {
|
|
6
|
+
let binary = "";
|
|
7
|
+
for (let i = 0; i < data.length; i++) {
|
|
8
|
+
binary += String.fromCharCode(data[i]);
|
|
9
|
+
}
|
|
10
|
+
return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
11
|
+
}
|
|
12
|
+
function hexToUint8Array(hex) {
|
|
13
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
14
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
15
|
+
bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);
|
|
16
|
+
}
|
|
17
|
+
return bytes;
|
|
18
|
+
}
|
|
19
|
+
function parsePemToSpki(pem) {
|
|
20
|
+
const pemBody = pem.replace(/-----BEGIN PRIVATE KEY-----/g, "").replace(/-----END PRIVATE KEY-----/g, "").replace(/\s/g, "");
|
|
21
|
+
const binary = atob(pemBody);
|
|
22
|
+
const bytes = new Uint8Array(binary.length);
|
|
23
|
+
for (let i = 0; i < binary.length; i++) {
|
|
24
|
+
bytes[i] = binary.charCodeAt(i);
|
|
25
|
+
}
|
|
26
|
+
return bytes;
|
|
27
|
+
}
|
|
28
|
+
async function importHmacSigningKey(secret) {
|
|
29
|
+
const encoder = new TextEncoder();
|
|
30
|
+
const keyData = encoder.encode(secret);
|
|
31
|
+
return crypto.subtle.importKey(
|
|
32
|
+
"raw",
|
|
33
|
+
keyData.buffer,
|
|
34
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
35
|
+
false,
|
|
36
|
+
["sign"]
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
async function importEdDSAPrivateKey(privateKey) {
|
|
40
|
+
const keyBytes = typeof privateKey === "string" ? hexToUint8Array(privateKey) : privateKey;
|
|
41
|
+
return crypto.subtle.importKey(
|
|
42
|
+
"raw",
|
|
43
|
+
keyBytes.buffer,
|
|
44
|
+
{ name: "Ed25519" },
|
|
45
|
+
false,
|
|
46
|
+
["sign"]
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
async function importRsaPrivateKey(privateKey) {
|
|
50
|
+
if (typeof privateKey === "object") {
|
|
51
|
+
return crypto.subtle.importKey(
|
|
52
|
+
"jwk",
|
|
53
|
+
privateKey,
|
|
54
|
+
{ name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
|
|
55
|
+
false,
|
|
56
|
+
["sign"]
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
const pkcs8Bytes = parsePemToSpki(privateKey);
|
|
60
|
+
return crypto.subtle.importKey(
|
|
61
|
+
"pkcs8",
|
|
62
|
+
pkcs8Bytes.buffer,
|
|
63
|
+
{ name: "RSASSA-PKCS1-v1_5", hash: "SHA-256" },
|
|
64
|
+
false,
|
|
65
|
+
["sign"]
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
async function importEcdsaPrivateKey(privateKey) {
|
|
69
|
+
if (typeof privateKey === "object") {
|
|
70
|
+
return crypto.subtle.importKey(
|
|
71
|
+
"jwk",
|
|
72
|
+
privateKey,
|
|
73
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
74
|
+
false,
|
|
75
|
+
["sign"]
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
const pkcs8Bytes = parsePemToSpki(privateKey);
|
|
79
|
+
return crypto.subtle.importKey(
|
|
80
|
+
"pkcs8",
|
|
81
|
+
pkcs8Bytes.buffer,
|
|
82
|
+
{ name: "ECDSA", namedCurve: "P-256" },
|
|
83
|
+
false,
|
|
84
|
+
["sign"]
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
async function resolveSignKey(config) {
|
|
88
|
+
const strategy = config.strategy;
|
|
89
|
+
switch (strategy) {
|
|
90
|
+
case "hmac": {
|
|
91
|
+
const c = config;
|
|
92
|
+
return {
|
|
93
|
+
key: await importHmacSigningKey(c.secret),
|
|
94
|
+
jwtAlgorithm: "HS256",
|
|
95
|
+
cryptoAlgorithm: "HMAC"
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
case "eddsa": {
|
|
99
|
+
const c = config;
|
|
100
|
+
return {
|
|
101
|
+
key: await importEdDSAPrivateKey(c.privateKey),
|
|
102
|
+
jwtAlgorithm: "EdDSA",
|
|
103
|
+
cryptoAlgorithm: { name: "Ed25519" }
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
case "rs256": {
|
|
107
|
+
const c = config;
|
|
108
|
+
return {
|
|
109
|
+
key: await importRsaPrivateKey(c.privateKey),
|
|
110
|
+
jwtAlgorithm: "RS256",
|
|
111
|
+
cryptoAlgorithm: "RSASSA-PKCS1-v1_5"
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
case "es256": {
|
|
115
|
+
const c = config;
|
|
116
|
+
return {
|
|
117
|
+
key: await importEcdsaPrivateKey(c.privateKey),
|
|
118
|
+
jwtAlgorithm: "ES256",
|
|
119
|
+
cryptoAlgorithm: { name: "ECDSA", hash: "SHA-256" }
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
var REFRESH_BUFFER_SECONDS = 60;
|
|
125
|
+
var JwtSigner = class {
|
|
126
|
+
constructor(config) {
|
|
127
|
+
this.config = config;
|
|
128
|
+
}
|
|
129
|
+
cachedKeyInfo = null;
|
|
130
|
+
cachedToken = null;
|
|
131
|
+
cachedExp = 0;
|
|
132
|
+
/**
|
|
133
|
+
* Get a valid service JWT token.
|
|
134
|
+
* Automatically signs a new token when the current one is about to expire.
|
|
135
|
+
*/
|
|
136
|
+
async getToken() {
|
|
137
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
138
|
+
if (this.cachedToken && nowSeconds < this.cachedExp - REFRESH_BUFFER_SECONDS) {
|
|
139
|
+
return this.cachedToken;
|
|
140
|
+
}
|
|
141
|
+
return this.signNewToken();
|
|
142
|
+
}
|
|
143
|
+
async signNewToken() {
|
|
144
|
+
const keyInfo = await this.getKeyInfo();
|
|
145
|
+
const encoder = new TextEncoder();
|
|
146
|
+
const expiresInSeconds = this.config.expiresInSeconds ?? 300;
|
|
147
|
+
const nowSeconds = Math.floor(Date.now() / 1e3);
|
|
148
|
+
const header = base64urlEncode(
|
|
149
|
+
encoder.encode(JSON.stringify({ alg: keyInfo.jwtAlgorithm, typ: "JWT" }))
|
|
150
|
+
);
|
|
151
|
+
const payload = {
|
|
152
|
+
iat: nowSeconds,
|
|
153
|
+
exp: nowSeconds + expiresInSeconds
|
|
154
|
+
};
|
|
155
|
+
if (this.config.issuer !== void 0) {
|
|
156
|
+
payload.iss = this.config.issuer;
|
|
157
|
+
}
|
|
158
|
+
if (this.config.audience !== void 0) {
|
|
159
|
+
payload.aud = this.config.audience;
|
|
160
|
+
}
|
|
161
|
+
const payloadB64 = base64urlEncode(encoder.encode(JSON.stringify(payload)));
|
|
162
|
+
const signData = encoder.encode(`${header}.${payloadB64}`);
|
|
163
|
+
const signatureBytes = new Uint8Array(
|
|
164
|
+
await crypto.subtle.sign(
|
|
165
|
+
keyInfo.cryptoAlgorithm,
|
|
166
|
+
keyInfo.key,
|
|
167
|
+
signData.buffer
|
|
168
|
+
)
|
|
169
|
+
);
|
|
170
|
+
const signature = base64urlEncode(signatureBytes);
|
|
171
|
+
const token = `${header}.${payloadB64}.${signature}`;
|
|
172
|
+
this.cachedToken = token;
|
|
173
|
+
this.cachedExp = nowSeconds + expiresInSeconds;
|
|
174
|
+
return token;
|
|
175
|
+
}
|
|
176
|
+
async getKeyInfo() {
|
|
177
|
+
if (!this.cachedKeyInfo) {
|
|
178
|
+
this.cachedKeyInfo = await resolveSignKey(this.config);
|
|
179
|
+
}
|
|
180
|
+
return this.cachedKeyInfo;
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// src/errors.ts
|
|
185
|
+
import { defineError } from "ts-micro-result";
|
|
186
|
+
var sdkErrors = {
|
|
187
|
+
NETWORK_ERROR: defineError("SDK_NETWORK_ERROR", "Network request failed"),
|
|
188
|
+
TIMEOUT: defineError("SDK_TIMEOUT", "Request timed out"),
|
|
189
|
+
INVALID_RESPONSE: defineError("SDK_INVALID_RESPONSE", "Invalid response from auth service"),
|
|
190
|
+
JWT_SIGN_FAILED: defineError("SDK_JWT_SIGN_FAILED", "Failed to sign service JWT")
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
// src/http-client.ts
|
|
194
|
+
var HttpClient = class {
|
|
195
|
+
signer;
|
|
196
|
+
baseUrl;
|
|
197
|
+
basePath;
|
|
198
|
+
fetchFn;
|
|
199
|
+
timeout;
|
|
200
|
+
customHeaders;
|
|
201
|
+
constructor(config) {
|
|
202
|
+
this.signer = new JwtSigner(config.jwt);
|
|
203
|
+
this.baseUrl = config.baseUrl.replace(/\/$/, "");
|
|
204
|
+
this.basePath = config.basePath ?? "";
|
|
205
|
+
this.fetchFn = config.fetchImpl ?? globalThis.fetch;
|
|
206
|
+
this.timeout = config.timeout ?? 3e4;
|
|
207
|
+
this.customHeaders = config.headers ?? {};
|
|
208
|
+
}
|
|
209
|
+
async request(method, path, options) {
|
|
210
|
+
try {
|
|
211
|
+
let token;
|
|
212
|
+
try {
|
|
213
|
+
token = await this.signer.getToken();
|
|
214
|
+
} catch (signError) {
|
|
215
|
+
const message = signError instanceof Error ? signError.message : String(signError);
|
|
216
|
+
return err(sdkErrors.JWT_SIGN_FAILED({ message }));
|
|
217
|
+
}
|
|
218
|
+
const url = this.buildUrl(path, options?.query);
|
|
219
|
+
const headers = {
|
|
220
|
+
"Content-Type": "application/json",
|
|
221
|
+
"Authorization": `Bearer ${token}`,
|
|
222
|
+
...this.customHeaders
|
|
223
|
+
};
|
|
224
|
+
const controller = new AbortController();
|
|
225
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
226
|
+
let response;
|
|
227
|
+
try {
|
|
228
|
+
response = await this.fetchFn(url, {
|
|
229
|
+
method,
|
|
230
|
+
headers,
|
|
231
|
+
body: options?.body !== void 0 ? JSON.stringify(options.body) : void 0,
|
|
232
|
+
signal: controller.signal
|
|
233
|
+
});
|
|
234
|
+
} finally {
|
|
235
|
+
clearTimeout(timeoutId);
|
|
236
|
+
}
|
|
237
|
+
let envelope;
|
|
238
|
+
try {
|
|
239
|
+
envelope = await response.json();
|
|
240
|
+
} catch {
|
|
241
|
+
return err(
|
|
242
|
+
sdkErrors.INVALID_RESPONSE({ message: `HTTP ${response.status}: non-JSON response` }),
|
|
243
|
+
void 0,
|
|
244
|
+
response.status
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
if (envelope.ok && envelope.data !== void 0) {
|
|
248
|
+
return ok(envelope.data, envelope.meta);
|
|
249
|
+
}
|
|
250
|
+
const errors = envelope.errors ?? [{ code: "UNKNOWN_ERROR", message: `HTTP ${response.status}` }];
|
|
251
|
+
return err(errors, envelope.meta, response.status);
|
|
252
|
+
} catch (error) {
|
|
253
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
254
|
+
return err(sdkErrors.TIMEOUT({ message: `Request timed out after ${this.timeout}ms` }), void 0, 408);
|
|
255
|
+
}
|
|
256
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
257
|
+
return err(sdkErrors.NETWORK_ERROR({ message }), void 0, 0);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
buildUrl(path, query) {
|
|
261
|
+
let url = `${this.baseUrl}${this.basePath}/internal${path}`;
|
|
262
|
+
if (query) {
|
|
263
|
+
const entries = Object.entries(query).filter(([, v]) => v !== void 0);
|
|
264
|
+
if (entries.length > 0) {
|
|
265
|
+
const params = new URLSearchParams(entries);
|
|
266
|
+
url += `?${params.toString()}`;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return url;
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
// src/client.ts
|
|
274
|
+
var InternalClient = class {
|
|
275
|
+
http;
|
|
276
|
+
constructor(config) {
|
|
277
|
+
this.http = new HttpClient(config);
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Bootstrap tenant owner (assign owner role to a user for a new tenant).
|
|
281
|
+
* Typically called by tenant-provisioning service after creating a tenant.
|
|
282
|
+
*/
|
|
283
|
+
async bootstrapTenantOwner(request) {
|
|
284
|
+
return this.http.request(
|
|
285
|
+
"POST",
|
|
286
|
+
"/tenant/bootstrap-owner",
|
|
287
|
+
{ body: request }
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Get per-tenant user profile (internal).
|
|
292
|
+
* Allows services to read tenant profiles without user authentication.
|
|
293
|
+
*/
|
|
294
|
+
async getTenantProfile(request) {
|
|
295
|
+
return this.http.request(
|
|
296
|
+
"GET",
|
|
297
|
+
"/tenant/profile",
|
|
298
|
+
{
|
|
299
|
+
query: {
|
|
300
|
+
tenantId: request.tenantId,
|
|
301
|
+
userId: request.userId
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
// src/index.ts
|
|
309
|
+
function createInternalClient(config) {
|
|
310
|
+
return new InternalClient(config);
|
|
311
|
+
}
|
|
312
|
+
export {
|
|
313
|
+
InternalClient,
|
|
314
|
+
createInternalClient,
|
|
315
|
+
sdkErrors
|
|
316
|
+
};
|
|
317
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/http-client.ts","../src/jwt-signer.ts","../src/errors.ts","../src/client.ts","../src/index.ts"],"sourcesContent":["/**\r\n * Low-level HTTP Client\r\n * Wraps fetch with JWT auth, timeout, and Result<T> mapping.\r\n */\r\n\r\nimport { ok, err } from 'ts-micro-result';\r\nimport type { Result } from 'ts-micro-result';\r\nimport type { InternalClientConfig, ApiResponseEnvelope } from './types';\r\nimport { JwtSigner } from './jwt-signer';\r\nimport { sdkErrors } from './errors';\r\n\r\ntype HttpMethod = 'GET' | 'POST' | 'PATCH' | 'DELETE';\r\n\r\nexport class HttpClient {\r\n private readonly signer: JwtSigner;\r\n private readonly baseUrl: string;\r\n private readonly basePath: string;\r\n private readonly fetchFn: typeof fetch;\r\n private readonly timeout: number;\r\n private readonly customHeaders: Record<string, string>;\r\n\r\n constructor(config: InternalClientConfig) {\r\n this.signer = new JwtSigner(config.jwt);\r\n this.baseUrl = config.baseUrl.replace(/\\/$/, '');\r\n this.basePath = config.basePath ?? '';\r\n this.fetchFn = config.fetchImpl ?? globalThis.fetch;\r\n this.timeout = config.timeout ?? 30000;\r\n this.customHeaders = config.headers ?? {};\r\n }\r\n\r\n async request<T>(\r\n method: HttpMethod,\r\n path: string,\r\n options?: {\r\n body?: unknown;\r\n query?: Record<string, string>;\r\n }\r\n ): Promise<Result<T>> {\r\n try {\r\n // Get service JWT\r\n let token: string;\r\n try {\r\n token = await this.signer.getToken();\r\n } catch (signError) {\r\n const message = signError instanceof Error ? signError.message : String(signError);\r\n return err(sdkErrors.JWT_SIGN_FAILED({ message }));\r\n }\r\n\r\n // Build URL\r\n const url = this.buildUrl(path, options?.query);\r\n\r\n // Build headers\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n 'Authorization': `Bearer ${token}`,\r\n ...this.customHeaders,\r\n };\r\n\r\n // Timeout\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\r\n\r\n // Make request\r\n let response: Response;\r\n try {\r\n response = await this.fetchFn(url, {\r\n method,\r\n headers,\r\n body: options?.body !== undefined ? JSON.stringify(options.body) : undefined,\r\n signal: controller.signal,\r\n });\r\n } finally {\r\n clearTimeout(timeoutId);\r\n }\r\n\r\n // Parse response\r\n let envelope: ApiResponseEnvelope<T>;\r\n try {\r\n envelope = await response.json() as ApiResponseEnvelope<T>;\r\n } catch {\r\n return err(\r\n sdkErrors.INVALID_RESPONSE({ message: `HTTP ${response.status}: non-JSON response` }),\r\n undefined,\r\n response.status\r\n );\r\n }\r\n\r\n // Map to Result\r\n if (envelope.ok && envelope.data !== undefined) {\r\n return ok(envelope.data, envelope.meta);\r\n }\r\n\r\n const errors = envelope.errors ?? [{ code: 'UNKNOWN_ERROR', message: `HTTP ${response.status}` }];\r\n return err(errors, envelope.meta, response.status);\r\n\r\n } catch (error) {\r\n if (error instanceof Error && error.name === 'AbortError') {\r\n return err(sdkErrors.TIMEOUT({ message: `Request timed out after ${this.timeout}ms` }), undefined, 408);\r\n }\r\n\r\n const message = error instanceof Error ? error.message : String(error);\r\n return err(sdkErrors.NETWORK_ERROR({ message }), undefined, 0);\r\n }\r\n }\r\n\r\n private buildUrl(path: string, query?: Record<string, string>): string {\r\n let url = `${this.baseUrl}${this.basePath}/internal${path}`;\r\n\r\n if (query) {\r\n const entries = Object.entries(query).filter(([, v]) => v !== undefined);\r\n if (entries.length > 0) {\r\n const params = new URLSearchParams(entries);\r\n url += `?${params.toString()}`;\r\n }\r\n }\r\n\r\n return url;\r\n }\r\n}\r\n","/**\r\n * Service JWT Signer\r\n * Creates and auto-refreshes JWTs for service-to-service authentication.\r\n * Uses Web Crypto API for edge compatibility — zero dependencies.\r\n *\r\n * Reuses pattern from auth-http-core/middleware/internal-auth.ts\r\n */\r\n\r\nimport type { JwtConfig, JwtHmacConfig, JwtEddsaConfig, JwtRs256Config, JwtEs256Config } from './types';\r\n\r\n// ============================================================\r\n// Base64url helpers\r\n// ============================================================\r\n\r\nfunction base64urlEncode(data: Uint8Array): string {\r\n let binary = '';\r\n for (let i = 0; i < data.length; i++) {\r\n binary += String.fromCharCode(data[i]!);\r\n }\r\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\r\n}\r\n\r\nfunction hexToUint8Array(hex: string): Uint8Array {\r\n const bytes = new Uint8Array(hex.length / 2);\r\n for (let i = 0; i < hex.length; i += 2) {\r\n bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);\r\n }\r\n return bytes;\r\n}\r\n\r\nfunction parsePemToSpki(pem: string): Uint8Array {\r\n const pemBody = pem\r\n .replace(/-----BEGIN PRIVATE KEY-----/g, '')\r\n .replace(/-----END PRIVATE KEY-----/g, '')\r\n .replace(/\\s/g, '');\r\n\r\n const binary = atob(pemBody);\r\n const bytes = new Uint8Array(binary.length);\r\n for (let i = 0; i < binary.length; i++) {\r\n bytes[i] = binary.charCodeAt(i);\r\n }\r\n return bytes;\r\n}\r\n\r\n// ============================================================\r\n// Key import helpers (Web Crypto API)\r\n// ============================================================\r\n\r\nasync function importHmacSigningKey(secret: string): Promise<CryptoKey> {\r\n const encoder = new TextEncoder();\r\n const keyData = encoder.encode(secret);\r\n return crypto.subtle.importKey(\r\n 'raw',\r\n keyData.buffer as ArrayBuffer,\r\n { name: 'HMAC', hash: 'SHA-256' },\r\n false,\r\n ['sign']\r\n );\r\n}\r\n\r\nasync function importEdDSAPrivateKey(privateKey: string | Uint8Array): Promise<CryptoKey> {\r\n const keyBytes = typeof privateKey === 'string'\r\n ? hexToUint8Array(privateKey)\r\n : privateKey;\r\n\r\n return crypto.subtle.importKey(\r\n 'raw',\r\n keyBytes.buffer as ArrayBuffer,\r\n { name: 'Ed25519' } as Algorithm,\r\n false,\r\n ['sign']\r\n );\r\n}\r\n\r\nasync function importRsaPrivateKey(privateKey: string | JsonWebKey): Promise<CryptoKey> {\r\n if (typeof privateKey === 'object') {\r\n return crypto.subtle.importKey(\r\n 'jwk',\r\n privateKey,\r\n { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' },\r\n false,\r\n ['sign']\r\n );\r\n }\r\n\r\n const pkcs8Bytes = parsePemToSpki(privateKey);\r\n return crypto.subtle.importKey(\r\n 'pkcs8',\r\n pkcs8Bytes.buffer as ArrayBuffer,\r\n { name: 'RSASSA-PKCS1-v1_5', hash: 'SHA-256' },\r\n false,\r\n ['sign']\r\n );\r\n}\r\n\r\nasync function importEcdsaPrivateKey(privateKey: string | JsonWebKey): Promise<CryptoKey> {\r\n if (typeof privateKey === 'object') {\r\n return crypto.subtle.importKey(\r\n 'jwk',\r\n privateKey,\r\n { name: 'ECDSA', namedCurve: 'P-256' },\r\n false,\r\n ['sign']\r\n );\r\n }\r\n\r\n const pkcs8Bytes = parsePemToSpki(privateKey);\r\n return crypto.subtle.importKey(\r\n 'pkcs8',\r\n pkcs8Bytes.buffer as ArrayBuffer,\r\n { name: 'ECDSA', namedCurve: 'P-256' },\r\n false,\r\n ['sign']\r\n );\r\n}\r\n\r\n// ============================================================\r\n// Sign key info\r\n// ============================================================\r\n\r\ninterface SignKeyInfo {\r\n key: CryptoKey;\r\n jwtAlgorithm: string;\r\n cryptoAlgorithm: AlgorithmIdentifier;\r\n}\r\n\r\nasync function resolveSignKey(config: JwtConfig): Promise<SignKeyInfo> {\r\n const strategy = config.strategy;\r\n\r\n switch (strategy) {\r\n case 'hmac': {\r\n const c = config as JwtHmacConfig;\r\n return {\r\n key: await importHmacSigningKey(c.secret),\r\n jwtAlgorithm: 'HS256',\r\n cryptoAlgorithm: 'HMAC',\r\n };\r\n }\r\n case 'eddsa': {\r\n const c = config as JwtEddsaConfig;\r\n return {\r\n key: await importEdDSAPrivateKey(c.privateKey),\r\n jwtAlgorithm: 'EdDSA',\r\n cryptoAlgorithm: { name: 'Ed25519' } as Algorithm,\r\n };\r\n }\r\n case 'rs256': {\r\n const c = config as JwtRs256Config;\r\n return {\r\n key: await importRsaPrivateKey(c.privateKey),\r\n jwtAlgorithm: 'RS256',\r\n cryptoAlgorithm: 'RSASSA-PKCS1-v1_5',\r\n };\r\n }\r\n case 'es256': {\r\n const c = config as JwtEs256Config;\r\n return {\r\n key: await importEcdsaPrivateKey(c.privateKey),\r\n jwtAlgorithm: 'ES256',\r\n cryptoAlgorithm: { name: 'ECDSA', hash: 'SHA-256' } as EcdsaParams,\r\n };\r\n }\r\n }\r\n}\r\n\r\n// ============================================================\r\n// JWT Signer\r\n// ============================================================\r\n\r\n/** Minimum remaining TTL (seconds) before auto-refreshing the token */\r\nconst REFRESH_BUFFER_SECONDS = 60;\r\n\r\nexport class JwtSigner {\r\n private cachedKeyInfo: SignKeyInfo | null = null;\r\n private cachedToken: string | null = null;\r\n private cachedExp: number = 0;\r\n\r\n constructor(private readonly config: JwtConfig) {}\r\n\r\n /**\r\n * Get a valid service JWT token.\r\n * Automatically signs a new token when the current one is about to expire.\r\n */\r\n async getToken(): Promise<string> {\r\n const nowSeconds = Math.floor(Date.now() / 1000);\r\n\r\n // Return cached token if still valid (with buffer)\r\n if (this.cachedToken && nowSeconds < this.cachedExp - REFRESH_BUFFER_SECONDS) {\r\n return this.cachedToken;\r\n }\r\n\r\n // Sign new token\r\n return this.signNewToken();\r\n }\r\n\r\n private async signNewToken(): Promise<string> {\r\n const keyInfo = await this.getKeyInfo();\r\n const encoder = new TextEncoder();\r\n const expiresInSeconds = this.config.expiresInSeconds ?? 300;\r\n const nowSeconds = Math.floor(Date.now() / 1000);\r\n\r\n // Header\r\n const header = base64urlEncode(\r\n encoder.encode(JSON.stringify({ alg: keyInfo.jwtAlgorithm, typ: 'JWT' }))\r\n );\r\n\r\n // Payload\r\n const payload: Record<string, unknown> = {\r\n iat: nowSeconds,\r\n exp: nowSeconds + expiresInSeconds,\r\n };\r\n\r\n if (this.config.issuer !== undefined) {\r\n payload.iss = this.config.issuer;\r\n }\r\n if (this.config.audience !== undefined) {\r\n payload.aud = this.config.audience;\r\n }\r\n\r\n const payloadB64 = base64urlEncode(encoder.encode(JSON.stringify(payload)));\r\n\r\n // Sign\r\n const signData = encoder.encode(`${header}.${payloadB64}`);\r\n const signatureBytes = new Uint8Array(\r\n await crypto.subtle.sign(\r\n keyInfo.cryptoAlgorithm,\r\n keyInfo.key,\r\n signData.buffer as ArrayBuffer\r\n )\r\n );\r\n const signature = base64urlEncode(signatureBytes);\r\n\r\n const token = `${header}.${payloadB64}.${signature}`;\r\n\r\n // Cache\r\n this.cachedToken = token;\r\n this.cachedExp = nowSeconds + expiresInSeconds;\r\n\r\n return token;\r\n }\r\n\r\n private async getKeyInfo(): Promise<SignKeyInfo> {\r\n if (!this.cachedKeyInfo) {\r\n this.cachedKeyInfo = await resolveSignKey(this.config);\r\n }\r\n return this.cachedKeyInfo;\r\n }\r\n}\r\n","/**\r\n * Backend SDK Error Definitions\r\n */\r\n\r\nimport { defineError } from 'ts-micro-result';\r\n\r\nexport const sdkErrors = {\r\n NETWORK_ERROR: defineError('SDK_NETWORK_ERROR', 'Network request failed'),\r\n TIMEOUT: defineError('SDK_TIMEOUT', 'Request timed out'),\r\n INVALID_RESPONSE: defineError('SDK_INVALID_RESPONSE', 'Invalid response from auth service'),\r\n JWT_SIGN_FAILED: defineError('SDK_JWT_SIGN_FAILED', 'Failed to sign service JWT'),\r\n} as const;\r\n","/**\r\n * Internal Client\r\n * Type-safe client for auth service internal (service-to-service) API.\r\n */\r\n\r\nimport type { Result } from 'ts-micro-result';\r\nimport type {\r\n InternalClientConfig,\r\n BootstrapTenantOwnerRequest,\r\n BootstrapTenantOwnerResponse,\r\n GetTenantProfileRequest,\r\n TenantProfileResponse,\r\n} from './types';\r\nimport { HttpClient } from './http-client';\r\n\r\nexport class InternalClient {\r\n private readonly http: HttpClient;\r\n\r\n constructor(config: InternalClientConfig) {\r\n this.http = new HttpClient(config);\r\n }\r\n\r\n /**\r\n * Bootstrap tenant owner (assign owner role to a user for a new tenant).\r\n * Typically called by tenant-provisioning service after creating a tenant.\r\n */\r\n async bootstrapTenantOwner(\r\n request: BootstrapTenantOwnerRequest\r\n ): Promise<Result<BootstrapTenantOwnerResponse>> {\r\n return this.http.request<BootstrapTenantOwnerResponse>(\r\n 'POST',\r\n '/tenant/bootstrap-owner',\r\n { body: request }\r\n );\r\n }\r\n\r\n /**\r\n * Get per-tenant user profile (internal).\r\n * Allows services to read tenant profiles without user authentication.\r\n */\r\n async getTenantProfile(\r\n request: GetTenantProfileRequest\r\n ): Promise<Result<TenantProfileResponse>> {\r\n return this.http.request<TenantProfileResponse>(\r\n 'GET',\r\n '/tenant/profile',\r\n {\r\n query: {\r\n tenantId: request.tenantId,\r\n userId: request.userId,\r\n },\r\n }\r\n );\r\n }\r\n}\r\n","/**\r\n * @auth-craft/backend-sdk\r\n * Type-safe internal service SDK for Auth-Craft service-to-service calls.\r\n *\r\n * @example\r\n * ```ts\r\n * import { createInternalClient } from '@auth-craft/backend-sdk';\r\n *\r\n * const client = createInternalClient({\r\n * baseUrl: 'https://auth.example.com',\r\n * basePath: '/system',\r\n * jwt: {\r\n * strategy: 'hmac',\r\n * secret: process.env.INTERNAL_JWT_SECRET!,\r\n * issuer: 'tenant-provisioning-service',\r\n * },\r\n * });\r\n *\r\n * const result = await client.bootstrapTenantOwner({ tenantId, userId });\r\n * ```\r\n */\r\n\r\nimport { InternalClient } from './client';\r\nimport type { InternalClientConfig } from './types';\r\n\r\n/**\r\n * Create an internal service client for Auth-Craft.\r\n *\r\n * The client auto-signs service JWTs and refreshes them before expiry.\r\n */\r\nexport function createInternalClient(config: InternalClientConfig): InternalClient {\r\n return new InternalClient(config);\r\n}\r\n\r\n// Explicit type exports\r\nexport type {\r\n InternalClientConfig,\r\n JwtConfig,\r\n JwtHmacConfig,\r\n JwtEddsaConfig,\r\n JwtRs256Config,\r\n JwtEs256Config,\r\n BootstrapTenantOwnerRequest,\r\n BootstrapTenantOwnerResponse,\r\n GetTenantProfileRequest,\r\n TenantProfileResponse,\r\n} from './types';\r\n\r\nexport { InternalClient } from './client';\r\nexport { sdkErrors } from './errors';\r\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@auth-craft/backend-sdk",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Type-safe internal service SDK for Auth-Craft service-to-service calls",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"sideEffects": false,
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsup",
|
|
19
|
+
"type-check": "tsc --noEmit",
|
|
20
|
+
"dev": "tsup --watch"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"ts-micro-result": "^3.3.0"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@auth-craft/tsup-config": "workspace:*",
|
|
30
|
+
"typescript": "^5.9.3"
|
|
31
|
+
}
|
|
32
|
+
}
|