@drmhse/sso-sdk 0.2.9 → 0.3.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/dist/index.mjs CHANGED
@@ -104,7 +104,7 @@ var HttpClient = class {
104
104
  signal: controller.signal
105
105
  });
106
106
  clearTimeout(timeoutId);
107
- if (response.status === 401 && this.sessionManager && !options._retry && !path.includes("/auth/login")) {
107
+ if (response.status === 401 && this.sessionManager && !options._retry && !path.includes("/auth/login") && !path.includes("/auth/refresh")) {
108
108
  try {
109
109
  const newToken = await this.sessionManager.refreshSession();
110
110
  return this.request(path, {
@@ -688,6 +688,23 @@ var AuthModule = class {
688
688
  const response = await this.http.post("/api/auth/register", payload);
689
689
  return response.data;
690
690
  }
691
+ /**
692
+ * Verify an email address using the token from the verification email.
693
+ *
694
+ * @param token Verification token
695
+ * @returns HTML success page string
696
+ *
697
+ * @example
698
+ * ```typescript
699
+ * const html = await sso.auth.verifyEmail('token-from-email');
700
+ * ```
701
+ */
702
+ async verifyEmail(token) {
703
+ const response = await this.http.get("/auth/verify-email", {
704
+ params: { token }
705
+ });
706
+ return response.data;
707
+ }
691
708
  /**
692
709
  * Login with email and password.
693
710
  * Automatically persists the session and configures the client.
@@ -1447,6 +1464,43 @@ var WebhooksModule = class {
1447
1464
  var OrganizationsModule = class {
1448
1465
  constructor(http) {
1449
1466
  this.http = http;
1467
+ /**
1468
+ * SCIM token management methods
1469
+ */
1470
+ this.scim = {
1471
+ /**
1472
+ * Create a new SCIM token.
1473
+ * The token is only returned once upon creation.
1474
+ */
1475
+ createToken: async (orgSlug, payload) => {
1476
+ const response = await this.http.post(
1477
+ `/api/organizations/${orgSlug}/scim-tokens`,
1478
+ payload
1479
+ );
1480
+ return response.data;
1481
+ },
1482
+ /**
1483
+ * List all SCIM tokens.
1484
+ */
1485
+ listTokens: async (orgSlug) => {
1486
+ const response = await this.http.get(
1487
+ `/api/organizations/${orgSlug}/scim-tokens`
1488
+ );
1489
+ return response.data;
1490
+ },
1491
+ /**
1492
+ * Revoke a SCIM token.
1493
+ */
1494
+ revokeToken: async (orgSlug, tokenId) => {
1495
+ await this.http.post(`/api/organizations/${orgSlug}/scim-tokens/${tokenId}/revoke`);
1496
+ },
1497
+ /**
1498
+ * Delete a SCIM token.
1499
+ */
1500
+ deleteToken: async (orgSlug, tokenId) => {
1501
+ await this.http.delete(`/api/organizations/${orgSlug}/scim-tokens/${tokenId}`);
1502
+ }
1503
+ };
1450
1504
  /**
1451
1505
  * Member management methods
1452
1506
  */
@@ -1470,6 +1524,24 @@ var OrganizationsModule = class {
1470
1524
  );
1471
1525
  return response.data;
1472
1526
  },
1527
+ /**
1528
+ * Add a member to the organization (Invite + Accept).
1529
+ * This is a convenience method that creates an invitation and immediately accepts it.
1530
+ * Useful for testing and admin operations.
1531
+ *
1532
+ * @param orgSlug Organization slug
1533
+ * @param payload Member details (email, role)
1534
+ * @returns The created invitation
1535
+ */
1536
+ add: async (orgSlug, payload) => {
1537
+ const response = await this.http.post(
1538
+ `/api/organizations/${orgSlug}/invitations`,
1539
+ payload
1540
+ );
1541
+ const invitation = response.data;
1542
+ await this.http.post("/api/invitations/accept", { token: invitation.token });
1543
+ return invitation;
1544
+ },
1473
1545
  /**
1474
1546
  * Update a member's role.
1475
1547
  * Requires 'owner' role.
@@ -2511,6 +2583,26 @@ var ServicesModule = class {
2511
2583
  );
2512
2584
  return response.data;
2513
2585
  },
2586
+ /**
2587
+ * Initiate an IdP-initiated SAML login.
2588
+ * Returns an HTML page with an auto-submitting form that POSTs the SAML assertion to the Service Provider.
2589
+ *
2590
+ * @param orgSlug Organization slug
2591
+ * @param serviceSlug Service slug
2592
+ * @returns HTML page with auto-submitting form
2593
+ *
2594
+ * @example
2595
+ * ```typescript
2596
+ * const html = await sso.services.saml.initiateLogin('acme-corp', 'salesforce');
2597
+ * document.body.innerHTML = html; // Auto-submits
2598
+ * ```
2599
+ */
2600
+ initiateLogin: async (orgSlug, serviceSlug) => {
2601
+ const response = await this.http.get(
2602
+ `/api/organizations/${orgSlug}/services/${serviceSlug}/saml/login`
2603
+ );
2604
+ return response.data;
2605
+ },
2514
2606
  /**
2515
2607
  * Generate a new SAML signing certificate for the IdP.
2516
2608
  * Requires 'owner' or 'admin' role.
@@ -2764,7 +2856,7 @@ var InvitationsModule = class {
2764
2856
  * @example
2765
2857
  * ```typescript
2766
2858
  * const invitation = await sso.invitations.create('acme-corp', {
2767
- * invitee_email: 'newuser@example.com',
2859
+ * email: 'newuser@example.com',
2768
2860
  * role: 'member'
2769
2861
  * });
2770
2862
  * ```
@@ -3300,6 +3392,78 @@ var ServiceApiModule = class {
3300
3392
  constructor(http) {
3301
3393
  this.http = http;
3302
3394
  }
3395
+ /**
3396
+ * List all users for the service
3397
+ * Requires 'read:users' permission on the API key
3398
+ *
3399
+ * @param params Optional pagination parameters
3400
+ * @returns List of users with total count
3401
+ */
3402
+ async listUsers(params) {
3403
+ const queryParams = new URLSearchParams();
3404
+ if (params?.limit) queryParams.set("limit", params.limit.toString());
3405
+ if (params?.offset) queryParams.set("offset", params.offset.toString());
3406
+ const query = queryParams.toString() ? `?${queryParams.toString()}` : "";
3407
+ const response = await this.http.get(`/api/service/users${query}`);
3408
+ return response.data;
3409
+ }
3410
+ /**
3411
+ * Get a specific user by ID
3412
+ * Requires 'read:users' permission on the API key
3413
+ *
3414
+ * @param userId User ID to retrieve
3415
+ * @returns User details
3416
+ */
3417
+ async getUser(userId) {
3418
+ const response = await this.http.get(`/api/service/users/${userId}`);
3419
+ return response.data;
3420
+ }
3421
+ /**
3422
+ * List all subscriptions for the service
3423
+ * Requires 'read:subscriptions' permission on the API key
3424
+ *
3425
+ * @param params Optional pagination parameters
3426
+ * @returns List of subscriptions with total count
3427
+ */
3428
+ async listSubscriptions(params) {
3429
+ const queryParams = new URLSearchParams();
3430
+ if (params?.limit) queryParams.set("limit", params.limit.toString());
3431
+ if (params?.offset) queryParams.set("offset", params.offset.toString());
3432
+ const query = queryParams.toString() ? `?${queryParams.toString()}` : "";
3433
+ const response = await this.http.get(`/api/service/subscriptions${query}`);
3434
+ return response.data;
3435
+ }
3436
+ /**
3437
+ * Get subscription for a specific user
3438
+ * Requires 'read:subscriptions' permission on the API key
3439
+ *
3440
+ * @param userId User ID whose subscription to retrieve
3441
+ * @returns User's subscription
3442
+ */
3443
+ async getSubscription(userId) {
3444
+ const response = await this.http.get(`/api/service/subscriptions/${userId}`);
3445
+ return response.data;
3446
+ }
3447
+ /**
3448
+ * Get analytics for the service
3449
+ * Requires 'read:analytics' permission on the API key
3450
+ *
3451
+ * @returns Service analytics data
3452
+ */
3453
+ async getAnalytics() {
3454
+ const response = await this.http.get("/api/service/analytics");
3455
+ return response.data;
3456
+ }
3457
+ /**
3458
+ * Get service information
3459
+ * Requires 'read:service' permission on the API key
3460
+ *
3461
+ * @returns Service information
3462
+ */
3463
+ async getServiceInfo() {
3464
+ const response = await this.http.get("/api/service/info");
3465
+ return response.data;
3466
+ }
3303
3467
  /**
3304
3468
  * Create a new user
3305
3469
  * Requires 'write:users' permission on the API key
@@ -3723,15 +3887,40 @@ var PasskeysModule = class {
3723
3887
  * }
3724
3888
  * ```
3725
3889
  */
3890
+ /**
3891
+ * Start the passkey registration ceremony.
3892
+ * returns the options required to create credentials in the browser.
3893
+ */
3894
+ async registerStart(displayName) {
3895
+ const response = await this.http.post(
3896
+ "/api/auth/passkeys/register/start",
3897
+ { name: displayName }
3898
+ );
3899
+ return response.data;
3900
+ }
3901
+ /**
3902
+ * Finish the passkey registration ceremony.
3903
+ * Verifies the credential created by the browser.
3904
+ */
3905
+ async registerFinish(challengeId, credential) {
3906
+ const response = await this.http.post(
3907
+ "/api/auth/passkeys/register/finish",
3908
+ {
3909
+ challenge_id: challengeId,
3910
+ credential
3911
+ }
3912
+ );
3913
+ return response.data;
3914
+ }
3915
+ /**
3916
+ * Register a new passkey for the authenticated user
3917
+ * ...
3918
+ */
3726
3919
  async register(displayName) {
3727
3920
  if (!this.isSupported()) {
3728
3921
  throw new Error("WebAuthn is not supported in this browser");
3729
3922
  }
3730
- const startResponse = await this.http.post(
3731
- "/auth/passkeys/register/start",
3732
- { name: displayName }
3733
- );
3734
- const startData = startResponse.data;
3923
+ const startData = await this.registerStart(displayName);
3735
3924
  const createOptions = {
3736
3925
  publicKey: {
3737
3926
  ...startData.options,
@@ -3765,14 +3954,8 @@ var PasskeysModule = class {
3765
3954
  clientExtensionResults: credential.getClientExtensionResults(),
3766
3955
  type: credential.type
3767
3956
  };
3768
- const finishResponse = await this.http.post(
3769
- "/auth/passkeys/register/finish",
3770
- {
3771
- challenge_id: startData.challenge_id,
3772
- credential: credentialJSON
3773
- }
3774
- );
3775
- return finishResponse.data.passkey_id;
3957
+ const finishResponse = await this.registerFinish(startData.challenge_id, credentialJSON);
3958
+ return finishResponse.passkey_id;
3776
3959
  }
3777
3960
  /**
3778
3961
  * Authenticate with a passkey and obtain a JWT token
@@ -3796,16 +3979,40 @@ var PasskeysModule = class {
3796
3979
  * }
3797
3980
  * ```
3798
3981
  */
3982
+ /**
3983
+ * Start the passkey authentication ceremony.
3984
+ * Returns the options required to get credentials from the browser.
3985
+ */
3986
+ async authenticateStart(email) {
3987
+ const response = await this.http.post(
3988
+ "/api/auth/passkeys/authenticate/start",
3989
+ { email }
3990
+ );
3991
+ return response.data;
3992
+ }
3993
+ /**
3994
+ * Finish the passkey authentication ceremony.
3995
+ * Verifies the assertion returned by the browser.
3996
+ */
3997
+ async authenticateFinish(challengeId, credential) {
3998
+ const response = await this.http.post(
3999
+ "/api/auth/passkeys/authenticate/finish",
4000
+ {
4001
+ challenge_id: challengeId,
4002
+ credential
4003
+ }
4004
+ );
4005
+ return response.data;
4006
+ }
4007
+ /**
4008
+ * Authenticate with a passkey and obtain a JWT token
4009
+ * ...
4010
+ */
3799
4011
  async login(email) {
3800
4012
  if (!this.isSupported()) {
3801
4013
  throw new Error("WebAuthn is not supported in this browser");
3802
4014
  }
3803
- const startRequest = { email };
3804
- const startResponse = await this.http.post(
3805
- "/auth/passkeys/authenticate/start",
3806
- startRequest
3807
- );
3808
- const startData = startResponse.data;
4015
+ const startData = await this.authenticateStart(email);
3809
4016
  const getOptions = {
3810
4017
  publicKey: {
3811
4018
  ...startData.options,
@@ -3836,14 +4043,7 @@ var PasskeysModule = class {
3836
4043
  clientExtensionResults: credential.getClientExtensionResults(),
3837
4044
  type: credential.type
3838
4045
  };
3839
- const finishResponse = await this.http.post(
3840
- "/auth/passkeys/authenticate/finish",
3841
- {
3842
- challenge_id: startData.challenge_id,
3843
- credential: credentialJSON
3844
- }
3845
- );
3846
- return finishResponse.data;
4046
+ return this.authenticateFinish(startData.challenge_id, credentialJSON);
3847
4047
  }
3848
4048
  /**
3849
4049
  * Convert Base64URL string to Uint8Array
@@ -4016,6 +4216,10 @@ var SsoClient = class {
4016
4216
  * Sets the JWT for all subsequent authenticated requests.
4017
4217
  * Pass null to clear the token.
4018
4218
  *
4219
+ * NOTE: For OAuth callback flows, prefer using setSession() which properly
4220
+ * updates the SessionManager. This method updates both the HTTP headers
4221
+ * AND the SessionManager for backward compatibility.
4222
+ *
4019
4223
  * @param token The JWT string, or null to clear
4020
4224
  *
4021
4225
  * @example
@@ -4030,10 +4234,30 @@ var SsoClient = class {
4030
4234
  setAuthToken(token) {
4031
4235
  if (token) {
4032
4236
  this.http.defaults.headers.common["Authorization"] = `Bearer ${token}`;
4237
+ this.session.setSession({ access_token: token });
4033
4238
  } else {
4034
4239
  delete this.http.defaults.headers.common["Authorization"];
4240
+ this.session.clearSession();
4035
4241
  }
4036
4242
  }
4243
+ /**
4244
+ * Sets the session tokens for OAuth callback flows.
4245
+ * This properly updates the SessionManager and persists tokens to storage.
4246
+ *
4247
+ * @param tokens Object containing access_token and optionally refresh_token
4248
+ *
4249
+ * @example
4250
+ * ```typescript
4251
+ * // After OAuth callback
4252
+ * await sso.setSession({
4253
+ * access_token: accessToken,
4254
+ * refresh_token: refreshToken
4255
+ * });
4256
+ * ```
4257
+ */
4258
+ async setSession(tokens) {
4259
+ await this.session.setSession(tokens);
4260
+ }
4037
4261
  /**
4038
4262
  * Sets the API key for service-to-service authentication.
4039
4263
  * Pass null to clear the API key.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@drmhse/sso-sdk",
3
- "version": "0.2.9",
4
- "description": "Zero-dependency TypeScript SDK for the multi-tenant SSO Platform API",
3
+ "version": "0.3.1",
4
+ "description": "Zero-dependency TypeScript SDK for AuthOS, the multi-tenant authentication platform",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",