{"_id":"@brandon-harmse/portal-auth","_rev":"7-173896f84cff4c258683b4ec05c253de","name":"@brandon-harmse/portal-auth","dist-tags":{"latest":"1.0.5"},"versions":{"1.0.0":{"name":"@brandon-harmse/portal-auth","version":"1.0.0","author":{"name":"Standard Wesant"},"license":"UNLICENSED","_id":"@brandon-harmse/portal-auth@1.0.0","maintainers":[{"name":"brandon-harmse","email":"brandon@barabbas.co.za"}],"homepage":"https://github.com/standard-wesant/portal-auth#readme","bugs":{"url":"https://github.com/standard-wesant/portal-auth/issues"},"dist":{"shasum":"577e59052d2b6e6fc05fa136c4ebde8df9015cb8","tarball":"https://registry.npmjs.org/@brandon-harmse/portal-auth/-/portal-auth-1.0.0.tgz","fileCount":133,"integrity":"sha512-guqfjIrCavuIlss0IbXfFB74daKRAgx0TonvIIs0KKazOGp/JzQx6gqXy2SfzIx0/YAAcjIY0z88xXItwW7VPg==","signatures":[{"sig":"MEQCIEgSyMT2GQwEX7QnqlxQKv6jXYviCxDKivAItMnN64JFAiAMX7xndSSLCPEvDFvTozkElBk/dyEVuLJEESTYvAgcsw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":621903},"main":"dist/index.js","type":"module","types":"./src/index.ts","module":"dist/index.mjs","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./src/index.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./types":{"types":"./src/types/index.ts","import":"./dist/types.js","require":"./dist/types.cjs"},"./utils":{"types":"./src/utils/index.ts","import":"./dist/utils.js","require":"./dist/utils.cjs"},"./client":{"types":"./src/client/index.ts","import":"./dist/client.js","require":"./dist/client.cjs"},"./errors":{"types":"./src/errors/index.ts","import":"./dist/errors.js","require":"./dist/errors.cjs"},"./server":{"types":"./src/server/index.ts","import":"./dist/server.js","require":"./dist/server.cjs"},"./schemas":{"types":"./src/schemas/index.ts","import":"./dist/schemas.js","require":"./dist/schemas.cjs"},"./components":{"types":"./src/components/index.ts","import":"./dist/components.js","require":"./dist/components.cjs"},"./components/realm-picker":{"types":"./src/components/realm-picker/index.tsx","import":"./dist/realm-picker.js","require":"./dist/realm-picker.cjs"},"./components/unified-sign-in":{"types":"./src/components/unified-sign-in/index.tsx","import":"./dist/unified-sign-in.js","require":"./dist/unified-sign-in.cjs"}},"gitHead":"9eeef0e546abf71269f38f3f555092bd5cdd2c89","scripts":{"build":"tsup","clean":"rm -rf dist","typecheck":"tsc --noEmit","prepublishOnly":"pnpm run build"},"_npmUser":{"name":"brandon-harmse","email":"brandon@barabbas.co.za"},"repository":{"url":"git+https://github.com/standard-wesant/portal-auth.git","type":"git"},"_npmVersion":"10.8.2","description":"Unified portal authentication package for cross-realm authentication","directories":{},"_nodeVersion":"20.19.5","dependencies":{"zod":"^3.24.1","jose":"^5.9.6","zustand":"^5.0.3","react-hook-form":"^7.54.2","@hookform/resolvers":"^3.9.1"},"publishConfig":{"access":"restricted","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.1","typescript":"^5.3.3","@types/node":"^20.11.0","@types/react":"^18.2.48"},"peerDependencies":{"react":"^18 || ^19","ioredis":">=5","@repo/ui":"workspace:*","@lingui/react":">=5"},"peerDependenciesMeta":{"ioredis":{"optional":true},"@lingui/react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/portal-auth_1.0.0_1768546760705_0.21573437427055242","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@brandon-harmse/portal-auth","version":"1.0.1","author":{"name":"Standard Wesant"},"license":"UNLICENSED","_id":"@brandon-harmse/portal-auth@1.0.1","maintainers":[{"name":"brandon-harmse","email":"brandon@barabbas.co.za"}],"homepage":"https://github.com/standard-wesant/portal-auth#readme","bugs":{"url":"https://github.com/standard-wesant/portal-auth/issues"},"dist":{"shasum":"052f13eb42edc01df3778ff230baae997211efe4","tarball":"https://registry.npmjs.org/@brandon-harmse/portal-auth/-/portal-auth-1.0.1.tgz","fileCount":133,"integrity":"sha512-7fmMHvLHhKFoqoqgr/43tJaeHj+VoEWwWe4Bp2dtk81M9rr6b8dSXyAGp74CTq9MuzG6vysOhpCnL+rvzP24tA==","signatures":[{"sig":"MEQCIFMpEdvtTkZWMOE0F7XuAufK7DQG25pD7kkrcVdQsFJUAiBvU3+SY0mpZlWQkyR3ahXSdPucH5LzQ0vUil87pWh4iQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":621869},"main":"dist/index.js","type":"module","types":"./src/index.ts","module":"dist/index.mjs","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./src/index.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./types":{"types":"./src/types/index.ts","import":"./dist/types.js","require":"./dist/types.cjs"},"./utils":{"types":"./src/utils/index.ts","import":"./dist/utils.js","require":"./dist/utils.cjs"},"./client":{"types":"./src/client/index.ts","import":"./dist/client.js","require":"./dist/client.cjs"},"./errors":{"types":"./src/errors/index.ts","import":"./dist/errors.js","require":"./dist/errors.cjs"},"./server":{"types":"./src/server/index.ts","import":"./dist/server.js","require":"./dist/server.cjs"},"./schemas":{"types":"./src/schemas/index.ts","import":"./dist/schemas.js","require":"./dist/schemas.cjs"},"./components":{"types":"./src/components/index.ts","import":"./dist/components.js","require":"./dist/components.cjs"},"./components/realm-picker":{"types":"./src/components/realm-picker/index.tsx","import":"./dist/realm-picker.js","require":"./dist/realm-picker.cjs"},"./components/unified-sign-in":{"types":"./src/components/unified-sign-in/index.tsx","import":"./dist/unified-sign-in.js","require":"./dist/unified-sign-in.cjs"}},"gitHead":"fe62322c6db9ffa9d532d55850dc2c85de70055f","scripts":{"build":"tsup","clean":"rm -rf dist","typecheck":"tsc --noEmit","prepublishOnly":"pnpm run build"},"_npmUser":{"name":"brandon-harmse","email":"brandon@barabbas.co.za"},"repository":{"url":"git+https://github.com/standard-wesant/portal-auth.git","type":"git"},"_npmVersion":"10.8.2","description":"Unified portal authentication package for cross-realm authentication","directories":{},"_nodeVersion":"20.19.5","dependencies":{"zod":"^3.24.1","jose":"^5.9.6","zustand":"^5.0.3","react-hook-form":"^7.54.2","@hookform/resolvers":"^3.9.1"},"publishConfig":{"access":"restricted","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.1","typescript":"^5.3.3","@types/node":"^20.11.0","@types/react":"^18.2.48"},"peerDependencies":{"react":"^18 || ^19","ioredis":">=5","@repo/ui":"workspace:*","@lingui/react":">=5"},"peerDependenciesMeta":{"ioredis":{"optional":true},"@lingui/react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/portal-auth_1.0.1_1768548422771_0.3235974956678407","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@brandon-harmse/portal-auth","version":"1.0.2","author":{"name":"Standard Wesant"},"license":"UNLICENSED","_id":"@brandon-harmse/portal-auth@1.0.2","maintainers":[{"name":"brandon-harmse","email":"brandon@barabbas.co.za"}],"homepage":"https://github.com/standard-wesant/portal-auth#readme","bugs":{"url":"https://github.com/standard-wesant/portal-auth/issues"},"dist":{"shasum":"3429fdfe57ed63f08a2b06d3621269db213c3d08","tarball":"https://registry.npmjs.org/@brandon-harmse/portal-auth/-/portal-auth-1.0.2.tgz","fileCount":133,"integrity":"sha512-771nm7RhYqzokXKpVIJfHky+rd6nNG/CgZx32j/vfiPOtlGJf45tl2uFZBUU/F62WvLSTdNcm/vJfN5Hw+posw==","signatures":[{"sig":"MEQCIBga6TqsPvGdl4C0qz+kbWKl9pFUJyzX75UjRFVK+8NIAiBU8ykIAppsmXcrq7pNzuvN5wBaswcfWc2l2JLxiK3oQw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":625255},"main":"dist/index.js","type":"module","types":"./src/index.ts","module":"dist/index.mjs","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./src/index.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./types":{"types":"./src/types/index.ts","import":"./dist/types.js","require":"./dist/types.cjs"},"./utils":{"types":"./src/utils/index.ts","import":"./dist/utils.js","require":"./dist/utils.cjs"},"./client":{"types":"./src/client/index.ts","import":"./dist/client.js","require":"./dist/client.cjs"},"./errors":{"types":"./src/errors/index.ts","import":"./dist/errors.js","require":"./dist/errors.cjs"},"./server":{"types":"./src/server/index.ts","import":"./dist/server.js","require":"./dist/server.cjs"},"./schemas":{"types":"./src/schemas/index.ts","import":"./dist/schemas.js","require":"./dist/schemas.cjs"},"./components":{"types":"./src/components/index.ts","import":"./dist/components.js","require":"./dist/components.cjs"},"./components/realm-picker":{"types":"./src/components/realm-picker/index.tsx","import":"./dist/realm-picker.js","require":"./dist/realm-picker.cjs"},"./components/unified-sign-in":{"types":"./src/components/unified-sign-in/index.tsx","import":"./dist/unified-sign-in.js","require":"./dist/unified-sign-in.cjs"}},"gitHead":"0bf689337e5769aa889ac558e1816b9af287ea5f","scripts":{"build":"tsup","clean":"rm -rf dist","typecheck":"tsc --noEmit","prepublishOnly":"pnpm run build"},"_npmUser":{"name":"brandon-harmse","email":"brandon@barabbas.co.za"},"repository":{"url":"git+https://github.com/standard-wesant/portal-auth.git","type":"git"},"_npmVersion":"10.8.2","description":"Unified portal authentication package for cross-realm authentication","directories":{},"_nodeVersion":"20.19.5","dependencies":{"zod":"^3.24.1","jose":"^5.9.6","zustand":"^5.0.3","react-hook-form":"^7.54.2","@hookform/resolvers":"^3.9.1"},"publishConfig":{"access":"restricted","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.1","typescript":"^5.3.3","@types/node":"^20.11.0","@types/react":"^18.2.48"},"peerDependencies":{"react":"^18 || ^19","ioredis":">=5","@repo/ui":"workspace:*","@lingui/react":">=5"},"peerDependenciesMeta":{"ioredis":{"optional":true},"@lingui/react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/portal-auth_1.0.2_1768550981477_0.7027159613055092","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@brandon-harmse/portal-auth","version":"1.0.3","author":{"name":"Standard Wesant"},"license":"UNLICENSED","_id":"@brandon-harmse/portal-auth@1.0.3","maintainers":[{"name":"brandon-harmse","email":"brandon@barabbas.co.za"}],"homepage":"https://github.com/standard-wesant/portal-auth#readme","bugs":{"url":"https://github.com/standard-wesant/portal-auth/issues"},"dist":{"shasum":"7a66eea3b18eb34217925960e1b378f8822eea37","tarball":"https://registry.npmjs.org/@brandon-harmse/portal-auth/-/portal-auth-1.0.3.tgz","fileCount":129,"integrity":"sha512-PGxZw7YZPy8dWxrySGI8TezXEdem98wwrAn5y9NTb9MNLfTK9S2YtNSOOFpauRHynTZIgWmeNGlOntu1mEEHyw==","signatures":[{"sig":"MEQCICxZBwVQCnlq702HFSO2KP7QQZb2Qgu4jjeI+2Y480ZMAiBhwgPDIm+5dCDWhVkuKtdZ7uDNL6fGsf+7q0n+701ybQ==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1173195},"main":"dist/index.js","type":"module","_from":"file:brandon-harmse-portal-auth-1.0.3.tgz","types":"./src/index.ts","module":"dist/index.mjs","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./src/index.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./types":{"types":"./src/types/index.ts","import":"./dist/types.js","require":"./dist/types.cjs"},"./utils":{"types":"./src/utils/index.ts","import":"./dist/utils.js","require":"./dist/utils.cjs"},"./client":{"types":"./src/client/index.ts","import":"./dist/client.js","require":"./dist/client.cjs"},"./errors":{"types":"./src/errors/index.ts","import":"./dist/errors.js","require":"./dist/errors.cjs"},"./server":{"types":"./src/server/index.ts","import":"./dist/server.js","require":"./dist/server.cjs"},"./schemas":{"types":"./src/schemas/index.ts","import":"./dist/schemas.js","require":"./dist/schemas.cjs"},"./components":{"types":"./src/components/index.ts","import":"./dist/components.js","require":"./dist/components.cjs"},"./components/realm-picker":{"types":"./src/components/realm-picker/index.tsx","import":"./dist/realm-picker.js","require":"./dist/realm-picker.cjs"},"./components/unified-sign-in":{"types":"./src/components/unified-sign-in/index.tsx","import":"./dist/unified-sign-in.js","require":"./dist/unified-sign-in.cjs"}},"scripts":{"build":"tsup","clean":"rm -rf dist","typecheck":"tsc --noEmit"},"_npmUser":{"name":"brandon-harmse","email":"brandon@barabbas.co.za"},"_resolved":"/tmp/32653062d5725fb033e082145d4ff5dc/brandon-harmse-portal-auth-1.0.3.tgz","_integrity":"sha512-PGxZw7YZPy8dWxrySGI8TezXEdem98wwrAn5y9NTb9MNLfTK9S2YtNSOOFpauRHynTZIgWmeNGlOntu1mEEHyw==","repository":{"url":"git+https://github.com/standard-wesant/portal-auth.git","type":"git"},"_npmVersion":"10.8.2","description":"Unified portal authentication package for cross-realm authentication","directories":{},"_nodeVersion":"20.19.5","dependencies":{"zod":"^3.24.1","jose":"^5.9.6","zustand":"^5.0.3","react-hook-form":"^7.54.2","@hookform/resolvers":"^3.9.1"},"publishConfig":{"access":"restricted","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.1","@swc/core":"^1.15.8","typescript":"^5.3.3","@types/node":"^20.11.0","@types/react":"^18.2.48","@lingui/swc-plugin":"^5.10.1"},"peerDependencies":{"react":"^18 || ^19","ioredis":">=5","@repo/ui":"*","@lingui/react":">=5"},"peerDependenciesMeta":{"ioredis":{"optional":true},"@lingui/react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/portal-auth_1.0.3_1768654758888_0.6412552053468021","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@brandon-harmse/portal-auth","version":"1.0.4","author":{"name":"Standard Wesant"},"license":"UNLICENSED","_id":"@brandon-harmse/portal-auth@1.0.4","maintainers":[{"name":"brandon-harmse","email":"brandon@barabbas.co.za"}],"homepage":"https://github.com/standard-wesant/portal-auth#readme","bugs":{"url":"https://github.com/standard-wesant/portal-auth/issues"},"dist":{"shasum":"4fada48148975c360de5fbb18f95539aa795493a","tarball":"https://registry.npmjs.org/@brandon-harmse/portal-auth/-/portal-auth-1.0.4.tgz","fileCount":130,"integrity":"sha512-aAhbq9daORS1uJt3PHugSDRpZvM8qoNqW+xcFuSfjZ2e9oBfNRMpmFMgjDP2LMhGgKMCrnc1xi+B2pdloL6Nxw==","signatures":[{"sig":"MEYCIQCmrk20nj02E3YDKoOgMCmseamAbEm85ZaaGNdPkNjcPwIhAMueLWhmw+GeEHLcaFAiafvrjid5g9d0MkReGYFZdG77","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":1194379},"main":"dist/index.js","type":"module","types":"./src/index.ts","module":"dist/index.mjs","engines":{"node":">=18.0.0"},"exports":{".":{"types":"./src/index.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./types":{"types":"./src/types/index.ts","import":"./dist/types.js","require":"./dist/types.cjs"},"./utils":{"types":"./src/utils/index.ts","import":"./dist/utils.js","require":"./dist/utils.cjs"},"./client":{"types":"./src/client/index.ts","import":"./dist/client.js","require":"./dist/client.cjs"},"./errors":{"types":"./src/errors/index.ts","import":"./dist/errors.js","require":"./dist/errors.cjs"},"./server":{"types":"./src/server/index.ts","import":"./dist/server.js","require":"./dist/server.cjs"},"./schemas":{"types":"./src/schemas/index.ts","import":"./dist/schemas.js","require":"./dist/schemas.cjs"},"./components":{"types":"./src/components/index.ts","import":"./dist/components.js","require":"./dist/components.cjs"},"./components/realm-picker":{"types":"./src/components/realm-picker/index.tsx","import":"./dist/realm-picker.js","require":"./dist/realm-picker.cjs"},"./components/unified-sign-in":{"types":"./src/components/unified-sign-in/index.tsx","import":"./dist/unified-sign-in.js","require":"./dist/unified-sign-in.cjs"}},"gitHead":"6de021a1a44bcb52e19bad645789246ec7d4e140","scripts":{"build":"tsup","clean":"rm -rf dist","typecheck":"tsc --noEmit","prepublishOnly":"pnpm run build"},"_npmUser":{"name":"brandon-harmse","email":"brandon@barabbas.co.za"},"repository":{"url":"git+https://github.com/standard-wesant/portal-auth.git","type":"git"},"_npmVersion":"10.8.2","description":"Unified portal authentication package for cross-realm authentication","directories":{},"_nodeVersion":"20.19.5","dependencies":{"zod":"^3.24.1","jose":"^5.9.6","zustand":"^5.0.3","react-hook-form":"^7.54.2","@hookform/resolvers":"^3.9.1"},"publishConfig":{"access":"restricted","registry":"https://registry.npmjs.org"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.0.1","@swc/core":"^1.15.8","typescript":"^5.3.3","@types/node":"^20.11.0","@types/react":"^18.2.48","@lingui/swc-plugin":"^5.10.1"},"peerDependencies":{"next":">=14","react":"^18 || ^19","ioredis":">=5","@repo/ui":"*","@lingui/react":">=5"},"peerDependenciesMeta":{"ioredis":{"optional":true},"@lingui/react":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/portal-auth_1.0.4_1768721734504_0.5701371375776341","host":"s3://npm-registry-packages-npm-production"}},"1.0.5":{"name":"@brandon-harmse/portal-auth","version":"1.0.5","description":"Unified portal authentication package for cross-realm authentication","license":"UNLICENSED","author":{"name":"Standard Wesant"},"type":"module","main":"dist/index.js","module":"dist/index.mjs","types":"./src/index.ts","exports":{".":{"types":"./src/index.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./server":{"types":"./src/server/index.ts","import":"./dist/server.js","require":"./dist/server.cjs"},"./client":{"types":"./src/client/index.ts","import":"./dist/client.js","require":"./dist/client.cjs"},"./components":{"types":"./src/components/index.ts","import":"./dist/components.js","require":"./dist/components.cjs"},"./components/unified-sign-in":{"types":"./src/components/unified-sign-in/index.tsx","import":"./dist/unified-sign-in.js","require":"./dist/unified-sign-in.cjs"},"./components/realm-picker":{"types":"./src/components/realm-picker/index.tsx","import":"./dist/realm-picker.js","require":"./dist/realm-picker.cjs"},"./schemas":{"types":"./src/schemas/index.ts","import":"./dist/schemas.js","require":"./dist/schemas.cjs"},"./types":{"types":"./src/types/index.ts","import":"./dist/types.js","require":"./dist/types.cjs"},"./utils":{"types":"./src/utils/index.ts","import":"./dist/utils.js","require":"./dist/utils.cjs"},"./errors":{"types":"./src/errors/index.ts","import":"./dist/errors.js","require":"./dist/errors.cjs"}},"scripts":{"build":"tsup","clean":"rm -rf dist","prepublishOnly":"pnpm run build","typecheck":"tsc --noEmit"},"dependencies":{"@hookform/resolvers":"^3.9.1","jose":"^5.9.6","react-hook-form":"^7.54.2","zod":"^3.24.1","zustand":"^5.0.3"},"peerDependencies":{"@lingui/react":">=5","@repo/ui":"*","ioredis":">=5","next":">=14","react":"^18 || ^19"},"peerDependenciesMeta":{"@lingui/react":{"optional":true},"ioredis":{"optional":true}},"devDependencies":{"@lingui/swc-plugin":"^5.10.1","@swc/core":"^1.15.8","@types/node":"^20.11.0","@types/react":"^18.2.48","tsup":"^8.0.1","typescript":"^5.3.3"},"publishConfig":{"access":"public","registry":"https://registry.npmjs.org"},"repository":{"type":"git","url":"git+https://github.com/standard-wesant/portal-auth.git"},"engines":{"node":">=18.0.0"},"_id":"@brandon-harmse/portal-auth@1.0.5","gitHead":"e286a95996ee78132fa431b51dd0fb741919daa8","bugs":{"url":"https://github.com/standard-wesant/portal-auth/issues"},"homepage":"https://github.com/standard-wesant/portal-auth#readme","_nodeVersion":"20.19.5","_npmVersion":"10.8.2","dist":{"integrity":"sha512-zY6POg7fDH6J2hpBBiaRwmniGxds25R1TqwXVQcx2se4RfAzr3uEs24B0W0LzlpQiJe594liH9XRIhPwCq/Ulw==","shasum":"144c0bf5ceb45f4d97f17fbbddd1761c5613c091","tarball":"https://registry.npmjs.org/@brandon-harmse/portal-auth/-/portal-auth-1.0.5.tgz","fileCount":130,"unpackedSize":1195691,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCID16KXtA7Zh6gAzbCgeLKV7bsN6I+EFnErq+D/ApvX+wAiEA1E3MSAOpW4qMVeWTCoS+USR5V75PLuJTs2E+iYkCvqI="}]},"_npmUser":{"name":"brandon-harmse","email":"brandon@barabbas.co.za"},"directories":{},"maintainers":[{"name":"brandon-harmse","email":"brandon@barabbas.co.za"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/portal-auth_1.0.5_1772571166025_0.12252190606860114"},"_hasShrinkwrap":false}},"time":{"created":"2026-01-16T06:59:20.571Z","modified":"2026-03-03T20:52:46.362Z","1.0.0":"2026-01-16T06:59:20.866Z","1.0.1":"2026-01-16T07:27:03.092Z","1.0.2":"2026-01-16T08:09:41.633Z","1.0.3":"2026-01-17T12:59:19.081Z","1.0.4":"2026-01-18T07:35:34.676Z","1.0.5":"2026-03-03T20:52:46.252Z"},"bugs":{"url":"https://github.com/standard-wesant/portal-auth/issues"},"author":{"name":"Standard Wesant"},"license":"UNLICENSED","homepage":"https://github.com/standard-wesant/portal-auth#readme","repository":{"type":"git","url":"git+https://github.com/standard-wesant/portal-auth.git"},"description":"Unified portal authentication package for cross-realm authentication","maintainers":[{"name":"brandon-harmse","email":"brandon@barabbas.co.za"}],"readme":"# @standard-wesant/portal-auth\n\nUnified authentication package for cross-realm sign-in across ELA applications.\n\n## Prerequisites\n\nThis package requires the following peer dependencies that are **standard across all ELA repositories**:\n\n### `@repo/ui` (Required)\n\nThe UI components in this package depend on `@repo/ui` - a shared component library built on **Shadcn UI**.\n\n**Required Shadcn components:**\n- `Button`\n- `Input`\n- `Form` (FormField, FormItem, FormLabel, FormMessage)\n- `Card`\n- `Skeleton`\n\n**Required icons from `@repo/ui/icons`:**\n- `ArrowLeft`\n- `ArrowRight`\n- `Loader2`\n- `AlertCircle`\n- `CheckCircle`\n\nAll ELA repositories (`ela`, `vizier-repo/ela-projects`, etc.) include this package at `packages/ui/`.\n\n### Installation\n\n```bash\n# Using pnpm (recommended)\npnpm add @standard-wesant/portal-auth\n\n# Using npm\nnpm install @standard-wesant/portal-auth\n```\n\nEnsure your repository has `@repo/ui` configured in your workspace with the required Shadcn components installed.\n\n## Architecture Overview\n\n```mermaid\nflowchart TB\n    subgraph Portal[\"Corporate Portal (Sign-In Hub)\"]\n        UI[UnifiedSignIn Component]\n        Email[Email Form]\n        Code[Code Form]\n        Realm[Realm Picker]\n    end\n\n    subgraph Apps[\"Target Applications (Dynamic)\"]\n        Corp[Corporate App]\n        FS[\"Field Shop instances<br/>(configured via env vars)\"]\n        ELA[ELA Field]\n    end\n\n    subgraph Shared[\"Shared Libraries\"]\n        Lib[\"@repo/lib/auth\"]\n        PortalAuth[\"@repo/portal-auth\"]\n    end\n\n    UI --> Email\n    Email --> Code\n    Code --> Realm\n    Realm --> |\"Portal Token + PKCE\"| Apps\n\n    PortalAuth --> |\"UI Components\"| Portal\n    Lib --> |\"Token/PKCE Functions\"| Apps\n```\n\n## Authentication Flow\n\n```mermaid\nsequenceDiagram\n    autonumber\n    participant User\n    participant Portal as Corporate Portal\n    participant DB as Portal Database\n    participant Target as Target App (Field Shop/Corporate)\n    participant TargetDB as Target App Database\n\n    Note over User,TargetDB: Phase 1: Email Entry & OTP Verification\n\n    User->>Portal: Enter email address\n    Portal->>DB: Check user exists anywhere\n    Portal->>Target: POST /api/auth/realm-check (server-to-server)\n    Target-->>Portal: { exists: true, realmId, realmName }\n\n    alt User exists in at least one realm\n        Portal->>DB: Create verification record (OTP)\n        Portal->>User: Send OTP email\n        User->>Portal: Enter 6-digit OTP\n        Portal->>DB: Verify OTP (timing-safe comparison)\n        DB-->>Portal: OTP valid, email verified\n    else User not found\n        Portal-->>User: Error: No account found\n    end\n\n    Note over User,TargetDB: Phase 2: Realm Discovery\n\n    Portal->>DB: Query Corporate realm for user\n    Portal->>Target: Query all Field Shops for user\n    Portal->>Portal: Query ELA Field for user\n    Portal-->>User: Display available realms\n\n    Note over User,TargetDB: Phase 3: Cross-Realm Redirect (PKCE + JWT)\n\n    User->>Portal: Select target realm\n    Portal->>Portal: Generate PKCE pair (code_verifier, code_challenge)\n    Portal->>Portal: Create Portal Token (RS256 JWT, 60s TTL)\n\n    Note right of Portal: Token contains:<br/>- email<br/>- targetRealm<br/>- codeChallenge<br/>- jti (single-use ID)\n\n    Portal->>User: Redirect to Target callback URL\n\n    Note over User,TargetDB: Phase 4: Token Verification & Session Creation\n\n    User->>Target: GET /api/auth/portal/callback?token=...&code_verifier=...\n    Target->>Target: Verify JWT signature (RS256)\n    Target->>Target: Verify PKCE (code_verifier matches code_challenge)\n    Target->>Target: Check JTI not already used (replay prevention)\n    Target->>TargetDB: Lookup user by email\n    Target->>TargetDB: Load user role & permissions\n    Target->>Target: Create session JWT\n    Target->>User: Set session cookie + redirect to /dashboard\n```\n\n## PKCE Security Flow\n\n```mermaid\nflowchart LR\n    subgraph Portal[\"Portal (Client)\"]\n        A[Generate code_verifier<br/>43-128 chars, URL-safe]\n        B[SHA256 hash verifier]\n        C[Base64URL encode hash]\n        D[code_challenge]\n    end\n\n    subgraph Token[\"Portal Token (JWT)\"]\n        E[Embed code_challenge<br/>in token payload]\n    end\n\n    subgraph Target[\"Target App (Server)\"]\n        F[Receive code_verifier<br/>from URL params]\n        G[SHA256 hash received verifier]\n        H[Compare with code_challenge<br/>from token]\n        I{Match?}\n        J[Accept - Create Session]\n        K[Reject - Invalid PKCE]\n    end\n\n    A --> B --> C --> D --> E\n    E --> |\"Token in redirect URL\"| F\n    F --> G --> H --> I\n    I --> |Yes| J\n    I --> |No| K\n```\n\n## Token Structure\n\n```mermaid\nflowchart TB\n    subgraph JWT[\"Portal Token (RS256)\"]\n        Header[\"Header<br/>{alg: RS256, typ: portal}\"]\n        Payload[\"Payload\"]\n        Signature[\"Signature<br/>(Private Key)\"]\n    end\n\n    subgraph PayloadFields[\"Token Payload Fields\"]\n        P1[\"sub: user email\"]\n        P2[\"iss: portal issuer URL\"]\n        P3[\"aud: target realm ID\"]\n        P4[\"exp: now + 60 seconds\"]\n        P5[\"iat: issued at\"]\n        P6[\"jti: unique token ID\"]\n        P7[\"codeChallenge: PKCE S256\"]\n        P8[\"targetRealm: realm identifier\"]\n    end\n\n    Payload --> PayloadFields\n```\n\n## Realm Types\n\n```mermaid\nflowchart TB\n    subgraph Realms[\"Supported Realm Types\"]\n        Corp[\"corporate<br/>Corporate Admin Portal\"]\n        FS[\"fieldshop-{slug}<br/>Field Shop Instance\"]\n        ELA[\"ela-field<br/>ELA Field Application\"]\n    end\n\n    subgraph Discovery[\"Realm Discovery\"]\n        D1[Query Corporate DB]\n        D2[Query Field Shop APIs]\n        D3[Query ELA Field API]\n    end\n\n    D1 --> Corp\n    D2 --> FS\n    D3 --> ELA\n```\n\n## Component Architecture\n\n```mermaid\nflowchart TB\n    subgraph UnifiedSignIn[\"UnifiedSignIn Component\"]\n        direction TB\n        Store[Zustand Store<br/>Sign-in State]\n        VStore[Verification Store<br/>OTP State]\n\n        subgraph Steps[\"Sign-In Steps\"]\n            S1[EmailForm]\n            S2[CodeForm]\n            S3[RealmPicker]\n        end\n    end\n\n    subgraph Hooks[\"Client Hooks\"]\n        H1[useUnifiedSignInStore]\n        H2[useVerificationStore]\n        H3[usePkce]\n        H4[usePortalRedirect]\n        H5[useCountdown]\n    end\n\n    subgraph ServerActions[\"Server Actions (App-Level)\"]\n        SA1[sendSignInUnified]\n        SA2[verifyCodeUnified]\n        SA3[discoverRealms]\n        SA4[createPortalRedirect]\n    end\n\n    Store --> Steps\n    VStore --> S2\n\n    S1 --> |\"onSubmit\"| SA1\n    S2 --> |\"onSubmit\"| SA2\n    S2 --> |\"onVerified\"| SA3\n    S3 --> |\"onSelect\"| SA4\n\n    H1 --> Store\n    H2 --> VStore\n    H3 --> S3\n    H4 --> S3\n    H5 --> S2\n```\n\n## Security Features\n\n```mermaid\nflowchart TB\n    subgraph Security[\"Security Layers\"]\n        direction TB\n\n        subgraph Token[\"Token Security\"]\n            T1[RS256 Asymmetric Signing]\n            T2[60-second TTL]\n            T3[JTI Single-Use Enforcement]\n        end\n\n        subgraph PKCE[\"PKCE Protection\"]\n            P1[S256 Challenge Method]\n            P2[Timing-Safe Comparison]\n            P3[Prevents Token Interception]\n        end\n\n        subgraph OTP[\"OTP Security\"]\n            O1[6-digit Secure Random]\n            O2[10-minute Expiry]\n            O3[Max 3 Attempts]\n            O4[Timing-Safe Verification]\n        end\n\n        subgraph Server[\"Server-to-Server\"]\n            S1[Internal API Secret]\n            S2[Realm Check Authentication]\n        end\n    end\n```\n\n## Package Structure\n\n```\npackages/portal-auth/\n├── src/\n│   ├── components/           # UI Components (USED)\n│   │   ├── unified-sign-in/  # Main sign-in orchestrator\n│   │   ├── email-form/       # Email entry step\n│   │   ├── code-form/        # OTP verification step\n│   │   ├── realm-picker/     # Realm selection step\n│   │   ├── callback/         # Callback status display\n│   │   └── primitives/       # Shared UI primitives\n│   │\n│   ├── client/               # Client-Side State (USED)\n│   │   ├── stores/           # Zustand stores\n│   │   └── hooks/            # React hooks\n│   │\n│   ├── server/               # Server Utilities (NOT USED - see @repo/lib)\n│   │   ├── token/            # Token create/verify\n│   │   ├── callback/         # Callback handling\n│   │   ├── jti-store/        # JTI tracking\n│   │   └── registry/         # Realm registry\n│   │\n│   ├── schemas/              # Zod Validation Schemas\n│   ├── types/                # TypeScript Types\n│   ├── errors/               # Error Classes\n│   └── utils/                # Crypto & URL Utilities\n│\n└── __tests__/                # Unit Tests\n```\n\n## Usage\n\n### In Corporate Portal (Sign-In Hub)\n\n```tsx\nimport { UnifiedSignIn } from \"@repo/portal-auth/components\"\nimport {\n  sendSignInUnified,\n  verifyCodeUnified,\n  discoverRealms,\n  createPortalRedirect\n} from \"@/server-actions/auth\"\n\nexport function PortalSignIn() {\n  const handleRealmSelected = async (realm: RealmInfo, pkce: PKCEPair) => {\n    const result = await createPortalRedirect({ realm, pkce })\n    if (result.success) {\n      window.location.href = result.redirectUrl\n    }\n  }\n\n  return (\n    <UnifiedSignIn\n      sendCode={sendSignInUnified}\n      verifyCode={verifyCodeUnified}\n      discoverRealms={discoverRealms}\n      onRealmSelected={handleRealmSelected}\n    />\n  )\n}\n```\n\n### In Target App (Callback Handler)\n\n```typescript\n// app/api/auth/portal/callback/route.ts\nimport {\n  verifyPortalToken,\n  verifyPKCE,\n  portalRedirectParamsSchema\n} from \"@repo/lib\"\n\nexport async function GET(request: NextRequest) {\n  const { token, code_verifier } = portalRedirectParamsSchema.parse(params)\n\n  // Verify JWT signature\n  const payload = await verifyPortalToken(token, { publicKey })\n\n  // Verify PKCE\n  const pkceValid = await verifyPKCE(code_verifier, payload.codeChallenge)\n  if (!pkceValid) throw new Error(\"Invalid PKCE\")\n\n  // Check JTI not reused\n  if (isJtiUsed(payload.jti)) throw new Error(\"Token already used\")\n  markJtiUsed(payload.jti)\n\n  // Create local session\n  const user = await db.user.findUnique({ where: { email: payload.sub } })\n  const sessionToken = await createSessionJwt(user)\n\n  // Set cookie and redirect\n  cookies().set(\"session\", sessionToken)\n  return NextResponse.redirect(\"/dashboard\")\n}\n```\n\n## Environment Variables\n\n| Variable | Required | Description |\n|----------|----------|-------------|\n| `JWT_PRIVATE_KEY` | Yes | RSA private key for signing portal tokens |\n| `JWT_PUBLIC_KEY` | Yes | RSA public key for verifying portal tokens |\n| `PORTAL_JWT_PUBLIC_KEY` | No | Override public key for portal token verification |\n| `PORTAL_ISSUER` | Yes | Issuer URL for portal tokens |\n| `INTERNAL_API_SECRET` | Yes | Secret for server-to-server realm-check calls |\n| `OTHER_FIELDSHOP_URLS` | No | Comma-separated URLs of other Field Shop instances |\n| `ELA_FIELD_URL` | No | URL of ELA Field application |\n| `CORPORATE_APP_URL` | No | URL of Corporate portal (for Field Shop apps) |\n\n## Related Packages\n\n- `@repo/lib` - Server-side auth functions (token, PKCE, realm discovery)\n- `@repo/ui` - Shared UI components\n- `@repo/i18n` - Internationalization\n","readmeFilename":"README.md"}