authmi 1.0.0 → 1.2.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.
- package/README.md +7 -7
- package/dist/chunk-DMNUO422.mjs +706 -0
- package/dist/client-DmZsG2xs.d.mts +406 -0
- package/dist/client-DmZsG2xs.d.ts +406 -0
- package/dist/index.d.mts +48 -23
- package/dist/index.d.ts +48 -23
- package/dist/index.js +580 -384
- package/dist/index.mjs +99 -2
- package/dist/next.d.mts +7 -37
- package/dist/next.d.ts +7 -37
- package/dist/next.js +490 -413
- package/dist/next.mjs +5 -24
- package/dist/react.d.mts +29 -30
- package/dist/react.d.ts +29 -30
- package/dist/react.js +563 -441
- package/dist/react.mjs +77 -52
- package/package.json +8 -6
- package/dist/chunk-UNKK6FP4.mjs +0 -609
- package/dist/client-D6JiIhlU.d.mts +0 -332
- package/dist/client-D6JiIhlU.d.ts +0 -332
package/dist/next.js
CHANGED
|
@@ -4452,49 +4452,65 @@ var next_exports = {};
|
|
|
4452
4452
|
__export2(next_exports, {
|
|
4453
4453
|
AuthMiClient: () => AuthMiClient,
|
|
4454
4454
|
AuthMiError: () => AuthMiError,
|
|
4455
|
-
LocalStorageTokenStorage: () => LocalStorageTokenStorage,
|
|
4456
|
-
MemoryTokenStorage: () => MemoryTokenStorage,
|
|
4457
4455
|
ScopeError: () => ScopeError,
|
|
4458
4456
|
createAuthMiMiddleware: () => createAuthMiMiddleware,
|
|
4459
|
-
validateScopes: () => validateScopes
|
|
4460
|
-
withScope: () => withScope
|
|
4457
|
+
validateScopes: () => validateScopes
|
|
4461
4458
|
});
|
|
4462
4459
|
module.exports = __toCommonJS(next_exports);
|
|
4463
4460
|
var import_server = __toESM(require_server());
|
|
4464
4461
|
|
|
4465
|
-
// src/
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4474
|
-
|
|
4475
|
-
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4462
|
+
// src/config.ts
|
|
4463
|
+
function resolveConfig(provider) {
|
|
4464
|
+
const raw = typeof provider === "function" ? provider() : provider;
|
|
4465
|
+
return {
|
|
4466
|
+
baseUrl: raw.baseUrl,
|
|
4467
|
+
apiKey: raw.apiKey ?? "",
|
|
4468
|
+
serviceId: raw.serviceId ?? "",
|
|
4469
|
+
clientId: raw.clientId ?? "",
|
|
4470
|
+
clientSecret: raw.clientSecret ?? "",
|
|
4471
|
+
defaultTokenExpiry: raw.defaultTokenExpiry ?? 24
|
|
4472
|
+
};
|
|
4473
|
+
}
|
|
4474
|
+
|
|
4475
|
+
// src/storage/localStorage.ts
|
|
4476
|
+
var STORAGE_KEY = "authmi_token";
|
|
4477
|
+
var LocalStorageTokenStorage = class {
|
|
4478
|
+
canAccess() {
|
|
4479
|
+
if (typeof window === "undefined") return false;
|
|
4480
|
+
try {
|
|
4481
|
+
const probe = "__authmi_storage_test__";
|
|
4482
|
+
localStorage.setItem(probe, "1");
|
|
4483
|
+
localStorage.removeItem(probe);
|
|
4484
|
+
return true;
|
|
4485
|
+
} catch {
|
|
4486
|
+
return false;
|
|
4487
|
+
}
|
|
4480
4488
|
}
|
|
4481
|
-
};
|
|
4482
|
-
var _LocalStorageTokenStorage = class _LocalStorageTokenStorage {
|
|
4483
4489
|
getToken() {
|
|
4484
|
-
if (
|
|
4485
|
-
|
|
4490
|
+
if (!this.canAccess()) return null;
|
|
4491
|
+
try {
|
|
4492
|
+
return localStorage.getItem(STORAGE_KEY);
|
|
4493
|
+
} catch {
|
|
4494
|
+
return null;
|
|
4495
|
+
}
|
|
4486
4496
|
}
|
|
4487
4497
|
setToken(token) {
|
|
4488
|
-
if (
|
|
4489
|
-
|
|
4498
|
+
if (!this.canAccess()) return;
|
|
4499
|
+
try {
|
|
4500
|
+
localStorage.setItem(STORAGE_KEY, token);
|
|
4501
|
+
} catch {
|
|
4502
|
+
}
|
|
4490
4503
|
}
|
|
4491
4504
|
removeToken() {
|
|
4492
|
-
if (
|
|
4493
|
-
|
|
4505
|
+
if (!this.canAccess()) return;
|
|
4506
|
+
try {
|
|
4507
|
+
localStorage.removeItem(STORAGE_KEY);
|
|
4508
|
+
} catch {
|
|
4509
|
+
}
|
|
4494
4510
|
}
|
|
4495
4511
|
};
|
|
4496
|
-
|
|
4497
|
-
|
|
4512
|
+
|
|
4513
|
+
// src/storage/memory.ts
|
|
4498
4514
|
var MemoryTokenStorage = class {
|
|
4499
4515
|
constructor() {
|
|
4500
4516
|
this.token = null;
|
|
@@ -4510,51 +4526,56 @@ var MemoryTokenStorage = class {
|
|
|
4510
4526
|
}
|
|
4511
4527
|
};
|
|
4512
4528
|
|
|
4529
|
+
// src/types.ts
|
|
4530
|
+
var AuthMiError = class extends Error {
|
|
4531
|
+
constructor(message, code, statusCode) {
|
|
4532
|
+
super(message);
|
|
4533
|
+
this.code = code;
|
|
4534
|
+
this.statusCode = statusCode;
|
|
4535
|
+
this.name = "AuthMiError";
|
|
4536
|
+
}
|
|
4537
|
+
};
|
|
4538
|
+
var ScopeError = class extends AuthMiError {
|
|
4539
|
+
constructor(message, requiredScopes, providedScopes) {
|
|
4540
|
+
super(message, "INSUFFICIENT_SCOPES", 403);
|
|
4541
|
+
this.requiredScopes = requiredScopes;
|
|
4542
|
+
this.providedScopes = providedScopes;
|
|
4543
|
+
this.name = "ScopeError";
|
|
4544
|
+
}
|
|
4545
|
+
};
|
|
4546
|
+
|
|
4513
4547
|
// src/client.ts
|
|
4514
4548
|
var AuthMiClient = class {
|
|
4515
|
-
constructor(config,
|
|
4516
|
-
this.
|
|
4517
|
-
|
|
4518
|
-
|
|
4519
|
-
clientId: "",
|
|
4520
|
-
clientSecret: "",
|
|
4521
|
-
defaultTokenExpiry: 24,
|
|
4522
|
-
...config
|
|
4523
|
-
};
|
|
4524
|
-
this.tokenStorage = tokenStorage || new LocalStorageTokenStorage();
|
|
4549
|
+
constructor(config, options) {
|
|
4550
|
+
this.configProvider = config;
|
|
4551
|
+
this.storage = options?.storage ?? (typeof window !== "undefined" ? new LocalStorageTokenStorage() : new MemoryTokenStorage());
|
|
4552
|
+
this.cache = options?.cache || null;
|
|
4525
4553
|
}
|
|
4526
|
-
/**
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
const encoded = btoa(`${this.config.clientId}:${this.config.clientSecret}`);
|
|
4530
|
-
return `Basic ${encoded}`;
|
|
4531
|
-
}
|
|
4532
|
-
return null;
|
|
4554
|
+
/** Resolve current config (supports lazy evaluation) */
|
|
4555
|
+
get config() {
|
|
4556
|
+
return resolveConfig(this.configProvider);
|
|
4533
4557
|
}
|
|
4534
|
-
// ============ HTTP
|
|
4535
|
-
async request(endpoint, options = {},
|
|
4536
|
-
const
|
|
4558
|
+
// ============ HTTP plumbing ============
|
|
4559
|
+
async request(endpoint, options = {}, requireUserToken = false, requireServiceAuth = true) {
|
|
4560
|
+
const cfg = this.config;
|
|
4561
|
+
const url = `${cfg.baseUrl}${endpoint}`;
|
|
4537
4562
|
const headers = {
|
|
4538
4563
|
"Content-Type": "application/json",
|
|
4539
4564
|
...options.headers || {}
|
|
4540
4565
|
};
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4546
|
-
|
|
4547
|
-
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
headers["Authorization"] = `Bearer ${token}`;
|
|
4566
|
+
if (!headers["Authorization"]) {
|
|
4567
|
+
if (requireUserToken) {
|
|
4568
|
+
const token = await this.storage.getToken();
|
|
4569
|
+
if (token) headers["Authorization"] = `Bearer ${token}`;
|
|
4570
|
+
} else if (requireServiceAuth && cfg.clientId && cfg.clientSecret) {
|
|
4571
|
+
headers["Authorization"] = `Basic ${btoa(`${cfg.clientId}:${cfg.clientSecret}`)}`;
|
|
4572
|
+
headers["X-Service-ID"] = cfg.serviceId || cfg.clientId;
|
|
4573
|
+
} else if (requireServiceAuth && cfg.apiKey) {
|
|
4574
|
+
headers["Authorization"] = `Bearer ${cfg.apiKey}`;
|
|
4551
4575
|
}
|
|
4552
4576
|
}
|
|
4553
4577
|
try {
|
|
4554
|
-
const response = await fetch(url, {
|
|
4555
|
-
...options,
|
|
4556
|
-
headers
|
|
4557
|
-
});
|
|
4578
|
+
const response = await fetch(url, { ...options, headers });
|
|
4558
4579
|
const data = await response.json();
|
|
4559
4580
|
if (!response.ok) {
|
|
4560
4581
|
if (response.status === 403 && data.required && data.provided) {
|
|
@@ -4572,9 +4593,7 @@ var AuthMiClient = class {
|
|
|
4572
4593
|
}
|
|
4573
4594
|
return data;
|
|
4574
4595
|
} catch (error) {
|
|
4575
|
-
if (error instanceof AuthMiError)
|
|
4576
|
-
throw error;
|
|
4577
|
-
}
|
|
4596
|
+
if (error instanceof AuthMiError) throw error;
|
|
4578
4597
|
throw new AuthMiError(
|
|
4579
4598
|
error instanceof Error ? error.message : "Network error",
|
|
4580
4599
|
"NETWORK_ERROR"
|
|
@@ -4582,384 +4601,497 @@ var AuthMiClient = class {
|
|
|
4582
4601
|
}
|
|
4583
4602
|
}
|
|
4584
4603
|
// ============ Configuration ============
|
|
4585
|
-
/**
|
|
4586
|
-
* Update the client's service configuration
|
|
4587
|
-
*/
|
|
4588
4604
|
configure(config) {
|
|
4589
|
-
|
|
4605
|
+
const current = resolveConfig(this.configProvider);
|
|
4606
|
+
this.configProvider = { ...current, ...config };
|
|
4590
4607
|
}
|
|
4591
|
-
/**
|
|
4592
|
-
* Get current configuration (without sensitive data)
|
|
4593
|
-
*/
|
|
4594
4608
|
getConfig() {
|
|
4595
|
-
const { apiKey: _, clientSecret: __, ...rest } = this.
|
|
4609
|
+
const { apiKey: _, clientSecret: __, ...rest } = resolveConfig(this.configProvider);
|
|
4596
4610
|
return rest;
|
|
4597
4611
|
}
|
|
4598
4612
|
// ============ Token Management ============
|
|
4599
|
-
|
|
4600
|
-
|
|
4601
|
-
|
|
4602
|
-
getAccessToken() {
|
|
4603
|
-
return this.tokenStorage.getToken();
|
|
4604
|
-
}
|
|
4605
|
-
/**
|
|
4606
|
-
* Store an access token
|
|
4607
|
-
*/
|
|
4613
|
+
async getAccessToken() {
|
|
4614
|
+
return this.storage.getToken();
|
|
4615
|
+
}
|
|
4608
4616
|
setAccessToken(token) {
|
|
4609
|
-
this.
|
|
4617
|
+
this.storage.setToken(token);
|
|
4610
4618
|
}
|
|
4611
|
-
/**
|
|
4612
|
-
* Remove the stored access token (logout)
|
|
4613
|
-
*/
|
|
4614
4619
|
clearAccessToken() {
|
|
4615
|
-
this.
|
|
4616
|
-
}
|
|
4617
|
-
/**
|
|
4618
|
-
* Check if user is logged in
|
|
4619
|
-
*/
|
|
4620
|
-
isLoggedIn() {
|
|
4621
|
-
return !!this.getAccessToken();
|
|
4622
|
-
}
|
|
4623
|
-
// ============ Scope Validation ============
|
|
4624
|
-
/**
|
|
4625
|
-
* Introspect a token or API key and validate required scopes
|
|
4626
|
-
*/
|
|
4627
|
-
async introspect(request) {
|
|
4628
|
-
return this.request("/api/v1/introspect", {
|
|
4629
|
-
method: "POST",
|
|
4630
|
-
body: JSON.stringify(request)
|
|
4631
|
-
});
|
|
4632
|
-
}
|
|
4633
|
-
/**
|
|
4634
|
-
* Validate the current token with optional scope checking
|
|
4635
|
-
*/
|
|
4636
|
-
async validateWithScopes(requiredScopes) {
|
|
4637
|
-
const token = this.getAccessToken();
|
|
4638
|
-
if (!token) {
|
|
4639
|
-
return { valid: false, error: "No token provided" };
|
|
4640
|
-
}
|
|
4641
|
-
if (!this.config.apiKey && !this.config.clientSecret) {
|
|
4642
|
-
return { valid: false, error: "Service credentials not configured" };
|
|
4643
|
-
}
|
|
4644
|
-
if (!this.config.serviceId) {
|
|
4645
|
-
return { valid: false, error: "Service ID not configured in AuthMiConfig" };
|
|
4646
|
-
}
|
|
4647
|
-
try {
|
|
4648
|
-
const result = await this.introspect({
|
|
4649
|
-
serviceId: this.config.serviceId,
|
|
4650
|
-
token,
|
|
4651
|
-
requiredScopes
|
|
4652
|
-
});
|
|
4653
|
-
return {
|
|
4654
|
-
valid: result.valid,
|
|
4655
|
-
type: result.type === "bearer" ? "token" : "api_key",
|
|
4656
|
-
scopes: result.scopes,
|
|
4657
|
-
userId: result.userId,
|
|
4658
|
-
email: result.email,
|
|
4659
|
-
error: result.error
|
|
4660
|
-
};
|
|
4661
|
-
} catch (error) {
|
|
4662
|
-
if (error instanceof ScopeError) {
|
|
4663
|
-
return {
|
|
4664
|
-
valid: false,
|
|
4665
|
-
error: error.message,
|
|
4666
|
-
scopes: error.providedScopes
|
|
4667
|
-
};
|
|
4668
|
-
}
|
|
4669
|
-
if (error instanceof AuthMiError && error.statusCode === 401) {
|
|
4670
|
-
return { valid: false, error: "Invalid or expired token" };
|
|
4671
|
-
}
|
|
4672
|
-
throw error;
|
|
4673
|
-
}
|
|
4674
|
-
}
|
|
4675
|
-
/**
|
|
4676
|
-
* Check if the current user has all the required scopes
|
|
4677
|
-
* Throws ScopeError if scopes are insufficient
|
|
4678
|
-
*/
|
|
4679
|
-
async requireScopes(...requiredScopes) {
|
|
4680
|
-
const result = await this.validateWithScopes(requiredScopes);
|
|
4681
|
-
if (!result.valid) {
|
|
4682
|
-
throw new AuthMiError(
|
|
4683
|
-
result.error || "Authentication required",
|
|
4684
|
-
"UNAUTHORIZED",
|
|
4685
|
-
401
|
|
4686
|
-
);
|
|
4687
|
-
}
|
|
4688
|
-
const hasScopes = requiredScopes.every(
|
|
4689
|
-
(scope) => result.scopes?.includes(scope)
|
|
4690
|
-
);
|
|
4691
|
-
if (!hasScopes) {
|
|
4692
|
-
throw new ScopeError(
|
|
4693
|
-
`Required scopes: ${requiredScopes.join(", ")}`,
|
|
4694
|
-
requiredScopes,
|
|
4695
|
-
result.scopes || []
|
|
4696
|
-
);
|
|
4697
|
-
}
|
|
4698
|
-
return result;
|
|
4699
|
-
}
|
|
4700
|
-
/**
|
|
4701
|
-
* Execute a function only if the user has the required scopes
|
|
4702
|
-
*/
|
|
4703
|
-
async withScope(scopes, fn) {
|
|
4704
|
-
await this.requireScopes(...scopes);
|
|
4705
|
-
return fn();
|
|
4706
|
-
}
|
|
4707
|
-
// ============ OAuth ============
|
|
4708
|
-
/**
|
|
4709
|
-
* Initiate OAuth login flow and return the authorization URL
|
|
4710
|
-
*/
|
|
4711
|
-
async initiateOAuth(provider, redirectUri) {
|
|
4712
|
-
if (!this.config.apiKey && !this.config.clientSecret) {
|
|
4713
|
-
throw new AuthMiError(
|
|
4714
|
-
"API key or client credentials required for OAuth. Configure the client first.",
|
|
4715
|
-
"MISSING_CREDENTIALS"
|
|
4716
|
-
);
|
|
4717
|
-
}
|
|
4718
|
-
if (!this.config.serviceId) {
|
|
4719
|
-
throw new AuthMiError(
|
|
4720
|
-
"serviceId required for OAuth. Configure the client first.",
|
|
4721
|
-
"MISSING_SERVICE_ID"
|
|
4722
|
-
);
|
|
4723
|
-
}
|
|
4724
|
-
const response = await this.request(
|
|
4725
|
-
"/api/v1/auth/oauth/initiate",
|
|
4726
|
-
{
|
|
4727
|
-
method: "POST",
|
|
4728
|
-
body: JSON.stringify({ provider, redirectUri, client_id: this.config.serviceId })
|
|
4729
|
-
}
|
|
4730
|
-
);
|
|
4731
|
-
return response.url;
|
|
4620
|
+
this.storage.removeToken();
|
|
4732
4621
|
}
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
*/
|
|
4737
|
-
handleOAuthCallback(url) {
|
|
4738
|
-
const parsedUrl = typeof url === "string" ? new URL(url) : url;
|
|
4739
|
-
const token = parsedUrl.searchParams.get("token");
|
|
4740
|
-
const userId = parsedUrl.searchParams.get("user_id");
|
|
4741
|
-
const email = parsedUrl.searchParams.get("email");
|
|
4742
|
-
if (!token || !userId || !email) {
|
|
4743
|
-
return null;
|
|
4744
|
-
}
|
|
4745
|
-
this.setAccessToken(token);
|
|
4746
|
-
return { token, userId, email };
|
|
4622
|
+
async isLoggedIn() {
|
|
4623
|
+
const token = await this.storage.getToken();
|
|
4624
|
+
return !!token;
|
|
4747
4625
|
}
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
|
|
4752
|
-
|
|
4753
|
-
|
|
4626
|
+
// ============ Auth Endpoints ============
|
|
4627
|
+
async signup(credentials) {
|
|
4628
|
+
const response = await this.request("/api/v1/auth/signup", {
|
|
4629
|
+
method: "POST",
|
|
4630
|
+
body: JSON.stringify(credentials)
|
|
4631
|
+
}, false, false);
|
|
4632
|
+
return this.mapAuthToken(response);
|
|
4754
4633
|
}
|
|
4755
|
-
// ============ Authentication ============
|
|
4756
|
-
/**
|
|
4757
|
-
* Login a user and store the access token
|
|
4758
|
-
*/
|
|
4759
4634
|
async login(credentials) {
|
|
4760
|
-
|
|
4761
|
-
throw new AuthMiError(
|
|
4762
|
-
"API key or client credentials required for login. Configure the client first.",
|
|
4763
|
-
"MISSING_CREDENTIALS"
|
|
4764
|
-
);
|
|
4765
|
-
}
|
|
4635
|
+
const cfg = this.config;
|
|
4766
4636
|
const response = await this.request("/api/v1/auth/login", {
|
|
4767
4637
|
method: "POST",
|
|
4768
4638
|
body: JSON.stringify({
|
|
4769
4639
|
email: credentials.email,
|
|
4770
4640
|
password: credentials.password,
|
|
4771
|
-
client_id:
|
|
4772
|
-
expires_in_hours: credentials.expiresInHours ||
|
|
4641
|
+
client_id: cfg.serviceId,
|
|
4642
|
+
expires_in_hours: credentials.expiresInHours || cfg.defaultTokenExpiry,
|
|
4773
4643
|
scopes: credentials.scopes
|
|
4774
4644
|
})
|
|
4775
|
-
});
|
|
4776
|
-
const token =
|
|
4777
|
-
accessToken: response.access_token,
|
|
4778
|
-
tokenType: response.token_type,
|
|
4779
|
-
expiresIn: response.expires_in,
|
|
4780
|
-
expiresAt: response.expires_at,
|
|
4781
|
-
userId: response.user_id,
|
|
4782
|
-
email: response.email,
|
|
4783
|
-
scopes: response.scopes
|
|
4784
|
-
};
|
|
4645
|
+
}, false, false);
|
|
4646
|
+
const token = this.mapAuthToken(response);
|
|
4785
4647
|
this.setAccessToken(token.accessToken);
|
|
4786
4648
|
return token;
|
|
4787
4649
|
}
|
|
4788
|
-
/**
|
|
4789
|
-
* Logout the current user
|
|
4790
|
-
*/
|
|
4791
4650
|
async logout() {
|
|
4792
|
-
const token = this.
|
|
4651
|
+
const token = await this.storage.getToken();
|
|
4793
4652
|
if (token) {
|
|
4794
4653
|
try {
|
|
4795
|
-
await this.request("/api/v1/auth/logout", {
|
|
4796
|
-
|
|
4797
|
-
}, true);
|
|
4798
|
-
} catch (error) {
|
|
4654
|
+
await this.request("/api/v1/auth/logout", { method: "POST" }, true);
|
|
4655
|
+
} catch {
|
|
4799
4656
|
}
|
|
4800
4657
|
}
|
|
4801
4658
|
this.clearAccessToken();
|
|
4802
4659
|
}
|
|
4803
|
-
/**
|
|
4804
|
-
* Validate the current token or an API key
|
|
4805
|
-
* @deprecated Use validateWithScopes instead
|
|
4806
|
-
*/
|
|
4807
|
-
async validate(_credential) {
|
|
4808
|
-
return this.validateWithScopes();
|
|
4809
|
-
}
|
|
4810
|
-
/**
|
|
4811
|
-
* Refresh the current token
|
|
4812
|
-
*/
|
|
4813
4660
|
async refreshToken() {
|
|
4814
|
-
const response = await this.request("/api/v1/auth/refresh", {
|
|
4815
|
-
method: "POST"
|
|
4816
|
-
}, true);
|
|
4661
|
+
const response = await this.request("/api/v1/auth/refresh", { method: "POST" }, true);
|
|
4817
4662
|
const token = {
|
|
4818
4663
|
accessToken: response.access_token,
|
|
4819
|
-
tokenType:
|
|
4664
|
+
tokenType: "Bearer",
|
|
4820
4665
|
expiresIn: response.expires_in,
|
|
4821
4666
|
expiresAt: response.expires_at,
|
|
4822
4667
|
userId: "",
|
|
4823
|
-
// Refresh doesn't return user info
|
|
4824
4668
|
email: ""
|
|
4825
4669
|
};
|
|
4826
4670
|
this.setAccessToken(token.accessToken);
|
|
4827
4671
|
return token;
|
|
4828
4672
|
}
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
|
|
4833
|
-
async
|
|
4834
|
-
|
|
4673
|
+
async getMe() {
|
|
4674
|
+
const response = await this.request("/api/v1/auth/me", {}, true);
|
|
4675
|
+
return { userId: response.user_id, email: response.email, name: response.name, createdAt: response.created_at };
|
|
4676
|
+
}
|
|
4677
|
+
async forgotPassword(request) {
|
|
4678
|
+
return this.request("/api/v1/auth/forgot-password", {
|
|
4835
4679
|
method: "POST",
|
|
4836
|
-
body: JSON.stringify(request)
|
|
4837
|
-
});
|
|
4680
|
+
body: JSON.stringify({ email: request.email, client_id: this.config.serviceId })
|
|
4681
|
+
}, false, false);
|
|
4682
|
+
}
|
|
4683
|
+
async resetPassword(request) {
|
|
4684
|
+
return this.request("/api/v1/auth/reset-password", {
|
|
4685
|
+
method: "POST",
|
|
4686
|
+
body: JSON.stringify({ token: request.token, new_password: request.newPassword })
|
|
4687
|
+
}, false, false);
|
|
4688
|
+
}
|
|
4689
|
+
async verifyEmail(request) {
|
|
4690
|
+
return this.request("/api/v1/auth/verify-email", {
|
|
4691
|
+
method: "POST",
|
|
4692
|
+
body: JSON.stringify({ token: request.token })
|
|
4693
|
+
}, false, false);
|
|
4694
|
+
}
|
|
4695
|
+
async resendVerification(request) {
|
|
4696
|
+
return this.request("/api/v1/auth/resend-verification", {
|
|
4697
|
+
method: "POST",
|
|
4698
|
+
body: JSON.stringify({ email: request.email, client_id: this.config.serviceId })
|
|
4699
|
+
}, false, false);
|
|
4700
|
+
}
|
|
4701
|
+
async deactivateAccount(password) {
|
|
4702
|
+
await this.request("/api/v1/auth/deactivate", {
|
|
4703
|
+
method: "POST",
|
|
4704
|
+
body: JSON.stringify({ password })
|
|
4705
|
+
}, true, false);
|
|
4706
|
+
}
|
|
4707
|
+
mapAuthToken(raw) {
|
|
4838
4708
|
return {
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4709
|
+
accessToken: raw.access_token,
|
|
4710
|
+
tokenType: raw.token_type,
|
|
4711
|
+
expiresIn: raw.expires_in,
|
|
4712
|
+
expiresAt: raw.expires_at,
|
|
4713
|
+
userId: raw.user_id,
|
|
4714
|
+
email: raw.email,
|
|
4715
|
+
emailVerified: raw.email_verified,
|
|
4716
|
+
scopes: raw.scopes
|
|
4842
4717
|
};
|
|
4843
4718
|
}
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4719
|
+
// ============ OAuth ============
|
|
4720
|
+
async initiateOAuth(provider, redirectUri) {
|
|
4721
|
+
const cfg = this.config;
|
|
4722
|
+
if (!cfg.clientId && !cfg.clientSecret && !cfg.apiKey) {
|
|
4723
|
+
throw new AuthMiError("Credentials required for OAuth", "MISSING_CREDENTIALS");
|
|
4724
|
+
}
|
|
4725
|
+
const response = await this.request("/api/v1/auth/oauth/initiate", {
|
|
4726
|
+
method: "POST",
|
|
4727
|
+
body: JSON.stringify({ provider, redirectUri, client_id: cfg.serviceId || cfg.clientId })
|
|
4728
|
+
}, false, false);
|
|
4729
|
+
return response.url;
|
|
4730
|
+
}
|
|
4731
|
+
handleOAuthCallback(url) {
|
|
4732
|
+
const parsed = typeof url === "string" ? new URL(url) : url;
|
|
4733
|
+
const token = parsed.searchParams.get("token");
|
|
4734
|
+
const userId = parsed.searchParams.get("user_id");
|
|
4735
|
+
const email = parsed.searchParams.get("email");
|
|
4736
|
+
if (!token || !userId || !email) return null;
|
|
4737
|
+
this.setAccessToken(token);
|
|
4738
|
+
return { token, userId, email };
|
|
4739
|
+
}
|
|
4740
|
+
isOAuthCallback(url) {
|
|
4741
|
+
const parsed = typeof url === "string" ? new URL(url) : url;
|
|
4742
|
+
return !!(parsed.searchParams.has("token") && parsed.searchParams.has("user_id") && parsed.searchParams.has("email"));
|
|
4743
|
+
}
|
|
4744
|
+
// ============ SAML ============
|
|
4745
|
+
async initiateSaml(request) {
|
|
4746
|
+
return this.request("/api/v1/auth/saml/initiate", {
|
|
4747
|
+
method: "POST",
|
|
4748
|
+
body: JSON.stringify({ email: request.email, redirect_uri: request.redirectUri })
|
|
4749
|
+
}, false, false);
|
|
4750
|
+
}
|
|
4751
|
+
async parseSamlMetadata(xml) {
|
|
4752
|
+
return this.request("/api/v1/auth/saml/parse-metadata", {
|
|
4753
|
+
method: "POST",
|
|
4754
|
+
body: JSON.stringify({ metadata_xml: xml })
|
|
4755
|
+
}, false, false);
|
|
4756
|
+
}
|
|
4757
|
+
async listSamlConnections() {
|
|
4758
|
+
const response = await this.request("/api/v1/auth/saml/connections");
|
|
4759
|
+
return response.connections;
|
|
4760
|
+
}
|
|
4761
|
+
async createSamlConnection(request) {
|
|
4762
|
+
return this.request("/api/v1/auth/saml/connections", {
|
|
4763
|
+
method: "POST",
|
|
4764
|
+
body: JSON.stringify(request)
|
|
4765
|
+
});
|
|
4766
|
+
}
|
|
4767
|
+
async deleteSamlConnection(id) {
|
|
4768
|
+
await this.request(`/api/v1/auth/saml/connections/${encodeURIComponent(id)}`, {
|
|
4769
|
+
method: "DELETE"
|
|
4770
|
+
});
|
|
4771
|
+
}
|
|
4772
|
+
// ============ 2FA ============
|
|
4773
|
+
async setup2fa() {
|
|
4774
|
+
return this.request("/api/v1/auth/2fa/setup", { method: "POST" }, true, false);
|
|
4775
|
+
}
|
|
4776
|
+
async enable2fa(code) {
|
|
4777
|
+
return this.request("/api/v1/auth/2fa/enable", {
|
|
4778
|
+
method: "POST",
|
|
4779
|
+
body: JSON.stringify({ code })
|
|
4780
|
+
}, true, false);
|
|
4781
|
+
}
|
|
4782
|
+
async disable2fa(password) {
|
|
4783
|
+
await this.request("/api/v1/auth/2fa/disable", {
|
|
4784
|
+
method: "POST",
|
|
4785
|
+
body: JSON.stringify({ password })
|
|
4786
|
+
}, true, false);
|
|
4787
|
+
}
|
|
4788
|
+
async regenerateBackupCodes() {
|
|
4789
|
+
return this.request("/api/v1/auth/2fa/backup-codes", { method: "POST" }, true, false);
|
|
4790
|
+
}
|
|
4791
|
+
async challenge2fa(request) {
|
|
4792
|
+
return this.request("/api/v1/auth/2fa/challenge", {
|
|
4793
|
+
method: "POST",
|
|
4794
|
+
body: JSON.stringify(request)
|
|
4795
|
+
}, false, false);
|
|
4796
|
+
}
|
|
4797
|
+
// ============ Users ============
|
|
4798
|
+
async createUser(request) {
|
|
4799
|
+
const response = await this.request(
|
|
4800
|
+
"/api/v1/users/create",
|
|
4801
|
+
{
|
|
4802
|
+
method: "POST",
|
|
4803
|
+
body: JSON.stringify(request)
|
|
4804
|
+
}
|
|
4805
|
+
);
|
|
4806
|
+
return { userId: response.user_id, email: response.email, name: response.name, createdAt: response.created_at };
|
|
4807
|
+
}
|
|
4847
4808
|
async listUsers() {
|
|
4848
4809
|
const response = await this.request("/api/v1/users/list");
|
|
4849
4810
|
return response.users.map((u) => ({
|
|
4850
4811
|
userId: u.user_id,
|
|
4851
4812
|
email: u.email,
|
|
4813
|
+
name: u.name,
|
|
4852
4814
|
createdAt: u.created_at
|
|
4853
4815
|
}));
|
|
4854
4816
|
}
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4817
|
+
async getUser(userId) {
|
|
4818
|
+
const response = await this.request(
|
|
4819
|
+
`/api/v1/users/${encodeURIComponent(userId)}`
|
|
4820
|
+
);
|
|
4821
|
+
return { userId: response.user_id, email: response.email, name: response.name, createdAt: response.created_at };
|
|
4822
|
+
}
|
|
4858
4823
|
async deleteUser(userId) {
|
|
4859
4824
|
await this.request("/api/v1/users/delete", {
|
|
4860
4825
|
method: "POST",
|
|
4861
4826
|
body: JSON.stringify({ user_id: userId })
|
|
4862
4827
|
});
|
|
4863
4828
|
}
|
|
4864
|
-
|
|
4865
|
-
|
|
4866
|
-
|
|
4829
|
+
async deleteUserById(userId) {
|
|
4830
|
+
await this.request(`/api/v1/users/${encodeURIComponent(userId)}`, { method: "DELETE" });
|
|
4831
|
+
}
|
|
4867
4832
|
async updatePassword(userId, oldPassword, newPassword) {
|
|
4868
4833
|
await this.request("/api/v1/users/password", {
|
|
4869
4834
|
method: "POST",
|
|
4870
|
-
body: JSON.stringify({
|
|
4871
|
-
user_id: userId,
|
|
4872
|
-
old_password: oldPassword,
|
|
4873
|
-
new_password: newPassword
|
|
4874
|
-
})
|
|
4835
|
+
body: JSON.stringify({ user_id: userId, old_password: oldPassword, new_password: newPassword })
|
|
4875
4836
|
});
|
|
4876
4837
|
}
|
|
4877
|
-
// ============
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
return response.
|
|
4838
|
+
// ============ Roles ============
|
|
4839
|
+
async createRole(request) {
|
|
4840
|
+
const response = await this.request(
|
|
4841
|
+
"/api/v1/users/roles/create",
|
|
4842
|
+
{ method: "POST", body: JSON.stringify(request) }
|
|
4843
|
+
);
|
|
4844
|
+
return { roleId: response.role_id, name: response.name, description: response.description, createdAt: response.created_at };
|
|
4884
4845
|
}
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4846
|
+
async listRoles() {
|
|
4847
|
+
const response = await this.request("/api/v1/users/roles/list");
|
|
4848
|
+
return response.roles.map((r) => ({
|
|
4849
|
+
roleId: r.role_id,
|
|
4850
|
+
name: r.name,
|
|
4851
|
+
description: r.description,
|
|
4852
|
+
createdAt: r.created_at
|
|
4853
|
+
}));
|
|
4854
|
+
}
|
|
4855
|
+
async deleteRole(roleId) {
|
|
4856
|
+
await this.request(`/api/v1/users/roles/${encodeURIComponent(roleId)}`, { method: "DELETE" });
|
|
4857
|
+
}
|
|
4858
|
+
async assignRole(userId, roleId) {
|
|
4859
|
+
await this.request("/api/v1/users/roles/assign", {
|
|
4890
4860
|
method: "POST",
|
|
4891
|
-
body: JSON.stringify(
|
|
4861
|
+
body: JSON.stringify({ user_id: userId, role_id: roleId })
|
|
4892
4862
|
});
|
|
4893
|
-
return {
|
|
4894
|
-
scopeId: response.scope_id,
|
|
4895
|
-
name: response.name,
|
|
4896
|
-
key: response.key,
|
|
4897
|
-
description: response.description,
|
|
4898
|
-
createdAt: response.created_at
|
|
4899
|
-
};
|
|
4900
4863
|
}
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
*/
|
|
4904
|
-
async deleteScope(scopeId) {
|
|
4905
|
-
await this.request("/api/v1/scopes/delete", {
|
|
4864
|
+
async unassignRole(userId, roleId) {
|
|
4865
|
+
await this.request("/api/v1/users/roles/unassign", {
|
|
4906
4866
|
method: "POST",
|
|
4907
|
-
body: JSON.stringify({
|
|
4867
|
+
body: JSON.stringify({ user_id: userId, role_id: roleId })
|
|
4908
4868
|
});
|
|
4909
4869
|
}
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4870
|
+
async getUserRoles(userId) {
|
|
4871
|
+
const response = await this.request(
|
|
4872
|
+
`/api/v1/users/${encodeURIComponent(userId)}/roles`
|
|
4873
|
+
);
|
|
4874
|
+
return response.roles.map((r) => ({
|
|
4875
|
+
roleId: r.role_id,
|
|
4876
|
+
name: r.name,
|
|
4877
|
+
description: r.description,
|
|
4878
|
+
createdAt: r.created_at
|
|
4879
|
+
}));
|
|
4880
|
+
}
|
|
4881
|
+
// ============ API Keys ============
|
|
4914
4882
|
async listApiKeys() {
|
|
4915
4883
|
const response = await this.request("/api/v1/keys/list");
|
|
4916
4884
|
return response.keys.map((k) => ({
|
|
4917
4885
|
keyId: k.keyId,
|
|
4918
4886
|
name: k.name,
|
|
4919
4887
|
scope: k.scope,
|
|
4920
|
-
scopes:
|
|
4888
|
+
scopes: k.scopes,
|
|
4921
4889
|
keyType: k.keyType,
|
|
4890
|
+
tpsLimit: k.tpsLimit,
|
|
4922
4891
|
revoked: k.revoked,
|
|
4923
|
-
createdAt: k.createdAt
|
|
4924
|
-
tpsLimit: k.tpsLimit
|
|
4892
|
+
createdAt: k.createdAt
|
|
4925
4893
|
}));
|
|
4926
4894
|
}
|
|
4927
|
-
/**
|
|
4928
|
-
* Create a new API key with optional custom scopes
|
|
4929
|
-
*/
|
|
4930
4895
|
async createApiKey(request) {
|
|
4931
|
-
const response = await this.request(
|
|
4896
|
+
const response = await this.request(
|
|
4897
|
+
"/api/v1/keys/create",
|
|
4898
|
+
{
|
|
4899
|
+
method: "POST",
|
|
4900
|
+
body: JSON.stringify({
|
|
4901
|
+
user_id: request.userId,
|
|
4902
|
+
name: request.name,
|
|
4903
|
+
scope: request.scope || "service",
|
|
4904
|
+
scopes: request.scopes,
|
|
4905
|
+
key_type: request.keyType || "service",
|
|
4906
|
+
tps_limit: request.tpsLimit || 100
|
|
4907
|
+
})
|
|
4908
|
+
}
|
|
4909
|
+
);
|
|
4910
|
+
return { keyId: response.key_id, apiKey: response.api_key, name: response.name, scope: response.scope, scopes: response.scopes };
|
|
4911
|
+
}
|
|
4912
|
+
async revokeApiKey(keyId) {
|
|
4913
|
+
await this.request("/api/v1/keys/revoke", {
|
|
4914
|
+
method: "POST",
|
|
4915
|
+
body: JSON.stringify({ key_id: keyId })
|
|
4916
|
+
});
|
|
4917
|
+
}
|
|
4918
|
+
// ============ Scopes ============
|
|
4919
|
+
async listScopes() {
|
|
4920
|
+
const response = await this.request("/api/v1/scopes/list");
|
|
4921
|
+
return response.scopes;
|
|
4922
|
+
}
|
|
4923
|
+
async createScope(request) {
|
|
4924
|
+
const response = await this.request(
|
|
4925
|
+
"/api/v1/scopes/create",
|
|
4926
|
+
{ method: "POST", body: JSON.stringify(request) }
|
|
4927
|
+
);
|
|
4928
|
+
return { scopeId: response.scope_id, name: response.name, key: response.key, description: response.description, createdAt: response.created_at };
|
|
4929
|
+
}
|
|
4930
|
+
async deleteScope(scopeId) {
|
|
4931
|
+
await this.request("/api/v1/scopes/delete", {
|
|
4932
|
+
method: "POST",
|
|
4933
|
+
body: JSON.stringify({ scope_id: scopeId })
|
|
4934
|
+
});
|
|
4935
|
+
}
|
|
4936
|
+
// ============ Introspection & Validation ============
|
|
4937
|
+
async introspect(request) {
|
|
4938
|
+
if (this.cache && request.token) {
|
|
4939
|
+
const cached = this.cache.get(request.token);
|
|
4940
|
+
if (cached) return cached;
|
|
4941
|
+
}
|
|
4942
|
+
const result = await this.request("/api/v1/introspect", {
|
|
4932
4943
|
method: "POST",
|
|
4933
4944
|
body: JSON.stringify({
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
key_type: request.keyType || "service",
|
|
4939
|
-
tps_limit: request.tpsLimit || 100
|
|
4945
|
+
serviceId: request.serviceId,
|
|
4946
|
+
token: request.token,
|
|
4947
|
+
apiKey: request.apiKey,
|
|
4948
|
+
requiredScopes: request.requiredScopes
|
|
4940
4949
|
})
|
|
4941
4950
|
});
|
|
4942
|
-
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
scope: response.scope,
|
|
4947
|
-
scopes: response.scopes
|
|
4948
|
-
};
|
|
4951
|
+
if (this.cache && request.token) {
|
|
4952
|
+
this.cache.set(request.token, result);
|
|
4953
|
+
}
|
|
4954
|
+
return result;
|
|
4949
4955
|
}
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4956
|
+
async validate() {
|
|
4957
|
+
const cfg = this.config;
|
|
4958
|
+
const token = await this.storage.getToken();
|
|
4959
|
+
if (!token) return { valid: false, error: "No token stored" };
|
|
4960
|
+
if (!cfg.serviceId) return { valid: false, error: "Service ID not configured" };
|
|
4961
|
+
if (!cfg.apiKey && !cfg.clientSecret) return { valid: false, error: "Service credentials not configured" };
|
|
4962
|
+
try {
|
|
4963
|
+
const result = await this.introspect({ serviceId: cfg.serviceId, token });
|
|
4964
|
+
return {
|
|
4965
|
+
valid: result.valid,
|
|
4966
|
+
type: result.type === "bearer" ? "token" : "api_key",
|
|
4967
|
+
scopes: result.scopes,
|
|
4968
|
+
userId: result.userId,
|
|
4969
|
+
email: result.email,
|
|
4970
|
+
error: result.error
|
|
4971
|
+
};
|
|
4972
|
+
} catch (error) {
|
|
4973
|
+
if (error instanceof ScopeError) {
|
|
4974
|
+
return { valid: false, error: error.message, scopes: error.providedScopes };
|
|
4975
|
+
}
|
|
4976
|
+
if (error instanceof AuthMiError && error.statusCode === 401) {
|
|
4977
|
+
return { valid: false, error: "Invalid or expired token" };
|
|
4978
|
+
}
|
|
4979
|
+
throw error;
|
|
4980
|
+
}
|
|
4981
|
+
}
|
|
4982
|
+
async validateWithScopes(requiredScopes) {
|
|
4983
|
+
const cfg = this.config;
|
|
4984
|
+
const token = await this.storage.getToken();
|
|
4985
|
+
if (!token) return { valid: false, error: "No token provided" };
|
|
4986
|
+
if (!cfg.apiKey && !cfg.clientSecret) return { valid: false, error: "Service credentials not configured" };
|
|
4987
|
+
if (!cfg.serviceId) return { valid: false, error: "Service ID not configured" };
|
|
4988
|
+
try {
|
|
4989
|
+
const result = await this.introspect({ serviceId: cfg.serviceId, token, requiredScopes });
|
|
4990
|
+
return {
|
|
4991
|
+
valid: result.valid,
|
|
4992
|
+
type: result.type === "bearer" ? "token" : "api_key",
|
|
4993
|
+
scopes: result.scopes,
|
|
4994
|
+
userId: result.userId,
|
|
4995
|
+
email: result.email,
|
|
4996
|
+
error: result.error
|
|
4997
|
+
};
|
|
4998
|
+
} catch (error) {
|
|
4999
|
+
if (error instanceof ScopeError) {
|
|
5000
|
+
return { valid: false, error: error.message, scopes: error.providedScopes };
|
|
5001
|
+
}
|
|
5002
|
+
if (error instanceof AuthMiError && error.statusCode === 401) {
|
|
5003
|
+
return { valid: false, error: "Invalid or expired token" };
|
|
5004
|
+
}
|
|
5005
|
+
throw error;
|
|
5006
|
+
}
|
|
5007
|
+
}
|
|
5008
|
+
async requireScopes(...requiredScopes) {
|
|
5009
|
+
const result = await this.validateWithScopes(requiredScopes);
|
|
5010
|
+
if (!result.valid) {
|
|
5011
|
+
throw new AuthMiError(result.error || "Authentication required", "UNAUTHORIZED", 401);
|
|
5012
|
+
}
|
|
5013
|
+
const hasScopes = requiredScopes.every((s) => result.scopes?.includes(s));
|
|
5014
|
+
if (!hasScopes) {
|
|
5015
|
+
throw new ScopeError(`Required: ${requiredScopes.join(", ")}`, requiredScopes, result.scopes || []);
|
|
5016
|
+
}
|
|
5017
|
+
return result;
|
|
5018
|
+
}
|
|
5019
|
+
async withScope(scopes, fn) {
|
|
5020
|
+
await this.requireScopes(...scopes);
|
|
5021
|
+
return fn();
|
|
5022
|
+
}
|
|
5023
|
+
// ============ Webhooks ============
|
|
5024
|
+
async listWebhooks() {
|
|
5025
|
+
const response = await this.request("/api/v1/webhooks/list");
|
|
5026
|
+
return response.webhooks;
|
|
5027
|
+
}
|
|
5028
|
+
async registerWebhook(request) {
|
|
5029
|
+
const response = await this.request(
|
|
5030
|
+
"/api/v1/webhooks/register",
|
|
5031
|
+
{ method: "POST", body: JSON.stringify(request) }
|
|
5032
|
+
);
|
|
5033
|
+
return { webhookId: response.webhook_id, url: response.url, events: response.events, active: response.active, createdAt: response.created_at };
|
|
5034
|
+
}
|
|
5035
|
+
async deleteWebhook(webhookId) {
|
|
5036
|
+
await this.request("/api/v1/webhooks/delete", {
|
|
4955
5037
|
method: "POST",
|
|
4956
|
-
body: JSON.stringify({
|
|
5038
|
+
body: JSON.stringify({ webhook_id: webhookId })
|
|
5039
|
+
});
|
|
5040
|
+
}
|
|
5041
|
+
// ============ Billing ============
|
|
5042
|
+
async listPlans() {
|
|
5043
|
+
const response = await this.request("/api/v1/billing/plans");
|
|
5044
|
+
return response.plans;
|
|
5045
|
+
}
|
|
5046
|
+
async getSubscription() {
|
|
5047
|
+
return this.request("/api/v1/billing/subscription");
|
|
5048
|
+
}
|
|
5049
|
+
async createCheckout(priceId) {
|
|
5050
|
+
return this.request("/api/v1/billing/checkout", {
|
|
5051
|
+
method: "POST",
|
|
5052
|
+
body: JSON.stringify({ price_id: priceId })
|
|
5053
|
+
});
|
|
5054
|
+
}
|
|
5055
|
+
async createPortalSession() {
|
|
5056
|
+
return this.request("/api/v1/billing/portal", { method: "POST" });
|
|
5057
|
+
}
|
|
5058
|
+
// ============ Audit ============
|
|
5059
|
+
async getAuditLogs(query) {
|
|
5060
|
+
const params = new URLSearchParams();
|
|
5061
|
+
if (query?.limit) params.set("limit", String(query.limit));
|
|
5062
|
+
if (query?.offset) params.set("offset", String(query.offset));
|
|
5063
|
+
if (query?.actorId) params.set("actor_id", query.actorId);
|
|
5064
|
+
if (query?.action) params.set("action", query.action);
|
|
5065
|
+
if (query?.resourceType) params.set("resource_type", query.resourceType);
|
|
5066
|
+
if (query?.startDate) params.set("start_date", query.startDate);
|
|
5067
|
+
if (query?.endDate) params.set("end_date", query.endDate);
|
|
5068
|
+
const qs = params.toString();
|
|
5069
|
+
const response = await this.request(
|
|
5070
|
+
`/api/v1/audit-logs${qs ? `?${qs}` : ""}`
|
|
5071
|
+
);
|
|
5072
|
+
return response.logs;
|
|
5073
|
+
}
|
|
5074
|
+
// ============ Services ============
|
|
5075
|
+
async getService(serviceId) {
|
|
5076
|
+
return this.request(`/api/v1/services/${encodeURIComponent(serviceId)}`);
|
|
5077
|
+
}
|
|
5078
|
+
async updateService(serviceId, data) {
|
|
5079
|
+
return this.request(`/api/v1/services/${encodeURIComponent(serviceId)}`, {
|
|
5080
|
+
method: "POST",
|
|
5081
|
+
body: JSON.stringify(data)
|
|
4957
5082
|
});
|
|
4958
5083
|
}
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
5084
|
+
async rotateClientSecret(serviceId) {
|
|
5085
|
+
return this.request(
|
|
5086
|
+
`/api/v1/services/${encodeURIComponent(serviceId)}/rotate-secret`,
|
|
5087
|
+
{ method: "POST" }
|
|
5088
|
+
);
|
|
5089
|
+
}
|
|
5090
|
+
// ============ JWKS ============
|
|
5091
|
+
async getJwks(serviceId) {
|
|
5092
|
+
return this.request(`/.well-known/jwks.json?service_id=${encodeURIComponent(serviceId)}`);
|
|
5093
|
+
}
|
|
5094
|
+
// ============ Onboarding (admin only) ============
|
|
4963
5095
|
async onboardService(request, masterAdminKey) {
|
|
4964
5096
|
const response = await this.request("/api/v1/services/onboard", {
|
|
4965
5097
|
method: "POST",
|
|
@@ -4980,9 +5112,6 @@ var AuthMiClient = class {
|
|
|
4980
5112
|
createdAt: response.created_at
|
|
4981
5113
|
};
|
|
4982
5114
|
}
|
|
4983
|
-
/**
|
|
4984
|
-
* Delete a service (requires master admin key)
|
|
4985
|
-
*/
|
|
4986
5115
|
async deleteService(serviceId, masterAdminKey) {
|
|
4987
5116
|
await this.request("/api/v1/services/deboard", {
|
|
4988
5117
|
method: "POST",
|
|
@@ -4992,45 +5121,9 @@ var AuthMiClient = class {
|
|
|
4992
5121
|
body: JSON.stringify({ service_id: serviceId })
|
|
4993
5122
|
});
|
|
4994
5123
|
}
|
|
4995
|
-
// ============ Webhook Management ============
|
|
4996
|
-
/**
|
|
4997
|
-
* List webhooks
|
|
4998
|
-
*/
|
|
4999
|
-
async listWebhooks() {
|
|
5000
|
-
const response = await this.request(
|
|
5001
|
-
"/api/v1/webhooks/list"
|
|
5002
|
-
);
|
|
5003
|
-
return response.webhooks;
|
|
5004
|
-
}
|
|
5005
|
-
/**
|
|
5006
|
-
* Register a webhook
|
|
5007
|
-
*/
|
|
5008
|
-
async registerWebhook(request) {
|
|
5009
|
-
const response = await this.request("/api/v1/webhooks/register", {
|
|
5010
|
-
method: "POST",
|
|
5011
|
-
body: JSON.stringify(request)
|
|
5012
|
-
});
|
|
5013
|
-
return {
|
|
5014
|
-
webhookId: response.webhook_id,
|
|
5015
|
-
url: response.url,
|
|
5016
|
-
events: response.events,
|
|
5017
|
-
active: response.active,
|
|
5018
|
-
createdAt: response.created_at
|
|
5019
|
-
};
|
|
5020
|
-
}
|
|
5021
|
-
/**
|
|
5022
|
-
* Delete a webhook
|
|
5023
|
-
*/
|
|
5024
|
-
async deleteWebhook(webhookId) {
|
|
5025
|
-
await this.request("/api/v1/webhooks/delete", {
|
|
5026
|
-
method: "POST",
|
|
5027
|
-
body: JSON.stringify({ webhook_id: webhookId })
|
|
5028
|
-
});
|
|
5029
|
-
}
|
|
5030
5124
|
};
|
|
5031
5125
|
|
|
5032
5126
|
// src/next.tsx
|
|
5033
|
-
var import_jsx_runtime = require("react/jsx-runtime");
|
|
5034
5127
|
function createAuthMiMiddleware(options) {
|
|
5035
5128
|
return async function middleware(request) {
|
|
5036
5129
|
const {
|
|
@@ -5048,10 +5141,7 @@ function createAuthMiMiddleware(options) {
|
|
|
5048
5141
|
}
|
|
5049
5142
|
const token = request.cookies.get("authmi_token")?.value || request.headers.get("Authorization")?.replace("Bearer ", "");
|
|
5050
5143
|
if (!token) {
|
|
5051
|
-
if (protectedPaths.some((p) => pathname.startsWith(p))) {
|
|
5052
|
-
return import_server.NextResponse.redirect(new URL(loginPath, request.url));
|
|
5053
|
-
}
|
|
5054
|
-
if (Object.keys(scopedPaths).some((p) => pathname.startsWith(p))) {
|
|
5144
|
+
if (protectedPaths.some((p) => pathname.startsWith(p)) || Object.keys(scopedPaths).some((p) => pathname.startsWith(p))) {
|
|
5055
5145
|
return import_server.NextResponse.redirect(new URL(loginPath, request.url));
|
|
5056
5146
|
}
|
|
5057
5147
|
return import_server.NextResponse.next();
|
|
@@ -5083,9 +5173,7 @@ function createAuthMiMiddleware(options) {
|
|
|
5083
5173
|
requestHeaders.set("x-user-email", introspectResult.email || "");
|
|
5084
5174
|
requestHeaders.set("x-user-scopes", JSON.stringify(introspectResult.scopes || []));
|
|
5085
5175
|
return import_server.NextResponse.next({
|
|
5086
|
-
request: {
|
|
5087
|
-
headers: requestHeaders
|
|
5088
|
-
}
|
|
5176
|
+
request: { headers: requestHeaders }
|
|
5089
5177
|
});
|
|
5090
5178
|
} catch (error) {
|
|
5091
5179
|
console.error("Auth middleware error:", error);
|
|
@@ -5096,11 +5184,6 @@ function createAuthMiMiddleware(options) {
|
|
|
5096
5184
|
}
|
|
5097
5185
|
};
|
|
5098
5186
|
}
|
|
5099
|
-
function withScope(Component, _requiredScopes, _config) {
|
|
5100
|
-
return function WithScopeWrapper(props) {
|
|
5101
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, { ...props });
|
|
5102
|
-
};
|
|
5103
|
-
}
|
|
5104
5187
|
async function validateScopes(request, options) {
|
|
5105
5188
|
const { baseUrl, apiKey, requiredScopes, serviceId } = options;
|
|
5106
5189
|
const authHeader = request.headers.get("Authorization");
|
|
@@ -5109,12 +5192,9 @@ async function validateScopes(request, options) {
|
|
|
5109
5192
|
return { valid: false, error: "No token provided", status: 401 };
|
|
5110
5193
|
}
|
|
5111
5194
|
const client = new AuthMiClient({ baseUrl, apiKey, serviceId });
|
|
5112
|
-
if (!serviceId) {
|
|
5113
|
-
return { valid: false, error: "Service ID not configured", status: 500 };
|
|
5114
|
-
}
|
|
5115
5195
|
try {
|
|
5116
5196
|
const result = await client.introspect({
|
|
5117
|
-
serviceId
|
|
5197
|
+
serviceId,
|
|
5118
5198
|
token,
|
|
5119
5199
|
requiredScopes
|
|
5120
5200
|
});
|
|
@@ -5139,10 +5219,7 @@ async function validateScopes(request, options) {
|
|
|
5139
5219
|
0 && (module.exports = {
|
|
5140
5220
|
AuthMiClient,
|
|
5141
5221
|
AuthMiError,
|
|
5142
|
-
LocalStorageTokenStorage,
|
|
5143
|
-
MemoryTokenStorage,
|
|
5144
5222
|
ScopeError,
|
|
5145
5223
|
createAuthMiMiddleware,
|
|
5146
|
-
validateScopes
|
|
5147
|
-
withScope
|
|
5224
|
+
validateScopes
|
|
5148
5225
|
});
|