@hanzo/iam 0.4.0 → 0.4.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hanzo/iam",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "description": "TypeScript SDK for Hanzo IAM — OIDC auth, JWT validation, OAuth2 PKCE, user/org/project APIs",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -33,14 +33,6 @@
33
33
  "./nextauth": {
34
34
  "types": "./dist/nextauth.d.ts",
35
35
  "import": "./dist/nextauth.js"
36
- },
37
- "./passport": {
38
- "types": "./dist/passport.d.ts",
39
- "import": "./dist/passport.js"
40
- },
41
- "./betterauth": {
42
- "types": "./dist/betterauth.d.ts",
43
- "import": "./dist/betterauth.js"
44
36
  }
45
37
  },
46
38
  "files": [
@@ -53,8 +45,8 @@
53
45
  "build": "tsc",
54
46
  "dev": "tsc --watch",
55
47
  "clean": "rm -rf dist",
56
- "prepare": "pnpm clean && pnpm build",
57
- "prepublishOnly": "pnpm clean && pnpm build",
48
+ "prepare": "npm run clean && npm run build",
49
+ "prepublishOnly": "npm run clean && npm run build",
58
50
  "test": "node --test --import tsx src/**/*.test.ts"
59
51
  },
60
52
  "dependencies": {
package/src/browser.ts CHANGED
@@ -80,8 +80,8 @@ export class BrowserIamSdk {
80
80
  this.discoveryCache = {
81
81
  issuer: baseUrl,
82
82
  authorization_endpoint: `${baseUrl}/login/oauth/authorize`,
83
- token_endpoint: `${baseUrl}/api/login/oauth/access_token`,
84
- userinfo_endpoint: `${baseUrl}/api/userinfo`,
83
+ token_endpoint: `${baseUrl}/oauth/token`,
84
+ userinfo_endpoint: `${baseUrl}/oauth/userinfo`,
85
85
  jwks_uri: `${baseUrl}/.well-known/jwks`,
86
86
  response_types_supported: ["code", "token", "id_token"],
87
87
  grant_types_supported: ["authorization_code", "implicit", "refresh_token"],
package/src/client.ts CHANGED
@@ -7,6 +7,7 @@ import type {
7
7
  IamApiResponse,
8
8
  IamUser,
9
9
  IamOrganization,
10
+ IamInvitation,
10
11
  IamProject,
11
12
  OidcDiscovery,
12
13
  TokenResponse,
@@ -289,6 +290,88 @@ export class IamClient {
289
290
  return org ? [org] : [];
290
291
  }
291
292
 
293
+ /** Create a new organization. */
294
+ async createOrganization(
295
+ org: Partial<IamOrganization>,
296
+ token?: string,
297
+ ): Promise<IamApiResponse<IamOrganization>> {
298
+ return this.request<IamApiResponse<IamOrganization>>(
299
+ "/api/add-organization",
300
+ { method: "POST", body: org, token },
301
+ );
302
+ }
303
+
304
+ /** Update an existing organization. */
305
+ async updateOrganization(
306
+ org: Partial<IamOrganization>,
307
+ token?: string,
308
+ ): Promise<IamApiResponse<IamOrganization>> {
309
+ return this.request<IamApiResponse<IamOrganization>>(
310
+ "/api/update-organization",
311
+ { method: "POST", body: org, token },
312
+ );
313
+ }
314
+
315
+ /** Delete an organization by owner and name. */
316
+ async deleteOrganization(
317
+ org: { owner: string; name: string },
318
+ token?: string,
319
+ ): Promise<IamApiResponse<IamOrganization>> {
320
+ return this.request<IamApiResponse<IamOrganization>>(
321
+ "/api/delete-organization",
322
+ { method: "POST", body: org, token },
323
+ );
324
+ }
325
+
326
+ // -----------------------------------------------------------------------
327
+ // Invitation
328
+ // -----------------------------------------------------------------------
329
+
330
+ /** List invitations for an owner (organization). */
331
+ async getInvitations(
332
+ owner: string,
333
+ token?: string,
334
+ ): Promise<IamInvitation[]> {
335
+ const resp = await this.request<IamApiResponse<IamInvitation[]>>(
336
+ "/api/get-invitations",
337
+ { params: { owner }, token },
338
+ );
339
+ return resp.data ?? [];
340
+ }
341
+
342
+ /** Create a new invitation. */
343
+ async createInvitation(
344
+ invitation: Partial<IamInvitation>,
345
+ token?: string,
346
+ ): Promise<IamApiResponse<IamInvitation>> {
347
+ return this.request<IamApiResponse<IamInvitation>>(
348
+ "/api/add-invitation",
349
+ { method: "POST", body: invitation, token },
350
+ );
351
+ }
352
+
353
+ /** Send an invitation by owner and name. */
354
+ async sendInvitation(
355
+ invitation: { owner: string; name: string },
356
+ token?: string,
357
+ ): Promise<IamApiResponse<IamInvitation>> {
358
+ return this.request<IamApiResponse<IamInvitation>>(
359
+ "/api/send-invitation",
360
+ { method: "POST", body: invitation, token },
361
+ );
362
+ }
363
+
364
+ /** Verify an invitation code. */
365
+ async verifyInvitation(
366
+ code: string,
367
+ token?: string,
368
+ ): Promise<IamApiResponse<IamInvitation>> {
369
+ return this.request<IamApiResponse<IamInvitation>>(
370
+ "/api/verify-invitation",
371
+ { params: { code }, token },
372
+ );
373
+ }
374
+
292
375
  // -----------------------------------------------------------------------
293
376
  // Project
294
377
  // -----------------------------------------------------------------------
package/src/index.ts CHANGED
@@ -14,7 +14,7 @@
14
14
  * });
15
15
  *
16
16
  * const billing = new BillingClient({
17
- * commerceUrl: "https://commerce.hanzo.ai",
17
+ * commerceUrl: "https://commerce-api.hanzo.ai/api",
18
18
  * });
19
19
  * ```
20
20
  */
@@ -43,6 +43,7 @@ export type {
43
43
  IamJwtClaims,
44
44
  IamUser,
45
45
  IamOrganization,
46
+ IamInvitation,
46
47
  IamProject,
47
48
  Subscription,
48
49
  Plan,
package/src/react.ts CHANGED
@@ -46,7 +46,7 @@ import type { ReactNode } from "react";
46
46
  import { BrowserIamSdk } from "./browser.js";
47
47
  import type { BrowserIamConfig } from "./browser.js";
48
48
  import { IamClient } from "./client.js";
49
- import type { IamUser, IamOrganization, IamProject, TokenResponse } from "./types.js";
49
+ import type { IamUser, IamOrganization, IamInvitation, IamProject, TokenResponse } from "./types.js";
50
50
 
51
51
  // ---------------------------------------------------------------------------
52
52
  // Types
@@ -589,6 +589,200 @@ export function useIamToken(): {
589
589
  };
590
590
  }
591
591
 
592
+ // ---------------------------------------------------------------------------
593
+ // useOrgManagement
594
+ // ---------------------------------------------------------------------------
595
+
596
+ export interface OrgManagementState {
597
+ /** Create a new organization. */
598
+ createOrg: (org: Partial<IamOrganization>) => Promise<void>;
599
+ /** Update an existing organization. */
600
+ updateOrg: (org: Partial<IamOrganization>) => Promise<void>;
601
+ /** Delete an organization by owner and name. */
602
+ deleteOrg: (org: { owner: string; name: string }) => Promise<void>;
603
+ /** Whether a mutation is in progress. */
604
+ isLoading: boolean;
605
+ }
606
+
607
+ /**
608
+ * Manage organization CRUD operations.
609
+ *
610
+ * Provides create, update, and delete methods that call the IAM API
611
+ * using the current user's access token.
612
+ */
613
+ export function useOrgManagement(): OrgManagementState {
614
+ const { config, accessToken } = useIam();
615
+ const [isLoading, setIsLoading] = useState(false);
616
+
617
+ const client = useMemo(
618
+ () =>
619
+ new IamClient({
620
+ serverUrl: config.serverUrl,
621
+ clientId: config.clientId,
622
+ }),
623
+ [config.serverUrl, config.clientId],
624
+ );
625
+
626
+ const createOrg = useCallback(
627
+ async (org: Partial<IamOrganization>) => {
628
+ setIsLoading(true);
629
+ try {
630
+ await client.createOrganization(org, accessToken ?? undefined);
631
+ } finally {
632
+ setIsLoading(false);
633
+ }
634
+ },
635
+ [client, accessToken],
636
+ );
637
+
638
+ const updateOrg = useCallback(
639
+ async (org: Partial<IamOrganization>) => {
640
+ setIsLoading(true);
641
+ try {
642
+ await client.updateOrganization(org, accessToken ?? undefined);
643
+ } finally {
644
+ setIsLoading(false);
645
+ }
646
+ },
647
+ [client, accessToken],
648
+ );
649
+
650
+ const deleteOrg = useCallback(
651
+ async (org: { owner: string; name: string }) => {
652
+ setIsLoading(true);
653
+ try {
654
+ await client.deleteOrganization(org, accessToken ?? undefined);
655
+ } finally {
656
+ setIsLoading(false);
657
+ }
658
+ },
659
+ [client, accessToken],
660
+ );
661
+
662
+ return { createOrg, updateOrg, deleteOrg, isLoading };
663
+ }
664
+
665
+ // ---------------------------------------------------------------------------
666
+ // useInvitations
667
+ // ---------------------------------------------------------------------------
668
+
669
+ export interface InvitationsState {
670
+ /** All invitations for the organization. */
671
+ invitations: IamInvitation[];
672
+ /** Create a new invitation. */
673
+ createInvite: (invitation: Partial<IamInvitation>) => Promise<void>;
674
+ /** Send an existing invitation. */
675
+ sendInvite: (invitation: { owner: string; name: string }) => Promise<void>;
676
+ /** Verify an invitation code. */
677
+ verifyInvite: (code: string) => Promise<IamInvitation | null>;
678
+ /** Whether invitations are loading. */
679
+ isLoading: boolean;
680
+ /** Re-fetch the invitations list. */
681
+ refresh: () => Promise<void>;
682
+ }
683
+
684
+ /**
685
+ * Manage invitations for an organization.
686
+ *
687
+ * Fetches the invitation list on mount and provides create, send,
688
+ * and verify methods using the current user's access token.
689
+ */
690
+ export function useInvitations(orgName: string): InvitationsState {
691
+ const { config, accessToken, isAuthenticated } = useIam();
692
+ const [invitations, setInvitations] = useState<IamInvitation[]>([]);
693
+ const [isLoading, setIsLoading] = useState(false);
694
+
695
+ const client = useMemo(
696
+ () =>
697
+ new IamClient({
698
+ serverUrl: config.serverUrl,
699
+ clientId: config.clientId,
700
+ }),
701
+ [config.serverUrl, config.clientId],
702
+ );
703
+
704
+ const fetchInvitations = useCallback(async () => {
705
+ if (!isAuthenticated || !accessToken || !orgName) return;
706
+ setIsLoading(true);
707
+ try {
708
+ const data = await client.getInvitations(orgName, accessToken);
709
+ setInvitations(data);
710
+ } catch {
711
+ setInvitations([]);
712
+ } finally {
713
+ setIsLoading(false);
714
+ }
715
+ }, [client, orgName, accessToken, isAuthenticated]);
716
+
717
+ // Fetch invitations on mount and when orgName changes
718
+ useEffect(() => {
719
+ if (!isAuthenticated || !accessToken || !orgName) {
720
+ setInvitations([]);
721
+ return;
722
+ }
723
+
724
+ let cancelled = false;
725
+
726
+ const load = async () => {
727
+ setIsLoading(true);
728
+ try {
729
+ const data = await client.getInvitations(orgName, accessToken);
730
+ if (!cancelled) setInvitations(data);
731
+ } catch {
732
+ if (!cancelled) setInvitations([]);
733
+ } finally {
734
+ if (!cancelled) setIsLoading(false);
735
+ }
736
+ };
737
+
738
+ load();
739
+ return () => {
740
+ cancelled = true;
741
+ };
742
+ // eslint-disable-next-line react-hooks/exhaustive-deps
743
+ }, [isAuthenticated, accessToken, orgName, config.serverUrl, config.clientId]);
744
+
745
+ const createInvite = useCallback(
746
+ async (invitation: Partial<IamInvitation>) => {
747
+ setIsLoading(true);
748
+ try {
749
+ await client.createInvitation(invitation, accessToken ?? undefined);
750
+ await fetchInvitations();
751
+ } finally {
752
+ setIsLoading(false);
753
+ }
754
+ },
755
+ [client, accessToken, fetchInvitations],
756
+ );
757
+
758
+ const sendInvite = useCallback(
759
+ async (invitation: { owner: string; name: string }) => {
760
+ setIsLoading(true);
761
+ try {
762
+ await client.sendInvitation(invitation, accessToken ?? undefined);
763
+ } finally {
764
+ setIsLoading(false);
765
+ }
766
+ },
767
+ [client, accessToken],
768
+ );
769
+
770
+ const verifyInvite = useCallback(
771
+ async (code: string): Promise<IamInvitation | null> => {
772
+ setIsLoading(true);
773
+ try {
774
+ const resp = await client.verifyInvitation(code, accessToken ?? undefined);
775
+ return resp.data ?? null;
776
+ } finally {
777
+ setIsLoading(false);
778
+ }
779
+ },
780
+ [client, accessToken],
781
+ );
782
+
783
+ return { invitations, createInvite, sendInvite, verifyInvite, isLoading, refresh: fetchInvitations };
784
+ }
785
+
592
786
  // Re-export context for advanced use
593
787
  export { IamContext };
594
788
 
package/src/types.ts CHANGED
@@ -226,6 +226,26 @@ export type IamOrder = Order;
226
226
  export type IamUsageRecord = UsageRecord;
227
227
  export type IamUsageSummary = UsageSummary;
228
228
 
229
+ // ---------------------------------------------------------------------------
230
+ // Invitation
231
+ // ---------------------------------------------------------------------------
232
+
233
+ export type IamInvitation = {
234
+ owner: string;
235
+ name: string;
236
+ displayName?: string;
237
+ code: string;
238
+ quota: number;
239
+ usedCount: number;
240
+ application?: string;
241
+ email?: string;
242
+ phone?: string;
243
+ signupGroup?: string;
244
+ state?: string;
245
+ createdTime?: string;
246
+ updatedTime?: string;
247
+ };
248
+
229
249
  // ---------------------------------------------------------------------------
230
250
  // Project
231
251
  // ---------------------------------------------------------------------------
@@ -1,62 +0,0 @@
1
- /**
2
- * BetterAuth SSO provider configuration for Hanzo IAM.
3
- *
4
- * Returns a provider config object compatible with BetterAuth's
5
- * `socialProviders` or generic OAuth plugin.
6
- *
7
- * @example
8
- * ```ts
9
- * import { betterAuth } from "better-auth";
10
- * import { hanzoIamProvider } from "@hanzo/iam/betterauth";
11
- *
12
- * export const auth = betterAuth({
13
- * socialProviders: [
14
- * hanzoIamProvider({
15
- * serverUrl: process.env.IAM_SERVER_URL!,
16
- * clientId: process.env.IAM_CLIENT_ID!,
17
- * clientSecret: process.env.IAM_CLIENT_SECRET!,
18
- * }),
19
- * ],
20
- * });
21
- * ```
22
- *
23
- * @packageDocumentation
24
- */
25
- import type { IamConfig } from "./types.js";
26
- export interface HanzoIamSocialProvider {
27
- id: string;
28
- name: string;
29
- type: "oidc";
30
- issuer: string;
31
- clientId: string;
32
- clientSecret?: string;
33
- authorization: {
34
- url: string;
35
- params: {
36
- scope: string;
37
- };
38
- };
39
- token: {
40
- url: string;
41
- };
42
- userinfo: {
43
- url: string;
44
- };
45
- profile: (profile: Record<string, unknown>) => {
46
- id: string;
47
- name: string;
48
- email: string;
49
- image: string | null;
50
- };
51
- }
52
- /**
53
- * Create a BetterAuth-compatible social provider for Hanzo IAM.
54
- *
55
- * Works with BetterAuth's SSO plugin or generic OAuth integration.
56
- * Uses the standard Hanzo IAM / Casdoor OIDC endpoints.
57
- */
58
- export declare function hanzoIamProvider(config: IamConfig & {
59
- redirectUri?: string;
60
- }): HanzoIamSocialProvider;
61
- export { hanzoIamProvider as hanzoIamSocialProvider };
62
- //# sourceMappingURL=betterauth.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"betterauth.d.ts","sourceRoot":"","sources":["../src/betterauth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE;YAAE,KAAK,EAAE,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;IAC1D,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IACvB,QAAQ,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1B,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK;QAC7C,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;KACtB,CAAC;CACH;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,SAAS,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3C,sBAAsB,CA6BxB;AAGD,OAAO,EAAE,gBAAgB,IAAI,sBAAsB,EAAE,CAAC"}
@@ -1,61 +0,0 @@
1
- /**
2
- * BetterAuth SSO provider configuration for Hanzo IAM.
3
- *
4
- * Returns a provider config object compatible with BetterAuth's
5
- * `socialProviders` or generic OAuth plugin.
6
- *
7
- * @example
8
- * ```ts
9
- * import { betterAuth } from "better-auth";
10
- * import { hanzoIamProvider } from "@hanzo/iam/betterauth";
11
- *
12
- * export const auth = betterAuth({
13
- * socialProviders: [
14
- * hanzoIamProvider({
15
- * serverUrl: process.env.IAM_SERVER_URL!,
16
- * clientId: process.env.IAM_CLIENT_ID!,
17
- * clientSecret: process.env.IAM_CLIENT_SECRET!,
18
- * }),
19
- * ],
20
- * });
21
- * ```
22
- *
23
- * @packageDocumentation
24
- */
25
- /**
26
- * Create a BetterAuth-compatible social provider for Hanzo IAM.
27
- *
28
- * Works with BetterAuth's SSO plugin or generic OAuth integration.
29
- * Uses the standard Hanzo IAM / Casdoor OIDC endpoints.
30
- */
31
- export function hanzoIamProvider(config) {
32
- const baseUrl = config.serverUrl.replace(/\/+$/, "");
33
- return {
34
- id: "hanzo-iam",
35
- name: "Hanzo IAM",
36
- type: "oidc",
37
- issuer: baseUrl,
38
- clientId: config.clientId,
39
- clientSecret: config.clientSecret,
40
- authorization: {
41
- url: `${baseUrl}/login/oauth/authorize`,
42
- params: { scope: "openid profile email" },
43
- },
44
- token: { url: `${baseUrl}/api/login/oauth/access_token` },
45
- userinfo: { url: `${baseUrl}/api/userinfo` },
46
- profile(profile) {
47
- return {
48
- id: profile.sub ?? profile.id ?? "",
49
- name: profile.displayName ??
50
- profile.name ??
51
- profile.preferred_username ??
52
- "",
53
- email: profile.email ?? "",
54
- image: profile.avatar ?? profile.picture ?? null,
55
- };
56
- },
57
- };
58
- }
59
- // Backwards-compatible alias
60
- export { hanzoIamProvider as hanzoIamSocialProvider };
61
- //# sourceMappingURL=betterauth.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"betterauth.js","sourceRoot":"","sources":["../src/betterauth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAsBH;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAA4C;IAE5C,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAErD,OAAO;QACL,EAAE,EAAE,WAAW;QACf,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,MAAM;QACZ,MAAM,EAAE,OAAO;QACf,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,aAAa,EAAE;YACb,GAAG,EAAE,GAAG,OAAO,wBAAwB;YACvC,MAAM,EAAE,EAAE,KAAK,EAAE,sBAAsB,EAAE;SAC1C;QACD,KAAK,EAAE,EAAE,GAAG,EAAE,GAAG,OAAO,+BAA+B,EAAE;QACzD,QAAQ,EAAE,EAAE,GAAG,EAAE,GAAG,OAAO,eAAe,EAAE;QAC5C,OAAO,CAAC,OAAgC;YACtC,OAAO;gBACL,EAAE,EAAG,OAAO,CAAC,GAAc,IAAK,OAAO,CAAC,EAAa,IAAI,EAAE;gBAC3D,IAAI,EACD,OAAO,CAAC,WAAsB;oBAC9B,OAAO,CAAC,IAAe;oBACvB,OAAO,CAAC,kBAA6B;oBACtC,EAAE;gBACJ,KAAK,EAAG,OAAO,CAAC,KAAgB,IAAI,EAAE;gBACtC,KAAK,EAAG,OAAO,CAAC,MAAiB,IAAK,OAAO,CAAC,OAAkB,IAAI,IAAI;aACzE,CAAC;QACJ,CAAC;KACF,CAAC;AACJ,CAAC;AAED,6BAA6B;AAC7B,OAAO,EAAE,gBAAgB,IAAI,sBAAsB,EAAE,CAAC"}
@@ -1,44 +0,0 @@
1
- /**
2
- * Passport.js OAuth2 strategy factory for Hanzo IAM.
3
- *
4
- * Creates a pre-configured passport-oauth2 strategy that authenticates
5
- * against hanzo.id with PKCE and fetches user info on callback.
6
- *
7
- * @example
8
- * ```ts
9
- * import passport from "passport";
10
- * import { createIamPassportStrategy } from "@hanzo/iam/passport";
11
- *
12
- * passport.use("iam", createIamPassportStrategy({
13
- * serverUrl: "https://hanzo.id",
14
- * clientId: "hanzo-kms-client-id",
15
- * clientSecret: process.env.IAM_CLIENT_SECRET!,
16
- * callbackUrl: "https://kms.hanzo.ai/api/v1/sso/oidc/callback",
17
- * }));
18
- * ```
19
- *
20
- * @packageDocumentation
21
- */
22
- import type { IamConfig } from "./types.js";
23
- export interface IamPassportConfig extends IamConfig {
24
- /** Full callback URL for OAuth2 redirect. */
25
- callbackUrl: string;
26
- /** OAuth2 scopes. Default: "openid profile email". */
27
- scope?: string;
28
- }
29
- export interface IamPassportUser {
30
- accessToken: string;
31
- refreshToken?: string;
32
- userinfo: Record<string, unknown>;
33
- }
34
- /**
35
- * Create a Passport OAuth2 strategy for Hanzo IAM.
36
- *
37
- * Requires `passport-oauth2` as a peer dependency.
38
- * Returns an OAuth2Strategy instance ready to pass to `passport.use()`.
39
- *
40
- * The verify callback fetches userinfo from the IAM server and passes
41
- * `{ accessToken, refreshToken, userinfo }` as the user object.
42
- */
43
- export declare function createIamPassportStrategy(config: IamPassportConfig): unknown;
44
- //# sourceMappingURL=passport.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"passport.d.ts","sourceRoot":"","sources":["../src/passport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,MAAM,WAAW,iBAAkB,SAAQ,SAAS;IAClD,6CAA6C;IAC7C,WAAW,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACnC;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,iBAAiB,GACxB,OAAO,CAgDT"}
package/dist/passport.js DELETED
@@ -1,67 +0,0 @@
1
- /**
2
- * Passport.js OAuth2 strategy factory for Hanzo IAM.
3
- *
4
- * Creates a pre-configured passport-oauth2 strategy that authenticates
5
- * against hanzo.id with PKCE and fetches user info on callback.
6
- *
7
- * @example
8
- * ```ts
9
- * import passport from "passport";
10
- * import { createIamPassportStrategy } from "@hanzo/iam/passport";
11
- *
12
- * passport.use("iam", createIamPassportStrategy({
13
- * serverUrl: "https://hanzo.id",
14
- * clientId: "hanzo-kms-client-id",
15
- * clientSecret: process.env.IAM_CLIENT_SECRET!,
16
- * callbackUrl: "https://kms.hanzo.ai/api/v1/sso/oidc/callback",
17
- * }));
18
- * ```
19
- *
20
- * @packageDocumentation
21
- */
22
- /**
23
- * Create a Passport OAuth2 strategy for Hanzo IAM.
24
- *
25
- * Requires `passport-oauth2` as a peer dependency.
26
- * Returns an OAuth2Strategy instance ready to pass to `passport.use()`.
27
- *
28
- * The verify callback fetches userinfo from the IAM server and passes
29
- * `{ accessToken, refreshToken, userinfo }` as the user object.
30
- */
31
- export function createIamPassportStrategy(config) {
32
- // Dynamic import to keep passport-oauth2 as optional peer dep.
33
- // eslint-disable-next-line @typescript-eslint/no-require-imports
34
- const { Strategy: OAuth2Strategy } = require("passport-oauth2");
35
- const baseUrl = config.serverUrl.replace(/\/+$/, "");
36
- const verify = async (...args) => {
37
- // passReqToCallback=true: (req, accessToken, refreshToken, profile, done)
38
- const accessToken = args[1];
39
- const refreshToken = args[2];
40
- const done = args[4];
41
- try {
42
- const res = await fetch(`${baseUrl}/api/userinfo`, {
43
- headers: { Authorization: `Bearer ${accessToken}` },
44
- });
45
- if (!res.ok) {
46
- return done(new Error(`IAM userinfo failed: ${res.status}`));
47
- }
48
- const userinfo = (await res.json());
49
- done(null, { accessToken, refreshToken, userinfo });
50
- }
51
- catch (err) {
52
- done(err instanceof Error ? err : new Error(String(err)));
53
- }
54
- };
55
- return new OAuth2Strategy({
56
- authorizationURL: `${baseUrl}/login/oauth/authorize`,
57
- tokenURL: `${baseUrl}/api/login/oauth/access_token`,
58
- clientID: config.clientId,
59
- clientSecret: config.clientSecret ?? "",
60
- callbackURL: config.callbackUrl,
61
- scope: config.scope ?? "openid profile email",
62
- state: true,
63
- pkce: true,
64
- passReqToCallback: true,
65
- }, verify);
66
- }
67
- //# sourceMappingURL=passport.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"passport.js","sourceRoot":"","sources":["../src/passport.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAiBH;;;;;;;;GAQG;AACH,MAAM,UAAU,yBAAyB,CACvC,MAAyB;IAEzB,+DAA+D;IAC/D,iEAAiE;IACjE,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,iBAAiB,CAK7D,CAAC;IAEF,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAErD,MAAM,MAAM,GAAG,KAAK,EAClB,GAAG,IAAe,EACH,EAAE;QACjB,0EAA0E;QAC1E,MAAM,WAAW,GAAG,IAAI,CAAC,CAAC,CAAW,CAAC;QACtC,MAAM,YAAY,GAAG,IAAI,CAAC,CAAC,CAAuB,CAAC;QACnD,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAwD,CAAC;QAE5E,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,eAAe,EAAE;gBACjD,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,WAAW,EAAE,EAAE;aACpD,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,OAAO,IAAI,CAAC,IAAI,KAAK,CAAC,wBAAwB,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;YAC/D,CAAC;YACD,MAAM,QAAQ,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA4B,CAAC;YAC/D,IAAI,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC,CAAC;QACtD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAC5D,CAAC;IACH,CAAC,CAAC;IAEF,OAAO,IAAI,cAAc,CACvB;QACE,gBAAgB,EAAE,GAAG,OAAO,wBAAwB;QACpD,QAAQ,EAAE,GAAG,OAAO,+BAA+B;QACnD,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,EAAE;QACvC,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,sBAAsB;QAC7C,KAAK,EAAE,IAAI;QACX,IAAI,EAAE,IAAI;QACV,iBAAiB,EAAE,IAAI;KACxB,EACD,MAAM,CACP,CAAC;AACJ,CAAC"}