authmi 1.0.0

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.
@@ -0,0 +1,31 @@
1
+ export { A as ApiKey, a as AuthMiClient, b as AuthMiConfig, c as AuthMiError, d as AuthToken, C as CreateApiKeyRequest, e as CreateApiKeyResponse, f as CreateScopeRequest, g as CreateUserRequest, I as IntrospectRequest, h as IntrospectResponse, L as LocalStorageTokenStorage, i as LoginCredentials, M as MemoryTokenStorage, O as OAuthCallbackResult, j as OAuthInitiateResponse, k as OAuthProvider, l as OnboardRequest, m as OnboardResponse, R as RegisterWebhookRequest, S as Scope, n as ScopeError, o as Service, T as TokenStorage, U as User, p as UserListResponse, V as ValidationResult, W as Webhook } from './client-D6JiIhlU.js';
2
+
3
+ /**
4
+ * Auth Mi Client
5
+ *
6
+ * Official client library for Auth Mi - Multi-tenant authentication-as-a-service
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { AuthMiClient } from "authmi";
11
+ *
12
+ * const client = new AuthMiClient({
13
+ * baseUrl: "https://authmi.dev",
14
+ * serviceId: "svc-xxx",
15
+ * apiKey: "ak-xxx",
16
+ * });
17
+ *
18
+ * // Login
19
+ * const token = await client.login({
20
+ * email: "user@example.com",
21
+ * password: "password123",
22
+ * });
23
+ *
24
+ * // Validate token
25
+ * const isValid = await client.validate();
26
+ * ```
27
+ */
28
+
29
+ declare const VERSION = "1.0.0";
30
+
31
+ export { VERSION };
package/dist/index.js ADDED
@@ -0,0 +1,609 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ AuthMiClient: () => AuthMiClient,
24
+ AuthMiError: () => AuthMiError,
25
+ LocalStorageTokenStorage: () => LocalStorageTokenStorage,
26
+ MemoryTokenStorage: () => MemoryTokenStorage,
27
+ ScopeError: () => ScopeError,
28
+ VERSION: () => VERSION
29
+ });
30
+ module.exports = __toCommonJS(index_exports);
31
+
32
+ // src/types.ts
33
+ var AuthMiError = class extends Error {
34
+ constructor(message, code, statusCode) {
35
+ super(message);
36
+ this.code = code;
37
+ this.statusCode = statusCode;
38
+ this.name = "AuthMiError";
39
+ }
40
+ };
41
+ var ScopeError = class extends AuthMiError {
42
+ constructor(message, requiredScopes, providedScopes) {
43
+ super(message, "INSUFFICIENT_SCOPES", 403);
44
+ this.requiredScopes = requiredScopes;
45
+ this.providedScopes = providedScopes;
46
+ this.name = "ScopeError";
47
+ }
48
+ };
49
+ var _LocalStorageTokenStorage = class _LocalStorageTokenStorage {
50
+ getToken() {
51
+ if (typeof window === "undefined") return null;
52
+ return localStorage.getItem(_LocalStorageTokenStorage.KEY);
53
+ }
54
+ setToken(token) {
55
+ if (typeof window === "undefined") return;
56
+ localStorage.setItem(_LocalStorageTokenStorage.KEY, token);
57
+ }
58
+ removeToken() {
59
+ if (typeof window === "undefined") return;
60
+ localStorage.removeItem(_LocalStorageTokenStorage.KEY);
61
+ }
62
+ };
63
+ _LocalStorageTokenStorage.KEY = "authmi_token";
64
+ var LocalStorageTokenStorage = _LocalStorageTokenStorage;
65
+ var MemoryTokenStorage = class {
66
+ constructor() {
67
+ this.token = null;
68
+ }
69
+ getToken() {
70
+ return this.token;
71
+ }
72
+ setToken(token) {
73
+ this.token = token;
74
+ }
75
+ removeToken() {
76
+ this.token = null;
77
+ }
78
+ };
79
+
80
+ // src/client.ts
81
+ var AuthMiClient = class {
82
+ constructor(config, tokenStorage) {
83
+ this.config = {
84
+ apiKey: "",
85
+ serviceId: "",
86
+ clientId: "",
87
+ clientSecret: "",
88
+ defaultTokenExpiry: 24,
89
+ ...config
90
+ };
91
+ this.tokenStorage = tokenStorage || new LocalStorageTokenStorage();
92
+ }
93
+ /** Build Basic auth header from clientId:clientSecret */
94
+ basicAuthHeader() {
95
+ if (this.config.clientId && this.config.clientSecret) {
96
+ const encoded = btoa(`${this.config.clientId}:${this.config.clientSecret}`);
97
+ return `Basic ${encoded}`;
98
+ }
99
+ return null;
100
+ }
101
+ // ============ HTTP Utilities ============
102
+ async request(endpoint, options = {}, requireAuth = false) {
103
+ const url = `${this.config.baseUrl}${endpoint}`;
104
+ const headers = {
105
+ "Content-Type": "application/json",
106
+ ...options.headers || {}
107
+ };
108
+ const basic = this.basicAuthHeader();
109
+ if (basic && !requireAuth && !headers["Authorization"]) {
110
+ headers["Authorization"] = basic;
111
+ } else if (this.config.apiKey && !requireAuth && !headers["Authorization"]) {
112
+ headers["Authorization"] = `Bearer ${this.config.apiKey}`;
113
+ }
114
+ if (requireAuth) {
115
+ const token = this.getAccessToken();
116
+ if (token && !headers["Authorization"]) {
117
+ headers["Authorization"] = `Bearer ${token}`;
118
+ }
119
+ }
120
+ try {
121
+ const response = await fetch(url, {
122
+ ...options,
123
+ headers
124
+ });
125
+ const data = await response.json();
126
+ if (!response.ok) {
127
+ if (response.status === 403 && data.required && data.provided) {
128
+ throw new ScopeError(
129
+ data.error || "Insufficient scopes",
130
+ data.required,
131
+ data.provided
132
+ );
133
+ }
134
+ throw new AuthMiError(
135
+ data.error || `HTTP ${response.status}`,
136
+ data.code || "UNKNOWN_ERROR",
137
+ response.status
138
+ );
139
+ }
140
+ return data;
141
+ } catch (error) {
142
+ if (error instanceof AuthMiError) {
143
+ throw error;
144
+ }
145
+ throw new AuthMiError(
146
+ error instanceof Error ? error.message : "Network error",
147
+ "NETWORK_ERROR"
148
+ );
149
+ }
150
+ }
151
+ // ============ Configuration ============
152
+ /**
153
+ * Update the client's service configuration
154
+ */
155
+ configure(config) {
156
+ this.config = { ...this.config, ...config };
157
+ }
158
+ /**
159
+ * Get current configuration (without sensitive data)
160
+ */
161
+ getConfig() {
162
+ const { apiKey: _, clientSecret: __, ...rest } = this.config;
163
+ return rest;
164
+ }
165
+ // ============ Token Management ============
166
+ /**
167
+ * Get the stored access token
168
+ */
169
+ getAccessToken() {
170
+ return this.tokenStorage.getToken();
171
+ }
172
+ /**
173
+ * Store an access token
174
+ */
175
+ setAccessToken(token) {
176
+ this.tokenStorage.setToken(token);
177
+ }
178
+ /**
179
+ * Remove the stored access token (logout)
180
+ */
181
+ clearAccessToken() {
182
+ this.tokenStorage.removeToken();
183
+ }
184
+ /**
185
+ * Check if user is logged in
186
+ */
187
+ isLoggedIn() {
188
+ return !!this.getAccessToken();
189
+ }
190
+ // ============ Scope Validation ============
191
+ /**
192
+ * Introspect a token or API key and validate required scopes
193
+ */
194
+ async introspect(request) {
195
+ return this.request("/api/v1/introspect", {
196
+ method: "POST",
197
+ body: JSON.stringify(request)
198
+ });
199
+ }
200
+ /**
201
+ * Validate the current token with optional scope checking
202
+ */
203
+ async validateWithScopes(requiredScopes) {
204
+ const token = this.getAccessToken();
205
+ if (!token) {
206
+ return { valid: false, error: "No token provided" };
207
+ }
208
+ if (!this.config.apiKey && !this.config.clientSecret) {
209
+ return { valid: false, error: "Service credentials not configured" };
210
+ }
211
+ if (!this.config.serviceId) {
212
+ return { valid: false, error: "Service ID not configured in AuthMiConfig" };
213
+ }
214
+ try {
215
+ const result = await this.introspect({
216
+ serviceId: this.config.serviceId,
217
+ token,
218
+ requiredScopes
219
+ });
220
+ return {
221
+ valid: result.valid,
222
+ type: result.type === "bearer" ? "token" : "api_key",
223
+ scopes: result.scopes,
224
+ userId: result.userId,
225
+ email: result.email,
226
+ error: result.error
227
+ };
228
+ } catch (error) {
229
+ if (error instanceof ScopeError) {
230
+ return {
231
+ valid: false,
232
+ error: error.message,
233
+ scopes: error.providedScopes
234
+ };
235
+ }
236
+ if (error instanceof AuthMiError && error.statusCode === 401) {
237
+ return { valid: false, error: "Invalid or expired token" };
238
+ }
239
+ throw error;
240
+ }
241
+ }
242
+ /**
243
+ * Check if the current user has all the required scopes
244
+ * Throws ScopeError if scopes are insufficient
245
+ */
246
+ async requireScopes(...requiredScopes) {
247
+ const result = await this.validateWithScopes(requiredScopes);
248
+ if (!result.valid) {
249
+ throw new AuthMiError(
250
+ result.error || "Authentication required",
251
+ "UNAUTHORIZED",
252
+ 401
253
+ );
254
+ }
255
+ const hasScopes = requiredScopes.every(
256
+ (scope) => result.scopes?.includes(scope)
257
+ );
258
+ if (!hasScopes) {
259
+ throw new ScopeError(
260
+ `Required scopes: ${requiredScopes.join(", ")}`,
261
+ requiredScopes,
262
+ result.scopes || []
263
+ );
264
+ }
265
+ return result;
266
+ }
267
+ /**
268
+ * Execute a function only if the user has the required scopes
269
+ */
270
+ async withScope(scopes, fn) {
271
+ await this.requireScopes(...scopes);
272
+ return fn();
273
+ }
274
+ // ============ OAuth ============
275
+ /**
276
+ * Initiate OAuth login flow and return the authorization URL
277
+ */
278
+ async initiateOAuth(provider, redirectUri) {
279
+ if (!this.config.apiKey && !this.config.clientSecret) {
280
+ throw new AuthMiError(
281
+ "API key or client credentials required for OAuth. Configure the client first.",
282
+ "MISSING_CREDENTIALS"
283
+ );
284
+ }
285
+ if (!this.config.serviceId) {
286
+ throw new AuthMiError(
287
+ "serviceId required for OAuth. Configure the client first.",
288
+ "MISSING_SERVICE_ID"
289
+ );
290
+ }
291
+ const response = await this.request(
292
+ "/api/v1/auth/oauth/initiate",
293
+ {
294
+ method: "POST",
295
+ body: JSON.stringify({ provider, redirectUri, client_id: this.config.serviceId })
296
+ }
297
+ );
298
+ return response.url;
299
+ }
300
+ /**
301
+ * Handle OAuth callback URL and store the access token
302
+ * Returns null if no OAuth params are present in the URL
303
+ */
304
+ handleOAuthCallback(url) {
305
+ const parsedUrl = typeof url === "string" ? new URL(url) : url;
306
+ const token = parsedUrl.searchParams.get("token");
307
+ const userId = parsedUrl.searchParams.get("user_id");
308
+ const email = parsedUrl.searchParams.get("email");
309
+ if (!token || !userId || !email) {
310
+ return null;
311
+ }
312
+ this.setAccessToken(token);
313
+ return { token, userId, email };
314
+ }
315
+ /**
316
+ * Check if the current URL contains OAuth callback params
317
+ */
318
+ isOAuthCallback(url) {
319
+ const parsedUrl = typeof url === "string" ? new URL(url) : url;
320
+ return parsedUrl.searchParams.has("token") && parsedUrl.searchParams.has("user_id") && parsedUrl.searchParams.has("email");
321
+ }
322
+ // ============ Authentication ============
323
+ /**
324
+ * Login a user and store the access token
325
+ */
326
+ async login(credentials) {
327
+ if (!this.config.apiKey && !this.config.clientSecret) {
328
+ throw new AuthMiError(
329
+ "API key or client credentials required for login. Configure the client first.",
330
+ "MISSING_CREDENTIALS"
331
+ );
332
+ }
333
+ const response = await this.request("/api/v1/auth/login", {
334
+ method: "POST",
335
+ body: JSON.stringify({
336
+ email: credentials.email,
337
+ password: credentials.password,
338
+ client_id: this.config.serviceId,
339
+ expires_in_hours: credentials.expiresInHours || this.config.defaultTokenExpiry,
340
+ scopes: credentials.scopes
341
+ })
342
+ });
343
+ const token = {
344
+ accessToken: response.access_token,
345
+ tokenType: response.token_type,
346
+ expiresIn: response.expires_in,
347
+ expiresAt: response.expires_at,
348
+ userId: response.user_id,
349
+ email: response.email,
350
+ scopes: response.scopes
351
+ };
352
+ this.setAccessToken(token.accessToken);
353
+ return token;
354
+ }
355
+ /**
356
+ * Logout the current user
357
+ */
358
+ async logout() {
359
+ const token = this.getAccessToken();
360
+ if (token) {
361
+ try {
362
+ await this.request("/api/v1/auth/logout", {
363
+ method: "POST"
364
+ }, true);
365
+ } catch (error) {
366
+ }
367
+ }
368
+ this.clearAccessToken();
369
+ }
370
+ /**
371
+ * Validate the current token or an API key
372
+ * @deprecated Use validateWithScopes instead
373
+ */
374
+ async validate(_credential) {
375
+ return this.validateWithScopes();
376
+ }
377
+ /**
378
+ * Refresh the current token
379
+ */
380
+ async refreshToken() {
381
+ const response = await this.request("/api/v1/auth/refresh", {
382
+ method: "POST"
383
+ }, true);
384
+ const token = {
385
+ accessToken: response.access_token,
386
+ tokenType: response.token_type,
387
+ expiresIn: response.expires_in,
388
+ expiresAt: response.expires_at,
389
+ userId: "",
390
+ // Refresh doesn't return user info
391
+ email: ""
392
+ };
393
+ this.setAccessToken(token.accessToken);
394
+ return token;
395
+ }
396
+ // ============ User Management ============
397
+ /**
398
+ * Create a new user (requires admin API key)
399
+ */
400
+ async createUser(request) {
401
+ const response = await this.request("/api/v1/users/create", {
402
+ method: "POST",
403
+ body: JSON.stringify(request)
404
+ });
405
+ return {
406
+ userId: response.user_id,
407
+ email: response.email,
408
+ createdAt: response.created_at
409
+ };
410
+ }
411
+ /**
412
+ * List all users for the service
413
+ */
414
+ async listUsers() {
415
+ const response = await this.request("/api/v1/users/list");
416
+ return response.users.map((u) => ({
417
+ userId: u.user_id,
418
+ email: u.email,
419
+ createdAt: u.created_at
420
+ }));
421
+ }
422
+ /**
423
+ * Delete a user
424
+ */
425
+ async deleteUser(userId) {
426
+ await this.request("/api/v1/users/delete", {
427
+ method: "POST",
428
+ body: JSON.stringify({ user_id: userId })
429
+ });
430
+ }
431
+ /**
432
+ * Update user password
433
+ */
434
+ async updatePassword(userId, oldPassword, newPassword) {
435
+ await this.request("/api/v1/users/password", {
436
+ method: "POST",
437
+ body: JSON.stringify({
438
+ user_id: userId,
439
+ old_password: oldPassword,
440
+ new_password: newPassword
441
+ })
442
+ });
443
+ }
444
+ // ============ Scope Management ============
445
+ /**
446
+ * List custom scopes for the service
447
+ */
448
+ async listScopes() {
449
+ const response = await this.request("/api/v1/scopes/list");
450
+ return response.scopes;
451
+ }
452
+ /**
453
+ * Create a custom scope
454
+ */
455
+ async createScope(request) {
456
+ const response = await this.request("/api/v1/scopes/create", {
457
+ method: "POST",
458
+ body: JSON.stringify(request)
459
+ });
460
+ return {
461
+ scopeId: response.scope_id,
462
+ name: response.name,
463
+ key: response.key,
464
+ description: response.description,
465
+ createdAt: response.created_at
466
+ };
467
+ }
468
+ /**
469
+ * Delete a custom scope
470
+ */
471
+ async deleteScope(scopeId) {
472
+ await this.request("/api/v1/scopes/delete", {
473
+ method: "POST",
474
+ body: JSON.stringify({ scope_id: scopeId })
475
+ });
476
+ }
477
+ // ============ API Key Management ============
478
+ /**
479
+ * List all API keys for the service
480
+ */
481
+ async listApiKeys() {
482
+ const response = await this.request("/api/v1/keys/list");
483
+ return response.keys.map((k) => ({
484
+ keyId: k.keyId,
485
+ name: k.name,
486
+ scope: k.scope,
487
+ scopes: [],
488
+ keyType: k.keyType,
489
+ revoked: k.revoked,
490
+ createdAt: k.createdAt,
491
+ tpsLimit: k.tpsLimit
492
+ }));
493
+ }
494
+ /**
495
+ * Create a new API key with optional custom scopes
496
+ */
497
+ async createApiKey(request) {
498
+ const response = await this.request("/api/v1/keys/create", {
499
+ method: "POST",
500
+ body: JSON.stringify({
501
+ user_id: request.userId,
502
+ name: request.name,
503
+ scope: request.scope || "service",
504
+ scopes: request.scopes,
505
+ key_type: request.keyType || "service",
506
+ tps_limit: request.tpsLimit || 100
507
+ })
508
+ });
509
+ return {
510
+ keyId: response.key_id,
511
+ apiKey: response.api_key,
512
+ name: response.name,
513
+ scope: response.scope,
514
+ scopes: response.scopes
515
+ };
516
+ }
517
+ /**
518
+ * Revoke an API key
519
+ */
520
+ async revokeApiKey(keyId) {
521
+ await this.request("/api/v1/keys/revoke", {
522
+ method: "POST",
523
+ body: JSON.stringify({ key_id: keyId })
524
+ });
525
+ }
526
+ // ============ Service Management ============
527
+ /**
528
+ * Onboard a new service (requires master admin key)
529
+ */
530
+ async onboardService(request, masterAdminKey) {
531
+ const response = await this.request("/api/v1/services/onboard", {
532
+ method: "POST",
533
+ headers: {
534
+ "x-onboarding-admin-key": masterAdminKey
535
+ },
536
+ body: JSON.stringify({
537
+ service_name: request.serviceName,
538
+ owner_email: request.ownerEmail
539
+ })
540
+ });
541
+ return {
542
+ serviceId: response.service_id,
543
+ serviceName: response.service_name,
544
+ ownerEmail: response.owner_email,
545
+ adminKeyId: response.admin_key_id,
546
+ serviceAdminApiKey: response.service_admin_api_key,
547
+ createdAt: response.created_at
548
+ };
549
+ }
550
+ /**
551
+ * Delete a service (requires master admin key)
552
+ */
553
+ async deleteService(serviceId, masterAdminKey) {
554
+ await this.request("/api/v1/services/deboard", {
555
+ method: "POST",
556
+ headers: {
557
+ "x-onboarding-admin-key": masterAdminKey
558
+ },
559
+ body: JSON.stringify({ service_id: serviceId })
560
+ });
561
+ }
562
+ // ============ Webhook Management ============
563
+ /**
564
+ * List webhooks
565
+ */
566
+ async listWebhooks() {
567
+ const response = await this.request(
568
+ "/api/v1/webhooks/list"
569
+ );
570
+ return response.webhooks;
571
+ }
572
+ /**
573
+ * Register a webhook
574
+ */
575
+ async registerWebhook(request) {
576
+ const response = await this.request("/api/v1/webhooks/register", {
577
+ method: "POST",
578
+ body: JSON.stringify(request)
579
+ });
580
+ return {
581
+ webhookId: response.webhook_id,
582
+ url: response.url,
583
+ events: response.events,
584
+ active: response.active,
585
+ createdAt: response.created_at
586
+ };
587
+ }
588
+ /**
589
+ * Delete a webhook
590
+ */
591
+ async deleteWebhook(webhookId) {
592
+ await this.request("/api/v1/webhooks/delete", {
593
+ method: "POST",
594
+ body: JSON.stringify({ webhook_id: webhookId })
595
+ });
596
+ }
597
+ };
598
+
599
+ // src/index.ts
600
+ var VERSION = "1.0.0";
601
+ // Annotate the CommonJS export names for ESM import in node:
602
+ 0 && (module.exports = {
603
+ AuthMiClient,
604
+ AuthMiError,
605
+ LocalStorageTokenStorage,
606
+ MemoryTokenStorage,
607
+ ScopeError,
608
+ VERSION
609
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,18 @@
1
+ import {
2
+ AuthMiClient,
3
+ AuthMiError,
4
+ LocalStorageTokenStorage,
5
+ MemoryTokenStorage,
6
+ ScopeError
7
+ } from "./chunk-UNKK6FP4.mjs";
8
+
9
+ // src/index.ts
10
+ var VERSION = "1.0.0";
11
+ export {
12
+ AuthMiClient,
13
+ AuthMiError,
14
+ LocalStorageTokenStorage,
15
+ MemoryTokenStorage,
16
+ ScopeError,
17
+ VERSION
18
+ };