{"version":3,"sources":["../src/paths.ts","../src/passport.ts"],"names":["OAuth2Strategy"],"mappings":";;;;;;;;;;;AAoBO,IAAM,UAAA,GAAa;AAAA;AAAA,EAExB,SAAA,EAAW,mCAAA;AAAA;AAAA,EAEX,SAAA,EAAW,yBAAA;AAAA;AAAA,EAEX,KAAA,EAAO,qBAAA;AAAA;AAAA,EAEP,QAAA,EAAU,wBAAA;AAAA;AAAA,EAEV,IAAA,EAAM,0BAAA;AAAA;AAAA,EAEN,MAAA,EAAQ;AACV,CAAA;AA2DO,SAAS,cAAc,SAAA,EAA2B;AACvD,EAAA,OAAO,SAAA,CAAU,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA;AACrC;AAQO,SAAS,MAAA,CAAO,WAAmB,GAAA,EAA0B;AAClE,EAAA,OAAO,GAAG,aAAA,CAAc,SAAS,CAAC,CAAA,EAAG,UAAA,CAAW,GAAG,CAAC,CAAA,CAAA;AACtD;;;ACpDO,SAAS,0BACd,MAAA,EACS;AAET,EAAA,MAAM,WAAA,GAAc,MAAA,CAAO,MAAA,CAAO,SAAA,EAAW,UAAU,CAAA;AAEvD,EAAA,MAAM,MAAA,GAAS,UACV,IAAA,KACe;AAElB,IAAA,MAAM,WAAA,GAAc,KAAK,CAAC,CAAA;AAC1B,IAAA,MAAM,YAAA,GAAe,KAAK,CAAC,CAAA;AAC3B,IAAA,MAAM,IAAA,GAAO,KAAK,CAAC,CAAA;AAEnB,IAAA,IAAI;AACF,MAAA,MAAM,GAAA,GAAM,MAAM,KAAA,CAAM,WAAA,EAAa;AAAA,QACnC,OAAA,EAAS,EAAE,aAAA,EAAe,CAAA,OAAA,EAAU,WAAW,CAAA,CAAA;AAAG,OACnD,CAAA;AACD,MAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,QAAA,OAAO,KAAK,IAAI,KAAA,CAAM,wBAAwB,GAAA,CAAI,MAAM,EAAE,CAAC,CAAA;AAAA,MAC7D;AACA,MAAA,MAAM,QAAA,GAAY,MAAM,GAAA,CAAI,IAAA,EAAK;AACjC,MAAA,IAAA,CAAK,IAAA,EAAM,EAAE,WAAA,EAAa,YAAA,EAAc,UAAU,CAAA;AAAA,IACpD,SAAS,GAAA,EAAK;AACZ,MAAA,IAAA,CAAK,GAAA,YAAe,QAAQ,GAAA,GAAM,IAAI,MAAM,MAAA,CAAO,GAAG,CAAC,CAAC,CAAA;AAAA,IAC1D;AAAA,EACF,CAAA;AAEA,EAAA,OAAO,IAAIA,+BAAA;AAAA,IACT;AAAA,MACE,gBAAA,EAAkB,MAAA,CAAO,MAAA,CAAO,SAAA,EAAW,WAAW,CAAA;AAAA,MACtD,QAAA,EAAU,MAAA,CAAO,MAAA,CAAO,SAAA,EAAW,OAAO,CAAA;AAAA,MAC1C,UAAU,MAAA,CAAO,QAAA;AAAA,MACjB,YAAA,EAAc,OAAO,YAAA,IAAgB,EAAA;AAAA,MACrC,aAAa,MAAA,CAAO,WAAA;AAAA,MACpB,KAAA,EAAO,OAAO,KAAA,IAAS,sBAAA;AAAA,MACvB,KAAA,EAAO,IAAA;AAAA,MACP,IAAA,EAAM,IAAA;AAAA,MACN,iBAAA,EAAmB;AAAA,KACrB;AAAA,IACA;AAAA,GACF;AACF","file":"passport.cjs","sourcesContent":["/**\n * The single source of truth for Hanzo IAM OIDC endpoint paths.\n *\n * Hanzo IAM is a Casdoor-derived OIDC provider served per-brand from a\n * configurable origin (`serverUrl`): hanzo → https://iam.hanzo.ai,\n * lux → https://lux.id, zoo → https://zoo.id, bootnode → https://id.bootno.de.\n *\n * These are the ONLY paths. There is no legacy `/oauth/*` and no\n * `/api/login/*`. Every module in this SDK references `OIDC_PATHS` —\n * no path string is written anywhere else.\n *\n * CRITICAL GOTCHA: IAM serves a 200 `text/html` SPA catch-all for ANY\n * unregistered path. A client that hits a wrong path therefore gets a\n * 200 HTML body, not a 404 — silent breakage. So clients MUST hit these\n * exact paths, and a discovery round-trip must never be allowed to\n * resolve to a different path. The hard-coded fallbacks here are these\n * same values, so a failed discovery degrades to correct paths.\n */\n\n/** OIDC endpoint paths, relative to the brand `serverUrl`. */\nexport const OIDC_PATHS = {\n  /** OIDC discovery document. */\n  discovery: \"/.well-known/openid-configuration\",\n  /** Authorization endpoint (RFC 6749 §3.1). */\n  authorize: \"/v1/iam/oauth/authorize\",\n  /** Token endpoint (RFC 6749 §3.2). */\n  token: \"/v1/iam/oauth/token\",\n  /** UserInfo endpoint (OIDC Core §5.3). */\n  userinfo: \"/v1/iam/oauth/userinfo\",\n  /** JWKS endpoint (RFC 7517). */\n  jwks: \"/v1/iam/.well-known/jwks\",\n  /** RP-initiated logout endpoint (OIDC RP-Initiated Logout). */\n  logout: \"/v1/iam/oauth/logout\",\n} as const;\n\nexport type OidcPathKey = keyof typeof OIDC_PATHS;\n\n/**\n * Hanzo-IAM application paths that are NOT part of the OIDC spec — the\n * auth-method discovery endpoint and the onboarding state machine the\n * embedded views drive. Mounted under the same `/v1/iam` prefix.\n */\nexport const IAM_PATHS = {\n  /** Live list of enabled auth methods for the embedded login views. */\n  authMethods: \"/v1/iam/auth/methods\",\n  /** Onboarding state-machine base (steps append `/identity`, etc.). */\n  onboarding: \"/v1/iam/onboarding\",\n  /**\n   * Casdoor credential-login endpoint the embedded `<Login>` views POST to.\n   * `type=code` (a client `redirectUri` is present) mints an authorization\n   * code returned in `data`; `type=login` establishes the session cookie.\n   * This is what the deployed IAM actually authenticates against — the OIDC\n   * token endpoint's password/OTP grants are NOT enabled per-client.\n   */\n  login: \"/v1/iam/login\",\n  /** Send an email/SMS verification code (passwordless login). */\n  sendCode: \"/v1/iam/send-verification-code\",\n  /** Account registration. */\n  signup: \"/v1/iam/signup\",\n} as const;\n\nexport type IamPathKey = keyof typeof IAM_PATHS;\n\n/**\n * The canonical `serverUrl` origin for each Hanzo IAM brand. White-label\n * is host-based: one IAM deployment serves every brand and selects the\n * tenant by the origin it is reached on. This is the SINGLE place the\n * brand→origin mapping lives — adapters take a `brand` and resolve here\n * rather than each app hard-coding a hostname.\n */\nexport const BRAND_SERVER_URLS = {\n  hanzo: \"https://iam.hanzo.ai\",\n  lux: \"https://lux.id\",\n  zoo: \"https://zoo.id\",\n  bootnode: \"https://id.bootno.de\",\n  pars: \"https://pars.id\",\n} as const;\n\n/** A known Hanzo IAM brand key. */\nexport type IamBrand = keyof typeof BRAND_SERVER_URLS;\n\n/**\n * Resolve a brand to its canonical IAM `serverUrl`.\n *\n * @example\n * serverUrlForBrand(\"lux\") // → \"https://lux.id\"\n */\nexport function serverUrlForBrand(brand: IamBrand): string {\n  return BRAND_SERVER_URLS[brand];\n}\n\n/** Strip trailing slashes from a server origin so paths concat cleanly. */\nexport function trimServerUrl(serverUrl: string): string {\n  return serverUrl.replace(/\\/+$/, \"\");\n}\n\n/**\n * Build an absolute IAM endpoint URL from a server origin and a path key.\n *\n * @example\n * iamUrl(\"https://iam.hanzo.ai\", \"token\") // → \"https://iam.hanzo.ai/v1/iam/oauth/token\"\n */\nexport function iamUrl(serverUrl: string, key: OidcPathKey): string {\n  return `${trimServerUrl(serverUrl)}${OIDC_PATHS[key]}`;\n}\n","/**\n * Passport.js OAuth2 strategy factory for Hanzo IAM.\n *\n * Creates a pre-configured passport-oauth2 strategy that authenticates\n * against hanzo.id with PKCE and fetches user info on callback.\n *\n * @example\n * ```ts\n * import passport from \"passport\";\n * import { createIamPassportStrategy } from \"@hanzo/iam/passport\";\n *\n * passport.use(\"iam\", createIamPassportStrategy({\n *   serverUrl: \"https://hanzo.id\",\n *   clientId: \"hanzo-kms-client-id\",\n *   clientSecret: process.env.IAM_CLIENT_SECRET!,\n *   callbackUrl: \"https://kms.hanzo.ai/api/v1/sso/oidc/callback\",\n * }));\n * ```\n *\n * @packageDocumentation\n */\n\nimport OAuth2Strategy from \"passport-oauth2\";\n\nimport type { Config } from \"./types.js\";\nimport { iamUrl } from \"./paths.js\";\n\nexport interface IamPassportConfig extends Config {\n  /** Full callback URL for OAuth2 redirect. */\n  callbackUrl: string;\n  /** OAuth2 scopes. Default: \"openid profile email\". */\n  scope?: string;\n}\n\nexport interface IamPassportUser {\n  accessToken: string;\n  refreshToken?: string;\n  userinfo: Record<string, unknown>;\n}\n\n/**\n * Create a Passport OAuth2 strategy for Hanzo IAM.\n *\n * Returns an OAuth2Strategy instance ready to pass to `passport.use()`.\n * The verify callback fetches userinfo from the IAM server and passes\n * `{ accessToken, refreshToken, userinfo }` as the user object.\n *\n * `passport-oauth2` is a runtime dependency of this entry — using a\n * static import lets downstream bundlers (esbuild, webpack, etc.)\n * statically resolve and bundle it. Consumers who don't need passport\n * can import from `@hanzo/iam` directly to avoid pulling it in.\n */\nexport function createIamPassportStrategy(\n  config: IamPassportConfig,\n): unknown {\n\n  const userinfoUrl = iamUrl(config.serverUrl, \"userinfo\");\n\n  const verify = async (\n    ...args: unknown[]\n  ): Promise<void> => {\n    // passReqToCallback=true: (req, accessToken, refreshToken, profile, done)\n    const accessToken = args[1] as string;\n    const refreshToken = args[2] as string | undefined;\n    const done = args[4] as (err: Error | null, user?: IamPassportUser) => void;\n\n    try {\n      const res = await fetch(userinfoUrl, {\n        headers: { Authorization: `Bearer ${accessToken}` },\n      });\n      if (!res.ok) {\n        return done(new Error(`IAM userinfo failed: ${res.status}`));\n      }\n      const userinfo = (await res.json()) as Record<string, unknown>;\n      done(null, { accessToken, refreshToken, userinfo });\n    } catch (err) {\n      done(err instanceof Error ? err : new Error(String(err)));\n    }\n  };\n\n  return new OAuth2Strategy(\n    {\n      authorizationURL: iamUrl(config.serverUrl, \"authorize\"),\n      tokenURL: iamUrl(config.serverUrl, \"token\"),\n      clientID: config.clientId,\n      clientSecret: config.clientSecret ?? \"\",\n      callbackURL: config.callbackUrl,\n      scope: config.scope ?? \"openid profile email\",\n      state: true,\n      pkce: true,\n      passReqToCallback: true,\n    },\n    verify,\n  );\n}\n"]}