[{"data":1,"prerenderedAt":5054},["ShallowReactive",2],{"navigation_docs":3,"-docs-essentials-authentication":493,"-docs-essentials-authentication-surround":5049},[4,46,135,218,257,292,355,377,420],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":45},"Getting Started","i-lucide-rocket","\u002Fdocs\u002Fgetting-started","docs\u002F01.getting-started",[10,15,20,25,30,35,40],{"title":11,"path":12,"stem":13,"icon":14},"What is Heximon?","\u002Fdocs\u002Fgetting-started\u002Fintroduction","docs\u002F01.getting-started\u002F01.introduction","i-lucide-info",{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fdocs\u002Fgetting-started\u002Finstallation","docs\u002F01.getting-started\u002F02.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":24},"Quick Start","\u002Fdocs\u002Fgetting-started\u002Fquick-start","docs\u002F01.getting-started\u002F03.quick-start","i-lucide-zap",{"title":26,"path":27,"stem":28,"icon":29},"Core Concepts","\u002Fdocs\u002Fgetting-started\u002Fcore-concepts","docs\u002F01.getting-started\u002F04.core-concepts","i-lucide-shapes",{"title":31,"path":32,"stem":33,"icon":34},"Examples","\u002Fdocs\u002Fgetting-started\u002Fexamples","docs\u002F01.getting-started\u002F05.examples","i-lucide-library",{"title":36,"path":37,"stem":38,"icon":39},"Where Next?","\u002Fdocs\u002Fgetting-started\u002Fwhere-next","docs\u002F01.getting-started\u002F06.where-next","i-lucide-signpost",{"title":41,"path":42,"stem":43,"icon":44},"Troubleshooting","\u002Fdocs\u002Fgetting-started\u002Ftroubleshooting","docs\u002F01.getting-started\u002F07.troubleshooting","i-lucide-life-buoy",false,{"title":47,"icon":48,"path":49,"stem":50,"children":51,"page":45},"Essentials","i-lucide-boxes","\u002Fdocs\u002Fessentials","docs\u002F02.essentials",[52,56,61,66,71,76,81,86,91,96,101,105,110,115,120,125,130],{"title":53,"path":54,"stem":55,"icon":48},"Modules & DI","\u002Fdocs\u002Fessentials\u002Fmodules-and-di","docs\u002F02.essentials\u002F01.modules-and-di",{"title":57,"path":58,"stem":59,"icon":60},"Controllers","\u002Fdocs\u002Fessentials\u002Fcontrollers","docs\u002F02.essentials\u002F02.controllers","i-lucide-route",{"title":62,"path":63,"stem":64,"icon":65},"Validation & DTOs","\u002Fdocs\u002Fessentials\u002Fvalidation","docs\u002F02.essentials\u002F03.validation","i-lucide-shield-check",{"title":67,"path":68,"stem":69,"icon":70},"Contracts","\u002Fdocs\u002Fessentials\u002Fcontracts","docs\u002F02.essentials\u002F04.contracts","i-lucide-file-signature",{"title":72,"path":73,"stem":74,"icon":75},"REST Client","\u002Fdocs\u002Fessentials\u002Fclient","docs\u002F02.essentials\u002F05.client","i-lucide-plug",{"title":77,"path":78,"stem":79,"icon":80},"Database","\u002Fdocs\u002Fessentials\u002Fdatabase","docs\u002F02.essentials\u002F06.database","i-lucide-database",{"title":82,"path":83,"stem":84,"icon":85},"Drizzle ORM","\u002Fdocs\u002Fessentials\u002Fdrizzle","docs\u002F02.essentials\u002F07.drizzle","i-lucide-database-zap",{"title":87,"path":88,"stem":89,"icon":90},"Persistence & Transactions","\u002Fdocs\u002Fessentials\u002Fpersistence","docs\u002F02.essentials\u002F08.persistence","i-lucide-database-backup",{"title":92,"path":93,"stem":94,"icon":95},"Migrations","\u002Fdocs\u002Fessentials\u002Fmigrations","docs\u002F02.essentials\u002F09.migrations","i-lucide-git-branch",{"title":97,"path":98,"stem":99,"icon":100},"Authentication","\u002Fdocs\u002Fessentials\u002Fauthentication","docs\u002F02.essentials\u002F10.authentication","i-lucide-key-round",{"title":102,"path":103,"stem":104,"icon":65},"Permissions & scopes","\u002Fdocs\u002Fessentials\u002Fpermissions","docs\u002F02.essentials\u002F11.permissions",{"title":106,"path":107,"stem":108,"icon":109},"Error Handling","\u002Fdocs\u002Fessentials\u002Ferrors","docs\u002F02.essentials\u002F12.errors","i-lucide-triangle-alert",{"title":111,"path":112,"stem":113,"icon":114},"Testing a Heximon App","\u002Fdocs\u002Fessentials\u002Ftesting","docs\u002F02.essentials\u002F13.testing","i-lucide-flask-conical",{"title":116,"path":117,"stem":118,"icon":119},"Test app harness","\u002Fdocs\u002Fessentials\u002Fcreatetestapp","docs\u002F02.essentials\u002F14.createtestapp","i-lucide-test-tube",{"title":121,"path":122,"stem":123,"icon":124},"Logging & Observability","\u002Fdocs\u002Fessentials\u002Flogging","docs\u002F02.essentials\u002F17.logging","i-lucide-scroll-text",{"title":126,"path":127,"stem":128,"icon":129},"Context & Lifecycle","\u002Fdocs\u002Fessentials\u002Fcontext-and-lifecycle","docs\u002F02.essentials\u002F18.context-and-lifecycle","i-lucide-radio",{"title":131,"path":132,"stem":133,"icon":134},"Project Structure","\u002Fdocs\u002Fessentials\u002Fproject-structure","docs\u002F02.essentials\u002F19.project-structure","i-lucide-folder-tree",{"title":136,"icon":137,"path":138,"stem":139,"children":140,"page":45},"Capabilities","i-lucide-sparkles","\u002Fdocs\u002Fcapabilities","docs\u002F03.capabilities",[141,145,150,155,160,164,169,174,179,184,188,193,198,203,208,213],{"title":142,"path":143,"stem":144,"icon":137},"Overview","\u002Fdocs\u002Fcapabilities\u002Foverview","docs\u002F03.capabilities\u002F01.overview",{"title":146,"path":147,"stem":148,"icon":149},"Events","\u002Fdocs\u002Fcapabilities\u002Fevents","docs\u002F03.capabilities\u002F02.events","i-lucide-radio-tower",{"title":151,"path":152,"stem":153,"icon":154},"Queue","\u002Fdocs\u002Fcapabilities\u002Fbackground-jobs","docs\u002F03.capabilities\u002F03.background-jobs","i-lucide-list-ordered",{"title":156,"path":157,"stem":158,"icon":159},"Scheduled Work","\u002Fdocs\u002Fcapabilities\u002Fscheduled-jobs","docs\u002F03.capabilities\u002F04.scheduled-jobs","i-lucide-clock",{"title":161,"path":162,"stem":163,"icon":85},"Caching","\u002Fdocs\u002Fcapabilities\u002Fcaching","docs\u002F03.capabilities\u002F05.caching",{"title":165,"path":166,"stem":167,"icon":168},"Key\u002FValue Storage","\u002Fdocs\u002Fcapabilities\u002Fkey-value","docs\u002F03.capabilities\u002F06.key-value","i-lucide-hard-drive",{"title":170,"path":171,"stem":172,"icon":173},"Blob Storage","\u002Fdocs\u002Fcapabilities\u002Fblob","docs\u002F03.capabilities\u002F07.blob","i-lucide-folder-open",{"title":175,"path":176,"stem":177,"icon":178},"Health & Readiness","\u002Fdocs\u002Fcapabilities\u002Fhealth","docs\u002F03.capabilities\u002F08.health","i-lucide-heart-pulse",{"title":180,"path":181,"stem":182,"icon":183},"Notifications","\u002Fdocs\u002Fcapabilities\u002Fnotifications","docs\u002F03.capabilities\u002F09.notifications","i-lucide-mail",{"title":185,"path":186,"stem":187,"icon":65},"Idempotency","\u002Fdocs\u002Fcapabilities\u002Fidempotency","docs\u002F03.capabilities\u002F10.idempotency",{"title":189,"path":190,"stem":191,"icon":192},"Security Hardening","\u002Fdocs\u002Fcapabilities\u002Fsecurity","docs\u002F03.capabilities\u002F11.security","i-lucide-shield",{"title":194,"path":195,"stem":196,"icon":197},"Observability & Tracing","\u002Fdocs\u002Fcapabilities\u002Fobservability","docs\u002F03.capabilities\u002F12.observability","i-lucide-activity",{"title":199,"path":200,"stem":201,"icon":202},"OpenAPI","\u002Fdocs\u002Fcapabilities\u002Fopenapi","docs\u002F03.capabilities\u002F13.openapi","i-lucide-book-marked",{"title":204,"path":205,"stem":206,"icon":207},"MCP Server","\u002Fdocs\u002Fcapabilities\u002Fmcp","docs\u002F03.capabilities\u002F14.mcp","i-lucide-bot",{"title":209,"path":210,"stem":211,"icon":212},"Schema DTOs","\u002Fdocs\u002Fcapabilities\u002Fschema","docs\u002F03.capabilities\u002F15.schema","i-lucide-file-json",{"title":214,"path":215,"stem":216,"icon":217},"Branded IDs","\u002Fdocs\u002Fcapabilities\u002Fbranded-ids","docs\u002F03.capabilities\u002F16.branded-ids","i-lucide-tag",{"title":219,"icon":220,"path":221,"stem":222,"children":223,"page":45},"Architecture","i-lucide-building","\u002Fdocs\u002Farchitecture","docs\u002F04.architecture",[224,227,232,237,242,247,252],{"title":142,"path":225,"stem":226,"icon":220},"\u002Fdocs\u002Farchitecture\u002Foverview","docs\u002F04.architecture\u002F01.overview",{"title":228,"path":229,"stem":230,"icon":231},"Domain-Driven Design","\u002Fdocs\u002Farchitecture\u002Fddd","docs\u002F04.architecture\u002F02.ddd","i-lucide-hexagon",{"title":233,"path":234,"stem":235,"icon":236},"CQRS","\u002Fdocs\u002Farchitecture\u002Fcqrs","docs\u002F04.architecture\u002F03.cqrs","i-lucide-split",{"title":238,"path":239,"stem":240,"icon":241},"Repository Pattern","\u002Fdocs\u002Farchitecture\u002Frepository-pattern","docs\u002F04.architecture\u002F04.repository-pattern","i-lucide-archive",{"title":243,"path":244,"stem":245,"icon":246},"Integration Events","\u002Fdocs\u002Farchitecture\u002Fintegration-events","docs\u002F04.architecture\u002F05.integration-events","i-lucide-send-horizontal",{"title":248,"path":249,"stem":250,"icon":251},"Saga Orchestration","\u002Fdocs\u002Farchitecture\u002Fsagas","docs\u002F04.architecture\u002F06.sagas","i-lucide-hourglass",{"title":253,"path":254,"stem":255,"icon":256},"Durable Workflows","\u002Fdocs\u002Farchitecture\u002Fworkflows","docs\u002F04.architecture\u002F07.workflows","i-lucide-workflow",{"title":258,"icon":259,"path":260,"stem":261,"children":262,"page":45},"Realtime","i-lucide-cable","\u002Fdocs\u002Frealtime","docs\u002F05.realtime",[263,266,270,274,279,284,288],{"title":142,"path":264,"stem":265,"icon":259},"\u002Fdocs\u002Frealtime\u002Foverview","docs\u002F05.realtime\u002F01.overview",{"title":267,"path":268,"stem":269,"icon":129},"WebSockets","\u002Fdocs\u002Frealtime\u002Fwebsockets","docs\u002F05.realtime\u002F02.websockets",{"title":271,"path":272,"stem":273,"icon":70},"WebSocket Contracts","\u002Fdocs\u002Frealtime\u002Fwebsocket-contracts","docs\u002F05.realtime\u002F03.websocket-contracts",{"title":275,"path":276,"stem":277,"icon":278},"Server-Sent Events","\u002Fdocs\u002Frealtime\u002Fserver-sent-events","docs\u002F05.realtime\u002F04.server-sent-events","i-lucide-rss",{"title":280,"path":281,"stem":282,"icon":283},"Typed Clients","\u002Fdocs\u002Frealtime\u002Ftyped-clients","docs\u002F05.realtime\u002F05.typed-clients","i-lucide-plug-zap",{"title":285,"path":286,"stem":287,"icon":259},"AsyncAPI","\u002Fdocs\u002Frealtime\u002Fasyncapi","docs\u002F05.realtime\u002F06.asyncapi",{"title":289,"path":290,"stem":291,"icon":80},"Durable Objects","\u002Fdocs\u002Frealtime\u002Fdurable-objects","docs\u002F05.realtime\u002F07.durable-objects",{"title":293,"icon":294,"path":295,"stem":296,"children":297,"page":45},"Deploy","i-lucide-cloud-upload","\u002Fdocs\u002Fdeploy","docs\u002F06.deploy",[298,301,306,311,316,321,326,331,336,341,345,350],{"title":142,"path":299,"stem":300,"icon":6},"\u002Fdocs\u002Fdeploy\u002Foverview","docs\u002F06.deploy\u002F01.overview",{"title":302,"path":303,"stem":304,"icon":305},"Node","\u002Fdocs\u002Fdeploy\u002Fnode","docs\u002F06.deploy\u002F02.node","la:node-js",{"title":307,"path":308,"stem":309,"icon":310},"Cloudflare","\u002Fdocs\u002Fdeploy\u002Fcloudflare","docs\u002F06.deploy\u002F03.cloudflare","simple-icons:cloudflare",{"title":312,"path":313,"stem":314,"icon":315},"Vercel","\u002Fdocs\u002Fdeploy\u002Fvercel","docs\u002F06.deploy\u002F04.vercel","ri:vercel-fill",{"title":317,"path":318,"stem":319,"icon":320},"Netlify","\u002Fdocs\u002Fdeploy\u002Fnetlify","docs\u002F06.deploy\u002F05.netlify","i-simple-icons-netlify",{"title":322,"path":323,"stem":324,"icon":325},"AWS Lambda","\u002Fdocs\u002Fdeploy\u002Faws-lambda","docs\u002F06.deploy\u002F06.aws-lambda","hugeicons:aws-lambda",{"title":327,"path":328,"stem":329,"icon":330},"Deno Deploy","\u002Fdocs\u002Fdeploy\u002Fdeno-deploy","docs\u002F06.deploy\u002F07.deno-deploy","simple-icons:denodeploy",{"title":332,"path":333,"stem":334,"icon":335},"Nitro","\u002Fdocs\u002Fdeploy\u002Fnitro","docs\u002F06.deploy\u002F08.nitro","i-unjs-nitro",{"title":337,"path":338,"stem":339,"icon":340},"Nuxt","\u002Fdocs\u002Fdeploy\u002Fnuxt","docs\u002F06.deploy\u002F09.nuxt","i-devicon-nuxt",{"title":342,"path":343,"stem":344,"icon":236},"Mixed-runtime split","\u002Fdocs\u002Fdeploy\u002Fmixed-runtime-split","docs\u002F06.deploy\u002F10.mixed-runtime-split",{"title":346,"path":347,"stem":348,"icon":349},"Hosts","\u002Fdocs\u002Fdeploy\u002Fhosts","docs\u002F06.deploy\u002F11.hosts","i-lucide-map",{"title":351,"path":352,"stem":353,"icon":354},"Cross-service events","\u002Fdocs\u002Fdeploy\u002Fcross-service-events","docs\u002F06.deploy\u002F12.cross-service-events","i-lucide-network",{"title":356,"icon":357,"path":358,"stem":359,"children":360,"page":45},"CLI","i-lucide-terminal","\u002Fdocs\u002Fcli","docs\u002F07.cli",[361,365,369,373],{"title":362,"path":363,"stem":364,"icon":357},"The heximon CLI","\u002Fdocs\u002Fcli\u002Foverview","docs\u002F07.cli\u002F01.overview",{"title":366,"path":367,"stem":368,"icon":137},"Create a New App","\u002Fdocs\u002Fcli\u002Fcreate","docs\u002F07.cli\u002F02.create",{"title":370,"path":371,"stem":372,"icon":95},"Migrations from the CLI","\u002Fdocs\u002Fcli\u002Fmigrations","docs\u002F07.cli\u002F03.migrations",{"title":374,"path":375,"stem":376,"icon":6},"Deploying a Heximon app","\u002Fdocs\u002Fcli\u002Fdeploy","docs\u002F07.cli\u002F04.deploy",{"title":378,"icon":379,"path":380,"stem":381,"children":382,"page":45},"Under the Hood","i-lucide-wrench","\u002Fdocs\u002Funder-the-hood","docs\u002F08.under-the-hood",[383,388,393,397,402,407,411,415],{"title":384,"path":385,"stem":386,"icon":387},"How the Compiler Works","\u002Fdocs\u002Funder-the-hood\u002Fhow-the-compiler-works","docs\u002F08.under-the-hood\u002F01.how-the-compiler-works","i-lucide-cog",{"title":389,"path":390,"stem":391,"icon":392},"Compiler","\u002Fdocs\u002Funder-the-hood\u002Fextending-the-compiler","docs\u002F08.under-the-hood\u002F02.extending-the-compiler","i-lucide-cpu",{"title":394,"path":395,"stem":396,"icon":357},"Compiler Diagnostics","\u002Fdocs\u002Funder-the-hood\u002Fcompiler-diagnostics","docs\u002F08.under-the-hood\u002F03.compiler-diagnostics",{"title":398,"path":399,"stem":400,"icon":401},"Library Mode","\u002Fdocs\u002Funder-the-hood\u002Flibrary-mode","docs\u002F08.under-the-hood\u002F04.library-mode","i-lucide-package",{"title":403,"path":404,"stem":405,"icon":406},"Other bundlers","\u002Fdocs\u002Funder-the-hood\u002Falternate-bundlers","docs\u002F08.under-the-hood\u002F05.alternate-bundlers","i-lucide-blocks",{"title":408,"path":409,"stem":410,"icon":401},"Packages","\u002Fdocs\u002Funder-the-hood\u002Fpackages","docs\u002F08.under-the-hood\u002F06.packages",{"title":412,"path":413,"stem":414,"icon":207},"AI Skills","\u002Fdocs\u002Funder-the-hood\u002Fai-and-agents","docs\u002F08.under-the-hood\u002F07.ai-and-agents",{"title":416,"path":417,"stem":418,"icon":419},"Advanced DI","\u002Fdocs\u002Funder-the-hood\u002Fadvanced-di","docs\u002F08.under-the-hood\u002F08.advanced-di","i-lucide-git-fork",{"title":421,"icon":422,"path":423,"stem":424,"children":425,"page":45},"Recipes","i-lucide-book-open-check","\u002Fdocs\u002Frecipes","docs\u002F09.recipes",[426,431,436,440,444,448,452,456,460,465,469,474,479,484,488],{"title":427,"path":428,"stem":429,"icon":430},"Send an Email","\u002Fdocs\u002Frecipes\u002Fsend-an-email","docs\u002F09.recipes\u002F01.send-an-email","i-lucide-send",{"title":432,"path":433,"stem":434,"icon":435},"Upload a File","\u002Fdocs\u002Frecipes\u002Fupload-a-file","docs\u002F09.recipes\u002F02.upload-a-file","i-lucide-upload",{"title":437,"path":438,"stem":439,"icon":24},"Cache an Expensive Call","\u002Fdocs\u002Frecipes\u002Fcache-an-expensive-call","docs\u002F09.recipes\u002F03.cache-an-expensive-call",{"title":441,"path":442,"stem":443,"icon":154},"Paginate a List","\u002Fdocs\u002Frecipes\u002Fpaginate-a-list","docs\u002F09.recipes\u002F04.paginate-a-list",{"title":445,"path":446,"stem":447,"icon":65},"Protect Admin Routes","\u002Fdocs\u002Frecipes\u002Fprotect-admin-routes","docs\u002F09.recipes\u002F05.protect-admin-routes",{"title":449,"path":450,"stem":451,"icon":178},"Health Probes and a Nightly Job","\u002Fdocs\u002Frecipes\u002Fhealth-probes-and-a-nightly-job","docs\u002F09.recipes\u002F06.health-probes-and-a-nightly-job",{"title":453,"path":454,"stem":455,"icon":80},"Build a CRUD API","\u002Fdocs\u002Frecipes\u002Fcrud-api","docs\u002F09.recipes\u002F07.crud-api",{"title":457,"path":458,"stem":459,"icon":100},"Add Authentication","\u002Fdocs\u002Frecipes\u002Fadd-authentication","docs\u002F09.recipes\u002F08.add-authentication",{"title":461,"path":462,"stem":463,"icon":464},"Background Jobs","\u002Fdocs\u002Frecipes\u002Fbackground-jobs","docs\u002F09.recipes\u002F09.background-jobs","i-lucide-timer",{"title":466,"path":467,"stem":468,"icon":149},"Decouple Features with Events","\u002Fdocs\u002Frecipes\u002Fevent-driven-module","docs\u002F09.recipes\u002F10.event-driven-module",{"title":470,"path":471,"stem":472,"icon":473},"Build a DDD Aggregate","\u002Fdocs\u002Frecipes\u002Fddd-aggregate","docs\u002F09.recipes\u002F11.ddd-aggregate","i-lucide-box",{"title":475,"path":476,"stem":477,"icon":478},"Publish a Feature Package","\u002Fdocs\u002Frecipes\u002Ffeature-package","docs\u002F09.recipes\u002F12.feature-package","i-lucide-package-open",{"title":480,"path":481,"stem":482,"icon":483},"Reliable Integration Events","\u002Fdocs\u002Frecipes\u002Freliable-integration-events","docs\u002F09.recipes\u002F13.reliable-integration-events","i-lucide-inbox",{"title":485,"path":486,"stem":487,"icon":95},"Reactive Choreography","\u002Fdocs\u002Frecipes\u002Freactive-choreography","docs\u002F09.recipes\u002F14.reactive-choreography",{"title":489,"path":490,"stem":491,"icon":492},"Build a Production CRUD API","\u002Fdocs\u002Frecipes\u002Fproduction-crud-api","docs\u002F09.recipes\u002F15.production-crud-api","i-lucide-layers",{"id":494,"title":97,"body":495,"description":5042,"extension":5043,"links":5044,"meta":5045,"navigation":5046,"path":98,"seo":5047,"stem":99,"__hash__":5048},"docs\u002Fdocs\u002F02.essentials\u002F10.authentication.md",{"type":496,"value":497,"toc":5030},"minimark",[498,528,533,604,615,619,643,1284,1301,1305,1328,1884,1887,1959,1978,1982,2020,2027,2127,2134,2156,2170,2189,2193,2230,2236,2321,2332,2336,2396,4443,4463,4488,4492,4512,4517,4616,4620,4627,4686,4690,4707,4721,4975,4979,5026],[499,500,501,502,506,507,511,512,515,516,519,520,523,524,527],"p",{},"Authentication answers one question on every request: ",[503,504,505],"strong",{},"who is the caller?"," Heximon verifies a signed JWT\noff the request, turns it into a request-scoped principal, and lets any handler read that principal by\ninjecting ",[508,509,510],"code",{},"AuthContext",". You issue the token at login by checking a password against a constant-time hash —\nthrough the abstract ",[508,513,514],{},"PasswordHashingAlgorithm"," port, so the same controller code hashes with ",[508,517,518],{},"Scrypt"," on\nNode or ",[508,521,522],{},"Pbkdf2"," on the edge — and signing the caller's id and scopes with ",[508,525,526],{},"JWTFactory",". Every piece is a\nplain DI provider — no decorators, class identity is the only token.",[529,530,532],"h2",{"id":531},"install-the-package","Install the package",[534,535,536,561,576,590],"code-group",{},[537,538,544],"pre",{"className":539,"code":540,"filename":541,"language":542,"meta":543,"style":543},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm add @heximon\u002Fauth\n","pnpm","bash","",[508,545,546],{"__ignoreMap":543},[547,548,551,554,558],"span",{"class":549,"line":550},"line",1,[547,552,541],{"class":553},"sBMFI",[547,555,557],{"class":556},"sfazB"," add",[547,559,560],{"class":556}," @heximon\u002Fauth\n",[537,562,565],{"className":539,"code":563,"filename":564,"language":542,"meta":543,"style":543},"npm install @heximon\u002Fauth\n","npm",[508,566,567],{"__ignoreMap":543},[547,568,569,571,574],{"class":549,"line":550},[547,570,564],{"class":553},[547,572,573],{"class":556}," install",[547,575,560],{"class":556},[537,577,580],{"className":539,"code":578,"filename":579,"language":542,"meta":543,"style":543},"yarn add @heximon\u002Fauth\n","yarn",[508,581,582],{"__ignoreMap":543},[547,583,584,586,588],{"class":549,"line":550},[547,585,579],{"class":553},[547,587,557],{"class":556},[547,589,560],{"class":556},[537,591,594],{"className":539,"code":592,"filename":593,"language":542,"meta":543,"style":543},"bun add @heximon\u002Fauth\n","bun",[508,595,596],{"__ignoreMap":543},[547,597,598,600,602],{"class":549,"line":550},[547,599,593],{"class":553},[547,601,557],{"class":556},[547,603,560],{"class":556},[499,605,606,607,614],{},"The only third-party dependency is ",[608,609,613],"a",{"href":610,"rel":611},"https:\u002F\u002Fgithub.com\u002Fpanva\u002Fjose",[612],"nofollow","jose"," for the JWT crypto. There's no\ncompiler plugin to register — every auth class is an ordinary DI provider, or a middleware the HTTP\nplugin discovers.",[529,616,618],{"id":617},"generate-a-key-pair-at-boot","Generate a key pair at boot",[499,620,621,623,624,627,628,631,632,634,635,638,639,642],{},[508,622,526],{}," signs tokens with the ",[503,625,626],{},"private"," key; ",[508,629,630],{},"JWTVerifier"," (which ",[508,633,510],{}," uses) verifies them\nwith the ",[503,636,637],{},"public"," key. Generate one ES256 key pair via ",[508,640,641],{},"JwkService"," and hold both halves on a single class,\nso the signer and verifier provably share it — an EC keygen is a couple of milliseconds versus an RSA\nkeygen's tens to hundreds, so this stays off the critical path even running at boot.",[537,644,649],{"className":645,"code":646,"filename":647,"language":648,"meta":543,"style":543},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { Base64JWK, type GeneratedKeyPair, JwkService, JWTVerifier } from \"@heximon\u002Fauth\";\nimport { Platform } from \"@heximon\u002Fruntime\";\n\n\u002F** The app's signing key pair — the signer and verifier both read it, so they can never drift apart. *\u002F\nexport class IdentityKeyPair {\n  private static readonly algorithm: string = \"ES256\";\n  private static readonly environmentVariable: string = \"HEXIMON_JWK\";\n\n  public readonly privateKey: GeneratedKeyPair[\"privateKey\"];\n  public readonly publicKey: GeneratedKeyPair[\"publicKey\"];\n\n  public constructor(keyPair: GeneratedKeyPair) {\n    this.privateKey = keyPair.privateKey;\n    this.publicKey = keyPair.publicKey;\n  }\n\n  \u002F** `HEXIMON_JWK` when set (production), else a freshly generated pair (dev). *\u002F\n  public static async resolve(): Promise\u003CIdentityKeyPair> {\n    const encoded = Platform.get(IdentityKeyPair.environmentVariable);\n\n    return encoded === undefined\n      ? IdentityKeyPair.generate()\n      : IdentityKeyPair.fromEncoded(encoded);\n  }\n\n  \u002F** Decode a Base64-encoded private JWK, deriving the public half by stripping its private members. *\u002F\n  public static fromEncoded(encoded: string): IdentityKeyPair {\n    const privateKey = Base64JWK.decode(encoded);\n\n    return new IdentityKeyPair({ privateKey, publicKey: JWTVerifier.toPublicJWK(privateKey) });\n  }\n\n  \u002F** Dev-only: keys rotate on every boot, so a restart (or a second instance) invalidates every session issued so far. *\u002F\n  public static async generate(): Promise\u003CIdentityKeyPair> {\n    return new IdentityKeyPair(await new JwkService().generate(IdentityKeyPair.algorithm));\n  }\n}\n","src\u002Fauth\u002Fidentity-key-pair.ts","ts",[508,650,651,702,725,732,739,755,789,816,821,851,878,883,907,927,944,950,955,961,991,1023,1028,1042,1058,1080,1085,1090,1096,1121,1145,1150,1194,1199,1204,1210,1234,1273,1278],{"__ignoreMap":543},[547,652,653,657,661,665,668,671,674,676,679,681,684,687,690,693,696,699],{"class":549,"line":550},[547,654,656],{"class":655},"s7zQu","import",[547,658,660],{"class":659},"sMK4o"," {",[547,662,664],{"class":663},"sTEyZ"," Base64JWK",[547,666,667],{"class":659},",",[547,669,670],{"class":655}," type",[547,672,673],{"class":663}," GeneratedKeyPair",[547,675,667],{"class":659},[547,677,678],{"class":663}," JwkService",[547,680,667],{"class":659},[547,682,683],{"class":663}," JWTVerifier",[547,685,686],{"class":659}," }",[547,688,689],{"class":655}," from",[547,691,692],{"class":659}," \"",[547,694,695],{"class":556},"@heximon\u002Fauth",[547,697,698],{"class":659},"\"",[547,700,701],{"class":659},";\n",[547,703,705,707,709,712,714,716,718,721,723],{"class":549,"line":704},2,[547,706,656],{"class":655},[547,708,660],{"class":659},[547,710,711],{"class":663}," Platform",[547,713,686],{"class":659},[547,715,689],{"class":655},[547,717,692],{"class":659},[547,719,720],{"class":556},"@heximon\u002Fruntime",[547,722,698],{"class":659},[547,724,701],{"class":659},[547,726,728],{"class":549,"line":727},3,[547,729,731],{"emptyLinePlaceholder":730},true,"\n",[547,733,735],{"class":549,"line":734},4,[547,736,738],{"class":737},"sHwdD","\u002F** The app's signing key pair — the signer and verifier both read it, so they can never drift apart. *\u002F\n",[547,740,742,745,749,752],{"class":549,"line":741},5,[547,743,744],{"class":655},"export",[547,746,748],{"class":747},"spNyl"," class",[547,750,751],{"class":553}," IdentityKeyPair",[547,753,754],{"class":659}," {\n",[547,756,758,761,764,767,771,774,777,780,782,785,787],{"class":549,"line":757},6,[547,759,760],{"class":747},"  private",[547,762,763],{"class":747}," static",[547,765,766],{"class":747}," readonly",[547,768,770],{"class":769},"swJcz"," algorithm",[547,772,773],{"class":659},":",[547,775,776],{"class":553}," string",[547,778,779],{"class":659}," =",[547,781,692],{"class":659},[547,783,784],{"class":556},"ES256",[547,786,698],{"class":659},[547,788,701],{"class":659},[547,790,792,794,796,798,801,803,805,807,809,812,814],{"class":549,"line":791},7,[547,793,760],{"class":747},[547,795,763],{"class":747},[547,797,766],{"class":747},[547,799,800],{"class":769}," environmentVariable",[547,802,773],{"class":659},[547,804,776],{"class":553},[547,806,779],{"class":659},[547,808,692],{"class":659},[547,810,811],{"class":556},"HEXIMON_JWK",[547,813,698],{"class":659},[547,815,701],{"class":659},[547,817,819],{"class":549,"line":818},8,[547,820,731],{"emptyLinePlaceholder":730},[547,822,824,827,829,832,834,836,839,841,844,846,849],{"class":549,"line":823},9,[547,825,826],{"class":747},"  public",[547,828,766],{"class":747},[547,830,831],{"class":769}," privateKey",[547,833,773],{"class":659},[547,835,673],{"class":553},[547,837,838],{"class":663},"[",[547,840,698],{"class":659},[547,842,843],{"class":556},"privateKey",[547,845,698],{"class":659},[547,847,848],{"class":663},"]",[547,850,701],{"class":659},[547,852,854,856,858,861,863,865,867,869,872,874,876],{"class":549,"line":853},10,[547,855,826],{"class":747},[547,857,766],{"class":747},[547,859,860],{"class":769}," publicKey",[547,862,773],{"class":659},[547,864,673],{"class":553},[547,866,838],{"class":663},[547,868,698],{"class":659},[547,870,871],{"class":556},"publicKey",[547,873,698],{"class":659},[547,875,848],{"class":663},[547,877,701],{"class":659},[547,879,881],{"class":549,"line":880},11,[547,882,731],{"emptyLinePlaceholder":730},[547,884,886,888,891,894,898,900,902,905],{"class":549,"line":885},12,[547,887,826],{"class":747},[547,889,890],{"class":747}," constructor",[547,892,893],{"class":659},"(",[547,895,897],{"class":896},"sHdIc","keyPair",[547,899,773],{"class":659},[547,901,673],{"class":553},[547,903,904],{"class":659},")",[547,906,754],{"class":659},[547,908,910,913,915,917,920,923,925],{"class":549,"line":909},13,[547,911,912],{"class":659},"    this.",[547,914,843],{"class":663},[547,916,779],{"class":659},[547,918,919],{"class":663}," keyPair",[547,921,922],{"class":659},".",[547,924,843],{"class":663},[547,926,701],{"class":659},[547,928,930,932,934,936,938,940,942],{"class":549,"line":929},14,[547,931,912],{"class":659},[547,933,871],{"class":663},[547,935,779],{"class":659},[547,937,919],{"class":663},[547,939,922],{"class":659},[547,941,871],{"class":663},[547,943,701],{"class":659},[547,945,947],{"class":549,"line":946},15,[547,948,949],{"class":659},"  }\n",[547,951,953],{"class":549,"line":952},16,[547,954,731],{"emptyLinePlaceholder":730},[547,956,958],{"class":549,"line":957},17,[547,959,960],{"class":737},"  \u002F** `HEXIMON_JWK` when set (production), else a freshly generated pair (dev). *\u002F\n",[547,962,964,966,968,971,974,977,980,983,986,989],{"class":549,"line":963},18,[547,965,826],{"class":747},[547,967,763],{"class":747},[547,969,970],{"class":747}," async",[547,972,973],{"class":769}," resolve",[547,975,976],{"class":659},"():",[547,978,979],{"class":553}," Promise",[547,981,982],{"class":659},"\u003C",[547,984,985],{"class":553},"IdentityKeyPair",[547,987,988],{"class":659},">",[547,990,754],{"class":659},[547,992,994,997,1000,1002,1004,1006,1010,1012,1014,1016,1019,1021],{"class":549,"line":993},19,[547,995,996],{"class":747},"    const",[547,998,999],{"class":663}," encoded",[547,1001,779],{"class":659},[547,1003,711],{"class":663},[547,1005,922],{"class":659},[547,1007,1009],{"class":1008},"s2Zo4","get",[547,1011,893],{"class":769},[547,1013,985],{"class":663},[547,1015,922],{"class":659},[547,1017,1018],{"class":663},"environmentVariable",[547,1020,904],{"class":769},[547,1022,701],{"class":659},[547,1024,1026],{"class":549,"line":1025},20,[547,1027,731],{"emptyLinePlaceholder":730},[547,1029,1031,1034,1036,1039],{"class":549,"line":1030},21,[547,1032,1033],{"class":655},"    return",[547,1035,999],{"class":663},[547,1037,1038],{"class":659}," ===",[547,1040,1041],{"class":659}," undefined\n",[547,1043,1045,1048,1050,1052,1055],{"class":549,"line":1044},22,[547,1046,1047],{"class":659},"      ?",[547,1049,751],{"class":663},[547,1051,922],{"class":659},[547,1053,1054],{"class":1008},"generate",[547,1056,1057],{"class":769},"()\n",[547,1059,1061,1064,1066,1068,1071,1073,1076,1078],{"class":549,"line":1060},23,[547,1062,1063],{"class":659},"      :",[547,1065,751],{"class":663},[547,1067,922],{"class":659},[547,1069,1070],{"class":1008},"fromEncoded",[547,1072,893],{"class":769},[547,1074,1075],{"class":663},"encoded",[547,1077,904],{"class":769},[547,1079,701],{"class":659},[547,1081,1083],{"class":549,"line":1082},24,[547,1084,949],{"class":659},[547,1086,1088],{"class":549,"line":1087},25,[547,1089,731],{"emptyLinePlaceholder":730},[547,1091,1093],{"class":549,"line":1092},26,[547,1094,1095],{"class":737},"  \u002F** Decode a Base64-encoded private JWK, deriving the public half by stripping its private members. *\u002F\n",[547,1097,1099,1101,1103,1106,1108,1110,1112,1114,1117,1119],{"class":549,"line":1098},27,[547,1100,826],{"class":747},[547,1102,763],{"class":747},[547,1104,1105],{"class":769}," fromEncoded",[547,1107,893],{"class":659},[547,1109,1075],{"class":896},[547,1111,773],{"class":659},[547,1113,776],{"class":553},[547,1115,1116],{"class":659},"):",[547,1118,751],{"class":553},[547,1120,754],{"class":659},[547,1122,1124,1126,1128,1130,1132,1134,1137,1139,1141,1143],{"class":549,"line":1123},28,[547,1125,996],{"class":747},[547,1127,831],{"class":663},[547,1129,779],{"class":659},[547,1131,664],{"class":663},[547,1133,922],{"class":659},[547,1135,1136],{"class":1008},"decode",[547,1138,893],{"class":769},[547,1140,1075],{"class":663},[547,1142,904],{"class":769},[547,1144,701],{"class":659},[547,1146,1148],{"class":549,"line":1147},29,[547,1149,731],{"emptyLinePlaceholder":730},[547,1151,1153,1155,1158,1160,1162,1165,1167,1169,1171,1173,1175,1177,1180,1182,1184,1187,1190,1192],{"class":549,"line":1152},30,[547,1154,1033],{"class":655},[547,1156,1157],{"class":659}," new",[547,1159,751],{"class":1008},[547,1161,893],{"class":769},[547,1163,1164],{"class":659},"{",[547,1166,831],{"class":663},[547,1168,667],{"class":659},[547,1170,860],{"class":769},[547,1172,773],{"class":659},[547,1174,683],{"class":663},[547,1176,922],{"class":659},[547,1178,1179],{"class":1008},"toPublicJWK",[547,1181,893],{"class":769},[547,1183,843],{"class":663},[547,1185,1186],{"class":769},") ",[547,1188,1189],{"class":659},"}",[547,1191,904],{"class":769},[547,1193,701],{"class":659},[547,1195,1197],{"class":549,"line":1196},31,[547,1198,949],{"class":659},[547,1200,1202],{"class":549,"line":1201},32,[547,1203,731],{"emptyLinePlaceholder":730},[547,1205,1207],{"class":549,"line":1206},33,[547,1208,1209],{"class":737},"  \u002F** Dev-only: keys rotate on every boot, so a restart (or a second instance) invalidates every session issued so far. *\u002F\n",[547,1211,1213,1215,1217,1219,1222,1224,1226,1228,1230,1232],{"class":549,"line":1212},34,[547,1214,826],{"class":747},[547,1216,763],{"class":747},[547,1218,970],{"class":747},[547,1220,1221],{"class":769}," generate",[547,1223,976],{"class":659},[547,1225,979],{"class":553},[547,1227,982],{"class":659},[547,1229,985],{"class":553},[547,1231,988],{"class":659},[547,1233,754],{"class":659},[547,1235,1237,1239,1241,1243,1245,1248,1250,1252,1255,1257,1259,1261,1263,1265,1268,1271],{"class":549,"line":1236},35,[547,1238,1033],{"class":655},[547,1240,1157],{"class":659},[547,1242,751],{"class":1008},[547,1244,893],{"class":769},[547,1246,1247],{"class":655},"await",[547,1249,1157],{"class":659},[547,1251,678],{"class":1008},[547,1253,1254],{"class":769},"()",[547,1256,922],{"class":659},[547,1258,1054],{"class":1008},[547,1260,893],{"class":769},[547,1262,985],{"class":663},[547,1264,922],{"class":659},[547,1266,1267],{"class":663},"algorithm",[547,1269,1270],{"class":769},"))",[547,1272,701],{"class":659},[547,1274,1276],{"class":549,"line":1275},36,[547,1277,949],{"class":659},[547,1279,1281],{"class":549,"line":1280},37,[547,1282,1283],{"class":659},"}\n",[499,1285,1286,1289,1290,1293,1294,1296,1297,1300],{},[508,1287,1288],{},"resolve()"," is what the module's ",[508,1291,1292],{},"useFactory"," calls (next section): it reads a Base64-encoded private JWK\nfrom ",[508,1295,811],{}," when set — so the key survives a restart or a scale-out — and only falls back to\n",[508,1298,1299],{},"generate()",", a fresh dev-only pair, when the variable is unset.",[529,1302,1304],{"id":1303},"wire-the-auth-providers-in-a-module","Wire the auth providers in a module",[499,1306,1307,1309,1310,1312,1313,1316,1317,1319,1320,1323,1324,1327],{},[508,1308,526],{}," and ",[508,1311,510],{}," take constructor arguments that mix injectable services with non-injectable\nconfiguration (a key, a ",[508,1314,1315],{},"TokenSource",") — bind those with ",[508,1318,1292],{}," providers, where the ",[503,1321,1322],{},"factory's\nparameter types"," become the dependency declaration. ",[508,1325,1326],{},"JWTAuthMiddleware"," and the password hasher need no\nsuch wiring:",[537,1329,1332],{"className":645,"code":1330,"filename":1331,"language":648,"meta":543,"style":543},"import {\n  AuthContext,\n  CookieTokenSource,\n  JWTAuthMiddleware,\n  JWTFactory,\n  JWTVerifier,\n  PasswordHashingAlgorithm,\n  Scrypt,\n} from \"@heximon\u002Fauth\";\nimport { Context, Module } from \"@heximon\u002Fruntime\";\nimport { AuthController } from \".\u002Fauth.controller\";\nimport { IdentityKeyPair } from \".\u002Fidentity-key-pair\";\nimport { JwksController } from \".\u002Fjwks.controller\";\nimport { UserAccountStore } from \".\u002Fuser-account-store\";\n\nexport class AuthModule extends Module({\n  providers: [\n    UserAccountStore,\n    { provide: PasswordHashingAlgorithm, useClass: Scrypt },\n    JWTAuthMiddleware,\n    {\n      provide: IdentityKeyPair,\n      useFactory: (): Promise\u003CIdentityKeyPair> => IdentityKeyPair.resolve(),\n    },\n    {\n      provide: JWTFactory,\n      useFactory: (keys: IdentityKeyPair): JWTFactory => new JWTFactory(keys.privateKey),\n    },\n    {\n      provide: AuthContext,\n      useFactory: (context: Context, verifier: JWTVerifier): AuthContext =>\n        new AuthContext(context, verifier, new CookieTokenSource(\"accessToken\")),\n    },\n  ],\n  http: { controllers: [AuthController, JwksController] },\n  exports: [\n    AuthContext,\n    JWTAuthMiddleware,\n    JWTVerifier,\n    JWTFactory,\n    UserAccountStore,\n    PasswordHashingAlgorithm,\n  ],\n}) {}\n","src\u002Fauth\u002Fauth.module.ts",[508,1333,1334,1340,1348,1355,1362,1369,1376,1383,1390,1404,1430,1452,1473,1495,1517,1521,1540,1550,1557,1583,1590,1595,1606,1638,1643,1647,1658,1694,1698,1702,1713,1744,1778,1782,1789,1813,1822,1829,1836,1844,1852,1859,1867,1874],{"__ignoreMap":543},[547,1335,1336,1338],{"class":549,"line":550},[547,1337,656],{"class":655},[547,1339,754],{"class":659},[547,1341,1342,1345],{"class":549,"line":704},[547,1343,1344],{"class":663},"  AuthContext",[547,1346,1347],{"class":659},",\n",[547,1349,1350,1353],{"class":549,"line":727},[547,1351,1352],{"class":663},"  CookieTokenSource",[547,1354,1347],{"class":659},[547,1356,1357,1360],{"class":549,"line":734},[547,1358,1359],{"class":663},"  JWTAuthMiddleware",[547,1361,1347],{"class":659},[547,1363,1364,1367],{"class":549,"line":741},[547,1365,1366],{"class":663},"  JWTFactory",[547,1368,1347],{"class":659},[547,1370,1371,1374],{"class":549,"line":757},[547,1372,1373],{"class":663},"  JWTVerifier",[547,1375,1347],{"class":659},[547,1377,1378,1381],{"class":549,"line":791},[547,1379,1380],{"class":663},"  PasswordHashingAlgorithm",[547,1382,1347],{"class":659},[547,1384,1385,1388],{"class":549,"line":818},[547,1386,1387],{"class":663},"  Scrypt",[547,1389,1347],{"class":659},[547,1391,1392,1394,1396,1398,1400,1402],{"class":549,"line":823},[547,1393,1189],{"class":659},[547,1395,689],{"class":655},[547,1397,692],{"class":659},[547,1399,695],{"class":556},[547,1401,698],{"class":659},[547,1403,701],{"class":659},[547,1405,1406,1408,1410,1413,1415,1418,1420,1422,1424,1426,1428],{"class":549,"line":853},[547,1407,656],{"class":655},[547,1409,660],{"class":659},[547,1411,1412],{"class":663}," Context",[547,1414,667],{"class":659},[547,1416,1417],{"class":663}," Module",[547,1419,686],{"class":659},[547,1421,689],{"class":655},[547,1423,692],{"class":659},[547,1425,720],{"class":556},[547,1427,698],{"class":659},[547,1429,701],{"class":659},[547,1431,1432,1434,1436,1439,1441,1443,1445,1448,1450],{"class":549,"line":880},[547,1433,656],{"class":655},[547,1435,660],{"class":659},[547,1437,1438],{"class":663}," AuthController",[547,1440,686],{"class":659},[547,1442,689],{"class":655},[547,1444,692],{"class":659},[547,1446,1447],{"class":556},".\u002Fauth.controller",[547,1449,698],{"class":659},[547,1451,701],{"class":659},[547,1453,1454,1456,1458,1460,1462,1464,1466,1469,1471],{"class":549,"line":885},[547,1455,656],{"class":655},[547,1457,660],{"class":659},[547,1459,751],{"class":663},[547,1461,686],{"class":659},[547,1463,689],{"class":655},[547,1465,692],{"class":659},[547,1467,1468],{"class":556},".\u002Fidentity-key-pair",[547,1470,698],{"class":659},[547,1472,701],{"class":659},[547,1474,1475,1477,1479,1482,1484,1486,1488,1491,1493],{"class":549,"line":909},[547,1476,656],{"class":655},[547,1478,660],{"class":659},[547,1480,1481],{"class":663}," JwksController",[547,1483,686],{"class":659},[547,1485,689],{"class":655},[547,1487,692],{"class":659},[547,1489,1490],{"class":556},".\u002Fjwks.controller",[547,1492,698],{"class":659},[547,1494,701],{"class":659},[547,1496,1497,1499,1501,1504,1506,1508,1510,1513,1515],{"class":549,"line":929},[547,1498,656],{"class":655},[547,1500,660],{"class":659},[547,1502,1503],{"class":663}," UserAccountStore",[547,1505,686],{"class":659},[547,1507,689],{"class":655},[547,1509,692],{"class":659},[547,1511,1512],{"class":556},".\u002Fuser-account-store",[547,1514,698],{"class":659},[547,1516,701],{"class":659},[547,1518,1519],{"class":549,"line":946},[547,1520,731],{"emptyLinePlaceholder":730},[547,1522,1523,1525,1527,1530,1533,1535,1537],{"class":549,"line":952},[547,1524,744],{"class":655},[547,1526,748],{"class":747},[547,1528,1529],{"class":553}," AuthModule",[547,1531,1532],{"class":747}," extends",[547,1534,1417],{"class":1008},[547,1536,893],{"class":663},[547,1538,1539],{"class":659},"{\n",[547,1541,1542,1545,1547],{"class":549,"line":957},[547,1543,1544],{"class":769},"  providers",[547,1546,773],{"class":659},[547,1548,1549],{"class":663}," [\n",[547,1551,1552,1555],{"class":549,"line":963},[547,1553,1554],{"class":663},"    UserAccountStore",[547,1556,1347],{"class":659},[547,1558,1559,1562,1565,1567,1570,1572,1575,1577,1580],{"class":549,"line":993},[547,1560,1561],{"class":659},"    {",[547,1563,1564],{"class":769}," provide",[547,1566,773],{"class":659},[547,1568,1569],{"class":663}," PasswordHashingAlgorithm",[547,1571,667],{"class":659},[547,1573,1574],{"class":769}," useClass",[547,1576,773],{"class":659},[547,1578,1579],{"class":663}," Scrypt ",[547,1581,1582],{"class":659},"},\n",[547,1584,1585,1588],{"class":549,"line":1025},[547,1586,1587],{"class":663},"    JWTAuthMiddleware",[547,1589,1347],{"class":659},[547,1591,1592],{"class":549,"line":1030},[547,1593,1594],{"class":659},"    {\n",[547,1596,1597,1600,1602,1604],{"class":549,"line":1044},[547,1598,1599],{"class":769},"      provide",[547,1601,773],{"class":659},[547,1603,751],{"class":663},[547,1605,1347],{"class":659},[547,1607,1608,1611,1613,1616,1618,1620,1622,1624,1627,1629,1631,1634,1636],{"class":549,"line":1060},[547,1609,1610],{"class":1008},"      useFactory",[547,1612,773],{"class":659},[547,1614,1615],{"class":659}," ():",[547,1617,979],{"class":553},[547,1619,982],{"class":659},[547,1621,985],{"class":553},[547,1623,988],{"class":659},[547,1625,1626],{"class":747}," =>",[547,1628,751],{"class":663},[547,1630,922],{"class":659},[547,1632,1633],{"class":1008},"resolve",[547,1635,1254],{"class":663},[547,1637,1347],{"class":659},[547,1639,1640],{"class":549,"line":1082},[547,1641,1642],{"class":659},"    },\n",[547,1644,1645],{"class":549,"line":1087},[547,1646,1594],{"class":659},[547,1648,1649,1651,1653,1656],{"class":549,"line":1092},[547,1650,1599],{"class":769},[547,1652,773],{"class":659},[547,1654,1655],{"class":663}," JWTFactory",[547,1657,1347],{"class":659},[547,1659,1660,1662,1664,1667,1670,1672,1674,1676,1678,1680,1682,1684,1687,1689,1692],{"class":549,"line":1098},[547,1661,1610],{"class":1008},[547,1663,773],{"class":659},[547,1665,1666],{"class":659}," (",[547,1668,1669],{"class":896},"keys",[547,1671,773],{"class":659},[547,1673,751],{"class":553},[547,1675,1116],{"class":659},[547,1677,1655],{"class":553},[547,1679,1626],{"class":747},[547,1681,1157],{"class":659},[547,1683,1655],{"class":1008},[547,1685,1686],{"class":663},"(keys",[547,1688,922],{"class":659},[547,1690,1691],{"class":663},"privateKey)",[547,1693,1347],{"class":659},[547,1695,1696],{"class":549,"line":1123},[547,1697,1642],{"class":659},[547,1699,1700],{"class":549,"line":1147},[547,1701,1594],{"class":659},[547,1703,1704,1706,1708,1711],{"class":549,"line":1152},[547,1705,1599],{"class":769},[547,1707,773],{"class":659},[547,1709,1710],{"class":663}," AuthContext",[547,1712,1347],{"class":659},[547,1714,1715,1717,1719,1721,1724,1726,1728,1730,1733,1735,1737,1739,1741],{"class":549,"line":1196},[547,1716,1610],{"class":1008},[547,1718,773],{"class":659},[547,1720,1666],{"class":659},[547,1722,1723],{"class":896},"context",[547,1725,773],{"class":659},[547,1727,1412],{"class":553},[547,1729,667],{"class":659},[547,1731,1732],{"class":896}," verifier",[547,1734,773],{"class":659},[547,1736,683],{"class":553},[547,1738,1116],{"class":659},[547,1740,1710],{"class":553},[547,1742,1743],{"class":747}," =>\n",[547,1745,1746,1749,1751,1754,1756,1758,1760,1762,1765,1767,1769,1772,1774,1776],{"class":549,"line":1201},[547,1747,1748],{"class":659},"        new",[547,1750,1710],{"class":1008},[547,1752,1753],{"class":663},"(context",[547,1755,667],{"class":659},[547,1757,1732],{"class":663},[547,1759,667],{"class":659},[547,1761,1157],{"class":659},[547,1763,1764],{"class":1008}," CookieTokenSource",[547,1766,893],{"class":663},[547,1768,698],{"class":659},[547,1770,1771],{"class":556},"accessToken",[547,1773,698],{"class":659},[547,1775,1270],{"class":663},[547,1777,1347],{"class":659},[547,1779,1780],{"class":549,"line":1206},[547,1781,1642],{"class":659},[547,1783,1784,1787],{"class":549,"line":1212},[547,1785,1786],{"class":663},"  ]",[547,1788,1347],{"class":659},[547,1790,1791,1794,1796,1798,1801,1803,1806,1808,1811],{"class":549,"line":1236},[547,1792,1793],{"class":769},"  http",[547,1795,773],{"class":659},[547,1797,660],{"class":659},[547,1799,1800],{"class":769}," controllers",[547,1802,773],{"class":659},[547,1804,1805],{"class":663}," [AuthController",[547,1807,667],{"class":659},[547,1809,1810],{"class":663}," JwksController] ",[547,1812,1582],{"class":659},[547,1814,1815,1818,1820],{"class":549,"line":1275},[547,1816,1817],{"class":769},"  exports",[547,1819,773],{"class":659},[547,1821,1549],{"class":663},[547,1823,1824,1827],{"class":549,"line":1280},[547,1825,1826],{"class":663},"    AuthContext",[547,1828,1347],{"class":659},[547,1830,1832,1834],{"class":549,"line":1831},38,[547,1833,1587],{"class":663},[547,1835,1347],{"class":659},[547,1837,1839,1842],{"class":549,"line":1838},39,[547,1840,1841],{"class":663},"    JWTVerifier",[547,1843,1347],{"class":659},[547,1845,1847,1850],{"class":549,"line":1846},40,[547,1848,1849],{"class":663},"    JWTFactory",[547,1851,1347],{"class":659},[547,1853,1855,1857],{"class":549,"line":1854},41,[547,1856,1554],{"class":663},[547,1858,1347],{"class":659},[547,1860,1862,1865],{"class":549,"line":1861},42,[547,1863,1864],{"class":663},"    PasswordHashingAlgorithm",[547,1866,1347],{"class":659},[547,1868,1870,1872],{"class":549,"line":1869},43,[547,1871,1786],{"class":663},[547,1873,1347],{"class":659},[547,1875,1877,1879,1881],{"class":549,"line":1876},44,[547,1878,1189],{"class":659},[547,1880,1186],{"class":663},[547,1882,1883],{"class":659},"{}\n",[499,1885,1886],{},"Three things worth noticing:",[1888,1889,1890,1907,1927],"ul",{},[1891,1892,1893,1896,1897,1900,1901,1903,1904,1906],"li",{},[503,1894,1895],{},"The password hasher is bound to a port."," ",[508,1898,1899],{},"{ provide: PasswordHashingAlgorithm, useClass: Scrypt }"," lets\nthe controller inject the abstract algorithm rather than a concrete hasher — swap ",[508,1902,518],{}," for ",[508,1905,522],{}," on\nan edge deploy and nothing else changes (more on this in the next section).",[1891,1908,1909,1916,1917,1919,1920,1922,1923,1926],{},[503,1910,1911,1913,1914,922],{},[508,1912,1326],{}," needs no ",[508,1915,1292],{}," Its constructor is only DI tokens — an ",[508,1918,510],{},", an\noptional flag — so the compiler recovers it straight from ",[508,1921,695],{},"'s shipped types; list it in\n",[508,1924,1925],{},"providers"," like any app class.",[1891,1928,1929,1896,1935,1938,1939,1941,1942,1944,1945,1949,1950,1952,1953,1955,1956,1958],{},[503,1930,1931,1932,1934],{},"There is no separate ",[508,1933,630],{}," provider.",[508,1936,1937],{},"JWTFactory extends JWTVerifier"," — it verifies with the\nsame key it signs with — so providing ",[508,1940,526],{}," alone satisfies every ",[508,1943,630],{},"-typed injection ",[1946,1947,1948],"em",{},"and","\nexport. ",[508,1951,510],{},"'s factory still declares its second parameter as ",[508,1954,630],{}," (the capability it\nactually needs); the compiler resolves it to the ",[508,1957,526],{}," instance.",[499,1960,1961,1963,1964,1967,1968,1970,1971,1974,1975,1977],{},[508,1962,985],{},"'s factory is ",[508,1965,1966],{},"async"," — Heximon awaits it once at boot — and ",[508,1969,510],{},"'s configures a\n",[508,1972,1973],{},"CookieTokenSource"," so the middleware reads the ",[508,1976,1771],{}," cookie the login handler sets (the next section\ncovers the header-based alternative).",[529,1979,1981],{"id":1980},"list-the-shipped-middleware-directly","List the shipped middleware directly",[499,1983,1984,1309,1986,1989,1990,1993,1994,1996,1997,2000,2001,1309,2004,2007,2008,2011,2012,2015,2016,2019],{},[508,1985,1326],{},[508,1987,1988],{},"GuardMiddleware"," are both ",[503,1991,1992],{},"bare providers"," — their constructors take only DI\ntokens, so the compiler recovers them from the package's shipped types and constructs them directly. There's\nno app-owned wrapper class to write; ",[508,1995,1326],{}," is already sitting in the module above, unwrapped,\nand it reads the bearer token (or the configured cookie), verifies it, and stores the principal. A ",[503,1998,1999],{},"missing\nor empty"," token continues as anonymous — deliberately, so ",[508,2002,2003],{},"\u002Fregister",[508,2005,2006],{},"\u002Flogin"," stay reachable without\none — while a present-but-",[503,2009,2010],{},"invalid"," token is always a hard ",[508,2013,2014],{},"401"," (RFC 9457 ",[508,2017,2018],{},"application\u002Fproblem+json",").",[499,2021,2022,2023,2026],{},"When a surface needs non-default behavior — say every request on it must carry a token — don't wrap it,\nsubclass it: a small subclass still gets its own DI identity, and the compiler reads the ",[508,2024,2025],{},"super(...)"," call to\nrecover the shipped base's constructor.",[537,2028,2031],{"className":645,"code":2029,"filename":2030,"language":648,"meta":543,"style":543},"import { AuthContext, JWTAuthMiddleware } from \"@heximon\u002Fauth\";\n\nexport class ApiAuthMiddleware extends JWTAuthMiddleware {\n  public constructor(authContext: AuthContext) {\n    super(authContext, true); \u002F\u002F requireToken: true — a missing token is a 401\n  }\n}\n","src\u002Fauth\u002Fapi-auth.middleware.ts",[508,2032,2033,2058,2062,2077,2096,2119,2123],{"__ignoreMap":543},[547,2034,2035,2037,2039,2041,2043,2046,2048,2050,2052,2054,2056],{"class":549,"line":550},[547,2036,656],{"class":655},[547,2038,660],{"class":659},[547,2040,1710],{"class":663},[547,2042,667],{"class":659},[547,2044,2045],{"class":663}," JWTAuthMiddleware",[547,2047,686],{"class":659},[547,2049,689],{"class":655},[547,2051,692],{"class":659},[547,2053,695],{"class":556},[547,2055,698],{"class":659},[547,2057,701],{"class":659},[547,2059,2060],{"class":549,"line":704},[547,2061,731],{"emptyLinePlaceholder":730},[547,2063,2064,2066,2068,2071,2073,2075],{"class":549,"line":727},[547,2065,744],{"class":655},[547,2067,748],{"class":747},[547,2069,2070],{"class":553}," ApiAuthMiddleware",[547,2072,1532],{"class":747},[547,2074,2045],{"class":553},[547,2076,754],{"class":659},[547,2078,2079,2081,2083,2085,2088,2090,2092,2094],{"class":549,"line":734},[547,2080,826],{"class":747},[547,2082,890],{"class":747},[547,2084,893],{"class":659},[547,2086,2087],{"class":896},"authContext",[547,2089,773],{"class":659},[547,2091,1710],{"class":553},[547,2093,904],{"class":659},[547,2095,754],{"class":659},[547,2097,2098,2101,2103,2105,2107,2111,2113,2116],{"class":549,"line":741},[547,2099,2100],{"class":663},"    super",[547,2102,893],{"class":769},[547,2104,2087],{"class":663},[547,2106,667],{"class":659},[547,2108,2110],{"class":2109},"sfNiH"," true",[547,2112,904],{"class":769},[547,2114,2115],{"class":659},";",[547,2117,2118],{"class":737}," \u002F\u002F requireToken: true — a missing token is a 401\n",[547,2120,2121],{"class":549,"line":757},[547,2122,949],{"class":659},[547,2124,2125],{"class":549,"line":791},[547,2126,1283],{"class":659},[499,2128,2129,2130,2133],{},"List ",[508,2131,2132],{},"ApiAuthMiddleware"," the same way as the shipped class — it's still a bare provider:",[537,2135,2137],{"className":645,"code":2136,"language":648,"meta":543,"style":543},"providers: [\u002F* … *\u002F ApiAuthMiddleware],\n",[508,2138,2139],{"__ignoreMap":543},[547,2140,2141,2143,2145,2148,2151,2154],{"class":549,"line":550},[547,2142,1925],{"class":553},[547,2144,773],{"class":659},[547,2146,2147],{"class":663}," [",[547,2149,2150],{"class":737},"\u002F* … *\u002F",[547,2152,2153],{"class":663}," ApiAuthMiddleware]",[547,2155,1347],{"class":659},[499,2157,2158,2159,2162,2163,2166,2167,2169],{},"A middleware that needs configuration DI truly can't express — not a property of a dependency, not a\n",[508,2160,2161],{},"super()"," argument, but a literal like a rate-limit threshold — can also be bound as ",[508,2164,2165],{},"{ provide: SomeMiddleware, useFactory: ... }"," in ",[508,2168,1925],{},", then referenced by class at every middleware site: the\ncompiler constructs one instance and every reference resolves to it.",[499,2171,2172,2174,2175,2178,2179,2181,2182,2184,2185,2188],{},[508,2173,1988],{}," is a bare provider too (",[508,2176,2177],{},"Context"," + ",[508,2180,510],{},") — see\n",[608,2183,102],{"href":103}," for how it reads a route's declared ",[508,2186,2187],{},"scopes"," and\nenforces them.",[529,2190,2192],{"id":2191},"choosing-where-the-token-comes-from","Choosing where the token comes from",[499,2194,2195,2196,2198,2199,2201,2202,2204,2205,2207,2208,2210,2211,2214,2215,2218,2219,2221,2222,2225,2226,1903,2228,922],{},"The module above passes a ",[508,2197,1973],{}," to ",[508,2200,510],{},"'s ",[508,2203,1292],{},", so ",[508,2206,1326],{}," reads\nthe token from the ",[508,2209,1771],{}," cookie the login handler sets, rather than the ",[508,2212,2213],{},"Authorization: Bearer","\nheader. The two sources are ",[503,2216,2217],{},"mutually exclusive"," — there is no implicit fallback chain. ",[508,2220,1973],{},"\nreads only the named cookie and ignores the ",[508,2223,2224],{},"Authorization"," header, and vice versa; pick one and configure it\nonce in the ",[508,2227,1292],{},[508,2229,510],{},[499,2231,2232,2235],{},[508,2233,2234],{},"HeaderTokenSource"," is the default, and this is its explicit form:",[537,2237,2239],{"className":645,"code":2238,"language":648,"meta":543,"style":543},"\u002F\u002F These three are equivalent:\nnew AuthContext(context, verifier);\nnew AuthContext(context, verifier, new HeaderTokenSource(\"authorization\"));\nnew AuthContext(context, verifier, \"authorization\"); \u002F\u002F deprecated string form\n",[508,2240,2241,2246,2262,2294],{"__ignoreMap":543},[547,2242,2243],{"class":549,"line":550},[547,2244,2245],{"class":737},"\u002F\u002F These three are equivalent:\n",[547,2247,2248,2251,2253,2255,2257,2260],{"class":549,"line":704},[547,2249,2250],{"class":659},"new",[547,2252,1710],{"class":1008},[547,2254,1753],{"class":663},[547,2256,667],{"class":659},[547,2258,2259],{"class":663}," verifier)",[547,2261,701],{"class":659},[547,2263,2264,2266,2268,2270,2272,2274,2276,2278,2281,2283,2285,2288,2290,2292],{"class":549,"line":727},[547,2265,2250],{"class":659},[547,2267,1710],{"class":1008},[547,2269,1753],{"class":663},[547,2271,667],{"class":659},[547,2273,1732],{"class":663},[547,2275,667],{"class":659},[547,2277,1157],{"class":659},[547,2279,2280],{"class":1008}," HeaderTokenSource",[547,2282,893],{"class":663},[547,2284,698],{"class":659},[547,2286,2287],{"class":556},"authorization",[547,2289,698],{"class":659},[547,2291,1270],{"class":663},[547,2293,701],{"class":659},[547,2295,2296,2298,2300,2302,2304,2306,2308,2310,2312,2314,2316,2318],{"class":549,"line":734},[547,2297,2250],{"class":659},[547,2299,1710],{"class":1008},[547,2301,1753],{"class":663},[547,2303,667],{"class":659},[547,2305,1732],{"class":663},[547,2307,667],{"class":659},[547,2309,692],{"class":659},[547,2311,2287],{"class":556},[547,2313,698],{"class":659},[547,2315,904],{"class":663},[547,2317,2115],{"class":659},[547,2319,2320],{"class":737}," \u002F\u002F deprecated string form\n",[499,2322,2323,2324,1309,2326,2328,2329,2331],{},"Both ",[508,2325,2234],{},[508,2327,1973],{}," extend the abstract ",[508,2330,1315],{}," base class, which you\ncan also extend to plug in custom extraction logic (e.g. a query-parameter token for OAuth callback flows).",[529,2333,2335],{"id":2334},"hash-passwords-and-issue-a-token-at-login","Hash passwords and issue a token at login",[499,2337,2338,2339,2342,2343,2345,2346,2348,2349,2352,2353,2356,2357,2359,2360,2363,2364,2367,2368,2371,2372,2375,2376,2378,2379,2381,2382,2385,2386,2385,2389,2392,2393,2395],{},"Registration and login are where you mint identity. ",[508,2340,2341],{},"register"," hashes the incoming password through the\nabstract ",[508,2344,514],{}," port — bound to ",[508,2347,518],{}," by the module above — and grants a default\nscope; ",[508,2350,2351],{},"login"," verifies it in constant time, then signs a ",[508,2354,2355],{},"PermissionsJWTPayload"," with ",[508,2358,526],{}," — the\nstandard JWT claims plus an inline ",[508,2361,2362],{},"permissions[]"," array — into a ",[508,2365,2366],{},"JWT"," whose ",[508,2369,2370],{},"value"," is the encoded string;\n",[508,2373,2374],{},"me"," reads back the principal the controller-level ",[508,2377,1326],{}," already established. The port is\n",[503,2380,1966],{}," — ",[508,2383,2384],{},"hash()"," \u002F ",[508,2387,2388],{},"verify()",[508,2390,2391],{},"simulate()"," return promises — because the edge-safe ",[508,2394,522],{}," algorithm\nderives via WebCrypto, which is async-only.",[537,2397,2400],{"className":645,"code":2398,"filename":2399,"language":648,"meta":543,"style":543},"import { AuthContext, JWTAuthMiddleware, JWTFactory, PasswordHashingAlgorithm } from \"@heximon\u002Fauth\";\nimport type { Controller, Get, Post } from \"@heximon\u002Fhttp\";\nimport type { UserAccount } from \".\u002Fuser-account-store\";\nimport { UserAccountStore } from \".\u002Fuser-account-store\";\n\ninterface Credentials {\n  readonly email: string;\n  readonly password: string;\n}\n\nexport class AuthController implements Controller\u003C{ prefix: \"\u002Fauth\"; middlewares: [JWTAuthMiddleware] }> {\n  private static readonly minimumPasswordLength: number = 8;\n  private static readonly tokenLifetimeMilliseconds: number = 60 * 60 * 1000; \u002F\u002F one hour\n  private static readonly defaultPermissions: readonly string[] = [\"profile:read\"];\n\n  public constructor(\n    private readonly accounts: UserAccountStore,\n    private readonly passwordHashing: PasswordHashingAlgorithm,\n    private readonly tokenFactory: JWTFactory,\n    private readonly authContext: AuthContext,\n  ) {}\n\n  public async register(action: Post\u003C\"\u002Fregister\">): Promise\u003CResponse> {\n    const credentials = AuthController.readCredentials(await action.request.readBody());\n\n    if (!credentials) {\n      return action.respond(400, { error: \"An email and an 8+ character password are required.\" });\n    }\n    if (this.accounts.hasEmail(credentials.email)) {\n      return action.respond(409, { error: \"That email is already registered.\" });\n    }\n\n    const account = this.accounts.create({\n      email: credentials.email,\n      passwordHash: await this.passwordHashing.hash(credentials.password),\n      permissions: AuthController.defaultPermissions,\n    });\n\n    return action.respond(201, { id: account.id, email: account.email });\n  }\n\n  public async login(action: Post\u003C\"\u002Flogin\">): Promise\u003CResponse> {\n    const credentials = AuthController.readCredentials(await action.request.readBody());\n\n    if (!credentials) {\n      return action.respond(400, { error: \"An email and a password are required.\" });\n    }\n\n    const account = this.accounts.findByEmail(credentials.email);\n\n    if (!account) {\n      \u002F\u002F Run a dummy hash so a missing account is indistinguishable (by timing) from a wrong password.\n      await this.passwordHashing.simulate();\n      return action.respond(401, { error: \"Invalid credentials.\" });\n    }\n    if (!(await this.passwordHashing.verify(account.passwordHash, credentials.password))) {\n      return action.respond(401, { error: \"Invalid credentials.\" });\n    }\n\n    const expiresAt = new Date(Date.now() + AuthController.tokenLifetimeMilliseconds);\n    const token = await this.tokenFactory.create(\n      { sub: account.id, permissions: [...account.permissions] },\n      expiresAt,\n    );\n\n    \u002F\u002F Deliver the token both ways: an HttpOnly cookie the middleware reads back, and the body for an\n    \u002F\u002F `Authorization: Bearer` client (curl, the test suite, another service).\n    action.response.setCookie(\"accessToken\", token.value, {\n      httpOnly: true,\n      sameSite: \"lax\",\n      secure: false,\n      expires: expiresAt,\n    });\n\n    return action.respond(200, {\n      userId: account.id,\n      accessToken: token.value,\n      expiresAt: expiresAt.toISOString(),\n    });\n  }\n\n  public async me(action: Get\u003C\"\u002Fme\">): Promise\u003CResponse> {\n    const userId = this.authContext.subject(); \u002F\u002F set by JWTAuthMiddleware when a valid token was sent\n\n    if (userId === undefined) {\n      return action.respond(401, { error: \"Authentication is required.\" });\n    }\n\n    const account = this.accounts.findById(userId);\n\n    if (!account) {\n      return action.respond(401, { error: \"The authenticated account no longer exists.\" });\n    }\n\n    return action.respond(200, AuthController.toProfile(account));\n  }\n\n  private static readCredentials(body: unknown): Credentials | undefined {\n    if (typeof body !== \"object\" || body === null) return undefined;\n    const { email, password } = body as Record\u003Cstring, unknown>;\n    if (typeof email !== \"string\" || !email.includes(\"@\")) return undefined;\n    if (typeof password !== \"string\" || password.length \u003C AuthController.minimumPasswordLength) {\n      return undefined;\n    }\n    return { email, password };\n  }\n\n  private static toProfile(account: UserAccount): { id: string; email: string; permissions: readonly string[] } {\n    return { id: account.id, email: account.email, permissions: account.permissions };\n  }\n}\n","src\u002Fauth\u002Fauth.controller.ts",[508,2401,2402,2434,2468,2491,2511,2515,2525,2539,2552,2556,2560,2607,2631,2666,2702,2706,2715,2731,2746,2761,2776,2784,2788,2828,2866,2870,2887,2926,2931,2962,2998,3002,3006,3029,3044,3077,3093,3102,3106,3155,3159,3163,3200,3232,3236,3251,3287,3292,3297,3327,3332,3348,3354,3373,3409,3414,3458,3493,3498,3503,3545,3568,3608,3616,3624,3629,3635,3641,3677,3689,3706,3719,3731,3740,3745,3765,3781,3797,3815,3824,3829,3834,3873,3899,3904,3923,3959,3964,3969,3995,4000,4015,4051,4056,4061,4093,4098,4103,4134,4175,4212,4258,4300,4307,4312,4328,4333,4338,4390,4433,4438],{"__ignoreMap":543},[547,2403,2404,2406,2408,2410,2412,2414,2416,2418,2420,2422,2424,2426,2428,2430,2432],{"class":549,"line":550},[547,2405,656],{"class":655},[547,2407,660],{"class":659},[547,2409,1710],{"class":663},[547,2411,667],{"class":659},[547,2413,2045],{"class":663},[547,2415,667],{"class":659},[547,2417,1655],{"class":663},[547,2419,667],{"class":659},[547,2421,1569],{"class":663},[547,2423,686],{"class":659},[547,2425,689],{"class":655},[547,2427,692],{"class":659},[547,2429,695],{"class":556},[547,2431,698],{"class":659},[547,2433,701],{"class":659},[547,2435,2436,2438,2440,2442,2445,2447,2450,2452,2455,2457,2459,2461,2464,2466],{"class":549,"line":704},[547,2437,656],{"class":655},[547,2439,670],{"class":655},[547,2441,660],{"class":659},[547,2443,2444],{"class":663}," Controller",[547,2446,667],{"class":659},[547,2448,2449],{"class":663}," Get",[547,2451,667],{"class":659},[547,2453,2454],{"class":663}," Post",[547,2456,686],{"class":659},[547,2458,689],{"class":655},[547,2460,692],{"class":659},[547,2462,2463],{"class":556},"@heximon\u002Fhttp",[547,2465,698],{"class":659},[547,2467,701],{"class":659},[547,2469,2470,2472,2474,2476,2479,2481,2483,2485,2487,2489],{"class":549,"line":727},[547,2471,656],{"class":655},[547,2473,670],{"class":655},[547,2475,660],{"class":659},[547,2477,2478],{"class":663}," UserAccount",[547,2480,686],{"class":659},[547,2482,689],{"class":655},[547,2484,692],{"class":659},[547,2486,1512],{"class":556},[547,2488,698],{"class":659},[547,2490,701],{"class":659},[547,2492,2493,2495,2497,2499,2501,2503,2505,2507,2509],{"class":549,"line":734},[547,2494,656],{"class":655},[547,2496,660],{"class":659},[547,2498,1503],{"class":663},[547,2500,686],{"class":659},[547,2502,689],{"class":655},[547,2504,692],{"class":659},[547,2506,1512],{"class":556},[547,2508,698],{"class":659},[547,2510,701],{"class":659},[547,2512,2513],{"class":549,"line":741},[547,2514,731],{"emptyLinePlaceholder":730},[547,2516,2517,2520,2523],{"class":549,"line":757},[547,2518,2519],{"class":747},"interface",[547,2521,2522],{"class":553}," Credentials",[547,2524,754],{"class":659},[547,2526,2527,2530,2533,2535,2537],{"class":549,"line":791},[547,2528,2529],{"class":747},"  readonly",[547,2531,2532],{"class":769}," email",[547,2534,773],{"class":659},[547,2536,776],{"class":553},[547,2538,701],{"class":659},[547,2540,2541,2543,2546,2548,2550],{"class":549,"line":818},[547,2542,2529],{"class":747},[547,2544,2545],{"class":769}," password",[547,2547,773],{"class":659},[547,2549,776],{"class":553},[547,2551,701],{"class":659},[547,2553,2554],{"class":549,"line":823},[547,2555,1283],{"class":659},[547,2557,2558],{"class":549,"line":853},[547,2559,731],{"emptyLinePlaceholder":730},[547,2561,2562,2564,2566,2568,2571,2573,2576,2579,2581,2583,2586,2588,2590,2593,2595,2597,2599,2602,2605],{"class":549,"line":880},[547,2563,744],{"class":655},[547,2565,748],{"class":747},[547,2567,1438],{"class":553},[547,2569,2570],{"class":747}," implements",[547,2572,2444],{"class":553},[547,2574,2575],{"class":659},"\u003C{",[547,2577,2578],{"class":769}," prefix",[547,2580,773],{"class":659},[547,2582,692],{"class":659},[547,2584,2585],{"class":556},"\u002Fauth",[547,2587,698],{"class":659},[547,2589,2115],{"class":659},[547,2591,2592],{"class":769}," middlewares",[547,2594,773],{"class":659},[547,2596,2147],{"class":663},[547,2598,1326],{"class":553},[547,2600,2601],{"class":663},"] ",[547,2603,2604],{"class":659},"}>",[547,2606,754],{"class":659},[547,2608,2609,2611,2613,2615,2618,2620,2623,2625,2629],{"class":549,"line":885},[547,2610,760],{"class":747},[547,2612,763],{"class":747},[547,2614,766],{"class":747},[547,2616,2617],{"class":769}," minimumPasswordLength",[547,2619,773],{"class":659},[547,2621,2622],{"class":553}," number",[547,2624,779],{"class":659},[547,2626,2628],{"class":2627},"sbssI"," 8",[547,2630,701],{"class":659},[547,2632,2633,2635,2637,2639,2642,2644,2646,2648,2651,2654,2656,2658,2661,2663],{"class":549,"line":909},[547,2634,760],{"class":747},[547,2636,763],{"class":747},[547,2638,766],{"class":747},[547,2640,2641],{"class":769}," tokenLifetimeMilliseconds",[547,2643,773],{"class":659},[547,2645,2622],{"class":553},[547,2647,779],{"class":659},[547,2649,2650],{"class":2627}," 60",[547,2652,2653],{"class":659}," *",[547,2655,2650],{"class":2627},[547,2657,2653],{"class":659},[547,2659,2660],{"class":2627}," 1000",[547,2662,2115],{"class":659},[547,2664,2665],{"class":737}," \u002F\u002F one hour\n",[547,2667,2668,2670,2672,2674,2677,2679,2681,2683,2686,2689,2691,2693,2696,2698,2700],{"class":549,"line":929},[547,2669,760],{"class":747},[547,2671,763],{"class":747},[547,2673,766],{"class":747},[547,2675,2676],{"class":769}," defaultPermissions",[547,2678,773],{"class":659},[547,2680,766],{"class":747},[547,2682,776],{"class":553},[547,2684,2685],{"class":663},"[] ",[547,2687,2688],{"class":659},"=",[547,2690,2147],{"class":663},[547,2692,698],{"class":659},[547,2694,2695],{"class":556},"profile:read",[547,2697,698],{"class":659},[547,2699,848],{"class":663},[547,2701,701],{"class":659},[547,2703,2704],{"class":549,"line":946},[547,2705,731],{"emptyLinePlaceholder":730},[547,2707,2708,2710,2712],{"class":549,"line":952},[547,2709,826],{"class":747},[547,2711,890],{"class":747},[547,2713,2714],{"class":659},"(\n",[547,2716,2717,2720,2722,2725,2727,2729],{"class":549,"line":957},[547,2718,2719],{"class":747},"    private",[547,2721,766],{"class":747},[547,2723,2724],{"class":896}," accounts",[547,2726,773],{"class":659},[547,2728,1503],{"class":553},[547,2730,1347],{"class":659},[547,2732,2733,2735,2737,2740,2742,2744],{"class":549,"line":963},[547,2734,2719],{"class":747},[547,2736,766],{"class":747},[547,2738,2739],{"class":896}," passwordHashing",[547,2741,773],{"class":659},[547,2743,1569],{"class":553},[547,2745,1347],{"class":659},[547,2747,2748,2750,2752,2755,2757,2759],{"class":549,"line":993},[547,2749,2719],{"class":747},[547,2751,766],{"class":747},[547,2753,2754],{"class":896}," tokenFactory",[547,2756,773],{"class":659},[547,2758,1655],{"class":553},[547,2760,1347],{"class":659},[547,2762,2763,2765,2767,2770,2772,2774],{"class":549,"line":1025},[547,2764,2719],{"class":747},[547,2766,766],{"class":747},[547,2768,2769],{"class":896}," authContext",[547,2771,773],{"class":659},[547,2773,1710],{"class":553},[547,2775,1347],{"class":659},[547,2777,2778,2781],{"class":549,"line":1030},[547,2779,2780],{"class":659},"  )",[547,2782,2783],{"class":659}," {}\n",[547,2785,2786],{"class":549,"line":1044},[547,2787,731],{"emptyLinePlaceholder":730},[547,2789,2790,2792,2794,2797,2799,2802,2804,2806,2808,2810,2812,2814,2817,2819,2821,2824,2826],{"class":549,"line":1060},[547,2791,826],{"class":747},[547,2793,970],{"class":747},[547,2795,2796],{"class":769}," register",[547,2798,893],{"class":659},[547,2800,2801],{"class":896},"action",[547,2803,773],{"class":659},[547,2805,2454],{"class":553},[547,2807,982],{"class":659},[547,2809,698],{"class":659},[547,2811,2003],{"class":556},[547,2813,698],{"class":659},[547,2815,2816],{"class":659},">):",[547,2818,979],{"class":553},[547,2820,982],{"class":659},[547,2822,2823],{"class":553},"Response",[547,2825,988],{"class":659},[547,2827,754],{"class":659},[547,2829,2830,2832,2835,2837,2839,2841,2844,2846,2848,2851,2853,2856,2858,2861,2864],{"class":549,"line":1082},[547,2831,996],{"class":747},[547,2833,2834],{"class":663}," credentials",[547,2836,779],{"class":659},[547,2838,1438],{"class":663},[547,2840,922],{"class":659},[547,2842,2843],{"class":1008},"readCredentials",[547,2845,893],{"class":769},[547,2847,1247],{"class":655},[547,2849,2850],{"class":663}," action",[547,2852,922],{"class":659},[547,2854,2855],{"class":663},"request",[547,2857,922],{"class":659},[547,2859,2860],{"class":1008},"readBody",[547,2862,2863],{"class":769},"())",[547,2865,701],{"class":659},[547,2867,2868],{"class":549,"line":1087},[547,2869,731],{"emptyLinePlaceholder":730},[547,2871,2872,2875,2877,2880,2883,2885],{"class":549,"line":1092},[547,2873,2874],{"class":655},"    if",[547,2876,1666],{"class":769},[547,2878,2879],{"class":659},"!",[547,2881,2882],{"class":663},"credentials",[547,2884,1186],{"class":769},[547,2886,1539],{"class":659},[547,2888,2889,2892,2894,2896,2899,2901,2904,2906,2908,2911,2913,2915,2918,2920,2922,2924],{"class":549,"line":1098},[547,2890,2891],{"class":655},"      return",[547,2893,2850],{"class":663},[547,2895,922],{"class":659},[547,2897,2898],{"class":1008},"respond",[547,2900,893],{"class":769},[547,2902,2903],{"class":2627},"400",[547,2905,667],{"class":659},[547,2907,660],{"class":659},[547,2909,2910],{"class":769}," error",[547,2912,773],{"class":659},[547,2914,692],{"class":659},[547,2916,2917],{"class":556},"An email and an 8+ character password are required.",[547,2919,698],{"class":659},[547,2921,686],{"class":659},[547,2923,904],{"class":769},[547,2925,701],{"class":659},[547,2927,2928],{"class":549,"line":1123},[547,2929,2930],{"class":659},"    }\n",[547,2932,2933,2935,2937,2940,2943,2945,2948,2950,2952,2954,2957,2960],{"class":549,"line":1147},[547,2934,2874],{"class":655},[547,2936,1666],{"class":769},[547,2938,2939],{"class":659},"this.",[547,2941,2942],{"class":663},"accounts",[547,2944,922],{"class":659},[547,2946,2947],{"class":1008},"hasEmail",[547,2949,893],{"class":769},[547,2951,2882],{"class":663},[547,2953,922],{"class":659},[547,2955,2956],{"class":663},"email",[547,2958,2959],{"class":769},")) ",[547,2961,1539],{"class":659},[547,2963,2964,2966,2968,2970,2972,2974,2977,2979,2981,2983,2985,2987,2990,2992,2994,2996],{"class":549,"line":1152},[547,2965,2891],{"class":655},[547,2967,2850],{"class":663},[547,2969,922],{"class":659},[547,2971,2898],{"class":1008},[547,2973,893],{"class":769},[547,2975,2976],{"class":2627},"409",[547,2978,667],{"class":659},[547,2980,660],{"class":659},[547,2982,2910],{"class":769},[547,2984,773],{"class":659},[547,2986,692],{"class":659},[547,2988,2989],{"class":556},"That email is already registered.",[547,2991,698],{"class":659},[547,2993,686],{"class":659},[547,2995,904],{"class":769},[547,2997,701],{"class":659},[547,2999,3000],{"class":549,"line":1196},[547,3001,2930],{"class":659},[547,3003,3004],{"class":549,"line":1201},[547,3005,731],{"emptyLinePlaceholder":730},[547,3007,3008,3010,3013,3015,3018,3020,3022,3025,3027],{"class":549,"line":1206},[547,3009,996],{"class":747},[547,3011,3012],{"class":663}," account",[547,3014,779],{"class":659},[547,3016,3017],{"class":659}," this.",[547,3019,2942],{"class":663},[547,3021,922],{"class":659},[547,3023,3024],{"class":1008},"create",[547,3026,893],{"class":769},[547,3028,1539],{"class":659},[547,3030,3031,3034,3036,3038,3040,3042],{"class":549,"line":1212},[547,3032,3033],{"class":769},"      email",[547,3035,773],{"class":659},[547,3037,2834],{"class":663},[547,3039,922],{"class":659},[547,3041,2956],{"class":663},[547,3043,1347],{"class":659},[547,3045,3046,3049,3051,3054,3056,3059,3061,3064,3066,3068,3070,3073,3075],{"class":549,"line":1236},[547,3047,3048],{"class":769},"      passwordHash",[547,3050,773],{"class":659},[547,3052,3053],{"class":655}," await",[547,3055,3017],{"class":659},[547,3057,3058],{"class":663},"passwordHashing",[547,3060,922],{"class":659},[547,3062,3063],{"class":1008},"hash",[547,3065,893],{"class":769},[547,3067,2882],{"class":663},[547,3069,922],{"class":659},[547,3071,3072],{"class":663},"password",[547,3074,904],{"class":769},[547,3076,1347],{"class":659},[547,3078,3079,3082,3084,3086,3088,3091],{"class":549,"line":1275},[547,3080,3081],{"class":769},"      permissions",[547,3083,773],{"class":659},[547,3085,1438],{"class":663},[547,3087,922],{"class":659},[547,3089,3090],{"class":663},"defaultPermissions",[547,3092,1347],{"class":659},[547,3094,3095,3098,3100],{"class":549,"line":1280},[547,3096,3097],{"class":659},"    }",[547,3099,904],{"class":769},[547,3101,701],{"class":659},[547,3103,3104],{"class":549,"line":1831},[547,3105,731],{"emptyLinePlaceholder":730},[547,3107,3108,3110,3112,3114,3116,3118,3121,3123,3125,3128,3130,3132,3134,3137,3139,3141,3143,3145,3147,3149,3151,3153],{"class":549,"line":1838},[547,3109,1033],{"class":655},[547,3111,2850],{"class":663},[547,3113,922],{"class":659},[547,3115,2898],{"class":1008},[547,3117,893],{"class":769},[547,3119,3120],{"class":2627},"201",[547,3122,667],{"class":659},[547,3124,660],{"class":659},[547,3126,3127],{"class":769}," id",[547,3129,773],{"class":659},[547,3131,3012],{"class":663},[547,3133,922],{"class":659},[547,3135,3136],{"class":663},"id",[547,3138,667],{"class":659},[547,3140,2532],{"class":769},[547,3142,773],{"class":659},[547,3144,3012],{"class":663},[547,3146,922],{"class":659},[547,3148,2956],{"class":663},[547,3150,686],{"class":659},[547,3152,904],{"class":769},[547,3154,701],{"class":659},[547,3156,3157],{"class":549,"line":1846},[547,3158,949],{"class":659},[547,3160,3161],{"class":549,"line":1854},[547,3162,731],{"emptyLinePlaceholder":730},[547,3164,3165,3167,3169,3172,3174,3176,3178,3180,3182,3184,3186,3188,3190,3192,3194,3196,3198],{"class":549,"line":1861},[547,3166,826],{"class":747},[547,3168,970],{"class":747},[547,3170,3171],{"class":769}," login",[547,3173,893],{"class":659},[547,3175,2801],{"class":896},[547,3177,773],{"class":659},[547,3179,2454],{"class":553},[547,3181,982],{"class":659},[547,3183,698],{"class":659},[547,3185,2006],{"class":556},[547,3187,698],{"class":659},[547,3189,2816],{"class":659},[547,3191,979],{"class":553},[547,3193,982],{"class":659},[547,3195,2823],{"class":553},[547,3197,988],{"class":659},[547,3199,754],{"class":659},[547,3201,3202,3204,3206,3208,3210,3212,3214,3216,3218,3220,3222,3224,3226,3228,3230],{"class":549,"line":1869},[547,3203,996],{"class":747},[547,3205,2834],{"class":663},[547,3207,779],{"class":659},[547,3209,1438],{"class":663},[547,3211,922],{"class":659},[547,3213,2843],{"class":1008},[547,3215,893],{"class":769},[547,3217,1247],{"class":655},[547,3219,2850],{"class":663},[547,3221,922],{"class":659},[547,3223,2855],{"class":663},[547,3225,922],{"class":659},[547,3227,2860],{"class":1008},[547,3229,2863],{"class":769},[547,3231,701],{"class":659},[547,3233,3234],{"class":549,"line":1876},[547,3235,731],{"emptyLinePlaceholder":730},[547,3237,3239,3241,3243,3245,3247,3249],{"class":549,"line":3238},45,[547,3240,2874],{"class":655},[547,3242,1666],{"class":769},[547,3244,2879],{"class":659},[547,3246,2882],{"class":663},[547,3248,1186],{"class":769},[547,3250,1539],{"class":659},[547,3252,3254,3256,3258,3260,3262,3264,3266,3268,3270,3272,3274,3276,3279,3281,3283,3285],{"class":549,"line":3253},46,[547,3255,2891],{"class":655},[547,3257,2850],{"class":663},[547,3259,922],{"class":659},[547,3261,2898],{"class":1008},[547,3263,893],{"class":769},[547,3265,2903],{"class":2627},[547,3267,667],{"class":659},[547,3269,660],{"class":659},[547,3271,2910],{"class":769},[547,3273,773],{"class":659},[547,3275,692],{"class":659},[547,3277,3278],{"class":556},"An email and a password are required.",[547,3280,698],{"class":659},[547,3282,686],{"class":659},[547,3284,904],{"class":769},[547,3286,701],{"class":659},[547,3288,3290],{"class":549,"line":3289},47,[547,3291,2930],{"class":659},[547,3293,3295],{"class":549,"line":3294},48,[547,3296,731],{"emptyLinePlaceholder":730},[547,3298,3300,3302,3304,3306,3308,3310,3312,3315,3317,3319,3321,3323,3325],{"class":549,"line":3299},49,[547,3301,996],{"class":747},[547,3303,3012],{"class":663},[547,3305,779],{"class":659},[547,3307,3017],{"class":659},[547,3309,2942],{"class":663},[547,3311,922],{"class":659},[547,3313,3314],{"class":1008},"findByEmail",[547,3316,893],{"class":769},[547,3318,2882],{"class":663},[547,3320,922],{"class":659},[547,3322,2956],{"class":663},[547,3324,904],{"class":769},[547,3326,701],{"class":659},[547,3328,3330],{"class":549,"line":3329},50,[547,3331,731],{"emptyLinePlaceholder":730},[547,3333,3335,3337,3339,3341,3344,3346],{"class":549,"line":3334},51,[547,3336,2874],{"class":655},[547,3338,1666],{"class":769},[547,3340,2879],{"class":659},[547,3342,3343],{"class":663},"account",[547,3345,1186],{"class":769},[547,3347,1539],{"class":659},[547,3349,3351],{"class":549,"line":3350},52,[547,3352,3353],{"class":737},"      \u002F\u002F Run a dummy hash so a missing account is indistinguishable (by timing) from a wrong password.\n",[547,3355,3357,3360,3362,3364,3366,3369,3371],{"class":549,"line":3356},53,[547,3358,3359],{"class":655},"      await",[547,3361,3017],{"class":659},[547,3363,3058],{"class":663},[547,3365,922],{"class":659},[547,3367,3368],{"class":1008},"simulate",[547,3370,1254],{"class":769},[547,3372,701],{"class":659},[547,3374,3376,3378,3380,3382,3384,3386,3388,3390,3392,3394,3396,3398,3401,3403,3405,3407],{"class":549,"line":3375},54,[547,3377,2891],{"class":655},[547,3379,2850],{"class":663},[547,3381,922],{"class":659},[547,3383,2898],{"class":1008},[547,3385,893],{"class":769},[547,3387,2014],{"class":2627},[547,3389,667],{"class":659},[547,3391,660],{"class":659},[547,3393,2910],{"class":769},[547,3395,773],{"class":659},[547,3397,692],{"class":659},[547,3399,3400],{"class":556},"Invalid credentials.",[547,3402,698],{"class":659},[547,3404,686],{"class":659},[547,3406,904],{"class":769},[547,3408,701],{"class":659},[547,3410,3412],{"class":549,"line":3411},55,[547,3413,2930],{"class":659},[547,3415,3417,3419,3421,3423,3425,3427,3429,3431,3433,3436,3438,3440,3442,3445,3447,3449,3451,3453,3456],{"class":549,"line":3416},56,[547,3418,2874],{"class":655},[547,3420,1666],{"class":769},[547,3422,2879],{"class":659},[547,3424,893],{"class":769},[547,3426,1247],{"class":655},[547,3428,3017],{"class":659},[547,3430,3058],{"class":663},[547,3432,922],{"class":659},[547,3434,3435],{"class":1008},"verify",[547,3437,893],{"class":769},[547,3439,3343],{"class":663},[547,3441,922],{"class":659},[547,3443,3444],{"class":663},"passwordHash",[547,3446,667],{"class":659},[547,3448,2834],{"class":663},[547,3450,922],{"class":659},[547,3452,3072],{"class":663},[547,3454,3455],{"class":769},"))) ",[547,3457,1539],{"class":659},[547,3459,3461,3463,3465,3467,3469,3471,3473,3475,3477,3479,3481,3483,3485,3487,3489,3491],{"class":549,"line":3460},57,[547,3462,2891],{"class":655},[547,3464,2850],{"class":663},[547,3466,922],{"class":659},[547,3468,2898],{"class":1008},[547,3470,893],{"class":769},[547,3472,2014],{"class":2627},[547,3474,667],{"class":659},[547,3476,660],{"class":659},[547,3478,2910],{"class":769},[547,3480,773],{"class":659},[547,3482,692],{"class":659},[547,3484,3400],{"class":556},[547,3486,698],{"class":659},[547,3488,686],{"class":659},[547,3490,904],{"class":769},[547,3492,701],{"class":659},[547,3494,3496],{"class":549,"line":3495},58,[547,3497,2930],{"class":659},[547,3499,3501],{"class":549,"line":3500},59,[547,3502,731],{"emptyLinePlaceholder":730},[547,3504,3506,3508,3511,3513,3515,3518,3520,3523,3525,3528,3531,3534,3536,3538,3541,3543],{"class":549,"line":3505},60,[547,3507,996],{"class":747},[547,3509,3510],{"class":663}," expiresAt",[547,3512,779],{"class":659},[547,3514,1157],{"class":659},[547,3516,3517],{"class":1008}," Date",[547,3519,893],{"class":769},[547,3521,3522],{"class":663},"Date",[547,3524,922],{"class":659},[547,3526,3527],{"class":1008},"now",[547,3529,3530],{"class":769},"() ",[547,3532,3533],{"class":659},"+",[547,3535,1438],{"class":663},[547,3537,922],{"class":659},[547,3539,3540],{"class":663},"tokenLifetimeMilliseconds",[547,3542,904],{"class":769},[547,3544,701],{"class":659},[547,3546,3548,3550,3553,3555,3557,3559,3562,3564,3566],{"class":549,"line":3547},61,[547,3549,996],{"class":747},[547,3551,3552],{"class":663}," token",[547,3554,779],{"class":659},[547,3556,3053],{"class":655},[547,3558,3017],{"class":659},[547,3560,3561],{"class":663},"tokenFactory",[547,3563,922],{"class":659},[547,3565,3024],{"class":1008},[547,3567,2714],{"class":769},[547,3569,3571,3574,3577,3579,3581,3583,3585,3587,3590,3592,3594,3597,3599,3601,3604,3606],{"class":549,"line":3570},62,[547,3572,3573],{"class":659},"      {",[547,3575,3576],{"class":769}," sub",[547,3578,773],{"class":659},[547,3580,3012],{"class":663},[547,3582,922],{"class":659},[547,3584,3136],{"class":663},[547,3586,667],{"class":659},[547,3588,3589],{"class":769}," permissions",[547,3591,773],{"class":659},[547,3593,2147],{"class":769},[547,3595,3596],{"class":659},"...",[547,3598,3343],{"class":663},[547,3600,922],{"class":659},[547,3602,3603],{"class":663},"permissions",[547,3605,2601],{"class":769},[547,3607,1582],{"class":659},[547,3609,3611,3614],{"class":549,"line":3610},63,[547,3612,3613],{"class":663},"      expiresAt",[547,3615,1347],{"class":659},[547,3617,3619,3622],{"class":549,"line":3618},64,[547,3620,3621],{"class":769},"    )",[547,3623,701],{"class":659},[547,3625,3627],{"class":549,"line":3626},65,[547,3628,731],{"emptyLinePlaceholder":730},[547,3630,3632],{"class":549,"line":3631},66,[547,3633,3634],{"class":737},"    \u002F\u002F Deliver the token both ways: an HttpOnly cookie the middleware reads back, and the body for an\n",[547,3636,3638],{"class":549,"line":3637},67,[547,3639,3640],{"class":737},"    \u002F\u002F `Authorization: Bearer` client (curl, the test suite, another service).\n",[547,3642,3644,3647,3649,3652,3654,3657,3659,3661,3663,3665,3667,3669,3671,3673,3675],{"class":549,"line":3643},68,[547,3645,3646],{"class":663},"    action",[547,3648,922],{"class":659},[547,3650,3651],{"class":663},"response",[547,3653,922],{"class":659},[547,3655,3656],{"class":1008},"setCookie",[547,3658,893],{"class":769},[547,3660,698],{"class":659},[547,3662,1771],{"class":556},[547,3664,698],{"class":659},[547,3666,667],{"class":659},[547,3668,3552],{"class":663},[547,3670,922],{"class":659},[547,3672,2370],{"class":663},[547,3674,667],{"class":659},[547,3676,754],{"class":659},[547,3678,3680,3683,3685,3687],{"class":549,"line":3679},69,[547,3681,3682],{"class":769},"      httpOnly",[547,3684,773],{"class":659},[547,3686,2110],{"class":2109},[547,3688,1347],{"class":659},[547,3690,3692,3695,3697,3699,3702,3704],{"class":549,"line":3691},70,[547,3693,3694],{"class":769},"      sameSite",[547,3696,773],{"class":659},[547,3698,692],{"class":659},[547,3700,3701],{"class":556},"lax",[547,3703,698],{"class":659},[547,3705,1347],{"class":659},[547,3707,3709,3712,3714,3717],{"class":549,"line":3708},71,[547,3710,3711],{"class":769},"      secure",[547,3713,773],{"class":659},[547,3715,3716],{"class":2109}," false",[547,3718,1347],{"class":659},[547,3720,3722,3725,3727,3729],{"class":549,"line":3721},72,[547,3723,3724],{"class":769},"      expires",[547,3726,773],{"class":659},[547,3728,3510],{"class":663},[547,3730,1347],{"class":659},[547,3732,3734,3736,3738],{"class":549,"line":3733},73,[547,3735,3097],{"class":659},[547,3737,904],{"class":769},[547,3739,701],{"class":659},[547,3741,3743],{"class":549,"line":3742},74,[547,3744,731],{"emptyLinePlaceholder":730},[547,3746,3748,3750,3752,3754,3756,3758,3761,3763],{"class":549,"line":3747},75,[547,3749,1033],{"class":655},[547,3751,2850],{"class":663},[547,3753,922],{"class":659},[547,3755,2898],{"class":1008},[547,3757,893],{"class":769},[547,3759,3760],{"class":2627},"200",[547,3762,667],{"class":659},[547,3764,754],{"class":659},[547,3766,3768,3771,3773,3775,3777,3779],{"class":549,"line":3767},76,[547,3769,3770],{"class":769},"      userId",[547,3772,773],{"class":659},[547,3774,3012],{"class":663},[547,3776,922],{"class":659},[547,3778,3136],{"class":663},[547,3780,1347],{"class":659},[547,3782,3784,3787,3789,3791,3793,3795],{"class":549,"line":3783},77,[547,3785,3786],{"class":769},"      accessToken",[547,3788,773],{"class":659},[547,3790,3552],{"class":663},[547,3792,922],{"class":659},[547,3794,2370],{"class":663},[547,3796,1347],{"class":659},[547,3798,3800,3802,3804,3806,3808,3811,3813],{"class":549,"line":3799},78,[547,3801,3613],{"class":769},[547,3803,773],{"class":659},[547,3805,3510],{"class":663},[547,3807,922],{"class":659},[547,3809,3810],{"class":1008},"toISOString",[547,3812,1254],{"class":769},[547,3814,1347],{"class":659},[547,3816,3818,3820,3822],{"class":549,"line":3817},79,[547,3819,3097],{"class":659},[547,3821,904],{"class":769},[547,3823,701],{"class":659},[547,3825,3827],{"class":549,"line":3826},80,[547,3828,949],{"class":659},[547,3830,3832],{"class":549,"line":3831},81,[547,3833,731],{"emptyLinePlaceholder":730},[547,3835,3837,3839,3841,3844,3846,3848,3850,3852,3854,3856,3859,3861,3863,3865,3867,3869,3871],{"class":549,"line":3836},82,[547,3838,826],{"class":747},[547,3840,970],{"class":747},[547,3842,3843],{"class":769}," me",[547,3845,893],{"class":659},[547,3847,2801],{"class":896},[547,3849,773],{"class":659},[547,3851,2449],{"class":553},[547,3853,982],{"class":659},[547,3855,698],{"class":659},[547,3857,3858],{"class":556},"\u002Fme",[547,3860,698],{"class":659},[547,3862,2816],{"class":659},[547,3864,979],{"class":553},[547,3866,982],{"class":659},[547,3868,2823],{"class":553},[547,3870,988],{"class":659},[547,3872,754],{"class":659},[547,3874,3876,3878,3881,3883,3885,3887,3889,3892,3894,3896],{"class":549,"line":3875},83,[547,3877,996],{"class":747},[547,3879,3880],{"class":663}," userId",[547,3882,779],{"class":659},[547,3884,3017],{"class":659},[547,3886,2087],{"class":663},[547,3888,922],{"class":659},[547,3890,3891],{"class":1008},"subject",[547,3893,1254],{"class":769},[547,3895,2115],{"class":659},[547,3897,3898],{"class":737}," \u002F\u002F set by JWTAuthMiddleware when a valid token was sent\n",[547,3900,3902],{"class":549,"line":3901},84,[547,3903,731],{"emptyLinePlaceholder":730},[547,3905,3907,3909,3911,3914,3916,3919,3921],{"class":549,"line":3906},85,[547,3908,2874],{"class":655},[547,3910,1666],{"class":769},[547,3912,3913],{"class":663},"userId",[547,3915,1038],{"class":659},[547,3917,3918],{"class":659}," undefined",[547,3920,1186],{"class":769},[547,3922,1539],{"class":659},[547,3924,3926,3928,3930,3932,3934,3936,3938,3940,3942,3944,3946,3948,3951,3953,3955,3957],{"class":549,"line":3925},86,[547,3927,2891],{"class":655},[547,3929,2850],{"class":663},[547,3931,922],{"class":659},[547,3933,2898],{"class":1008},[547,3935,893],{"class":769},[547,3937,2014],{"class":2627},[547,3939,667],{"class":659},[547,3941,660],{"class":659},[547,3943,2910],{"class":769},[547,3945,773],{"class":659},[547,3947,692],{"class":659},[547,3949,3950],{"class":556},"Authentication is required.",[547,3952,698],{"class":659},[547,3954,686],{"class":659},[547,3956,904],{"class":769},[547,3958,701],{"class":659},[547,3960,3962],{"class":549,"line":3961},87,[547,3963,2930],{"class":659},[547,3965,3967],{"class":549,"line":3966},88,[547,3968,731],{"emptyLinePlaceholder":730},[547,3970,3972,3974,3976,3978,3980,3982,3984,3987,3989,3991,3993],{"class":549,"line":3971},89,[547,3973,996],{"class":747},[547,3975,3012],{"class":663},[547,3977,779],{"class":659},[547,3979,3017],{"class":659},[547,3981,2942],{"class":663},[547,3983,922],{"class":659},[547,3985,3986],{"class":1008},"findById",[547,3988,893],{"class":769},[547,3990,3913],{"class":663},[547,3992,904],{"class":769},[547,3994,701],{"class":659},[547,3996,3998],{"class":549,"line":3997},90,[547,3999,731],{"emptyLinePlaceholder":730},[547,4001,4003,4005,4007,4009,4011,4013],{"class":549,"line":4002},91,[547,4004,2874],{"class":655},[547,4006,1666],{"class":769},[547,4008,2879],{"class":659},[547,4010,3343],{"class":663},[547,4012,1186],{"class":769},[547,4014,1539],{"class":659},[547,4016,4018,4020,4022,4024,4026,4028,4030,4032,4034,4036,4038,4040,4043,4045,4047,4049],{"class":549,"line":4017},92,[547,4019,2891],{"class":655},[547,4021,2850],{"class":663},[547,4023,922],{"class":659},[547,4025,2898],{"class":1008},[547,4027,893],{"class":769},[547,4029,2014],{"class":2627},[547,4031,667],{"class":659},[547,4033,660],{"class":659},[547,4035,2910],{"class":769},[547,4037,773],{"class":659},[547,4039,692],{"class":659},[547,4041,4042],{"class":556},"The authenticated account no longer exists.",[547,4044,698],{"class":659},[547,4046,686],{"class":659},[547,4048,904],{"class":769},[547,4050,701],{"class":659},[547,4052,4054],{"class":549,"line":4053},93,[547,4055,2930],{"class":659},[547,4057,4059],{"class":549,"line":4058},94,[547,4060,731],{"emptyLinePlaceholder":730},[547,4062,4064,4066,4068,4070,4072,4074,4076,4078,4080,4082,4085,4087,4089,4091],{"class":549,"line":4063},95,[547,4065,1033],{"class":655},[547,4067,2850],{"class":663},[547,4069,922],{"class":659},[547,4071,2898],{"class":1008},[547,4073,893],{"class":769},[547,4075,3760],{"class":2627},[547,4077,667],{"class":659},[547,4079,1438],{"class":663},[547,4081,922],{"class":659},[547,4083,4084],{"class":1008},"toProfile",[547,4086,893],{"class":769},[547,4088,3343],{"class":663},[547,4090,1270],{"class":769},[547,4092,701],{"class":659},[547,4094,4096],{"class":549,"line":4095},96,[547,4097,949],{"class":659},[547,4099,4101],{"class":549,"line":4100},97,[547,4102,731],{"emptyLinePlaceholder":730},[547,4104,4106,4108,4110,4113,4115,4118,4120,4123,4125,4127,4130,4132],{"class":549,"line":4105},98,[547,4107,760],{"class":747},[547,4109,763],{"class":747},[547,4111,4112],{"class":769}," readCredentials",[547,4114,893],{"class":659},[547,4116,4117],{"class":896},"body",[547,4119,773],{"class":659},[547,4121,4122],{"class":553}," unknown",[547,4124,1116],{"class":659},[547,4126,2522],{"class":553},[547,4128,4129],{"class":659}," |",[547,4131,3918],{"class":553},[547,4133,754],{"class":659},[547,4135,4137,4139,4141,4144,4147,4150,4152,4155,4157,4160,4162,4164,4167,4169,4172],{"class":549,"line":4136},99,[547,4138,2874],{"class":655},[547,4140,1666],{"class":769},[547,4142,4143],{"class":659},"typeof",[547,4145,4146],{"class":663}," body",[547,4148,4149],{"class":659}," !==",[547,4151,692],{"class":659},[547,4153,4154],{"class":556},"object",[547,4156,698],{"class":659},[547,4158,4159],{"class":659}," ||",[547,4161,4146],{"class":663},[547,4163,1038],{"class":659},[547,4165,4166],{"class":659}," null",[547,4168,1186],{"class":769},[547,4170,4171],{"class":655},"return",[547,4173,4174],{"class":659}," undefined;\n",[547,4176,4178,4180,4182,4184,4186,4188,4190,4192,4194,4197,4200,4202,4205,4207,4209],{"class":549,"line":4177},100,[547,4179,996],{"class":747},[547,4181,660],{"class":659},[547,4183,2532],{"class":663},[547,4185,667],{"class":659},[547,4187,2545],{"class":663},[547,4189,686],{"class":659},[547,4191,779],{"class":659},[547,4193,4146],{"class":663},[547,4195,4196],{"class":655}," as",[547,4198,4199],{"class":553}," Record",[547,4201,982],{"class":659},[547,4203,4204],{"class":553},"string",[547,4206,667],{"class":659},[547,4208,4122],{"class":553},[547,4210,4211],{"class":659},">;\n",[547,4213,4215,4217,4219,4221,4223,4225,4227,4229,4231,4233,4236,4238,4240,4243,4245,4247,4250,4252,4254,4256],{"class":549,"line":4214},101,[547,4216,2874],{"class":655},[547,4218,1666],{"class":769},[547,4220,4143],{"class":659},[547,4222,2532],{"class":663},[547,4224,4149],{"class":659},[547,4226,692],{"class":659},[547,4228,4204],{"class":556},[547,4230,698],{"class":659},[547,4232,4159],{"class":659},[547,4234,4235],{"class":659}," !",[547,4237,2956],{"class":663},[547,4239,922],{"class":659},[547,4241,4242],{"class":1008},"includes",[547,4244,893],{"class":769},[547,4246,698],{"class":659},[547,4248,4249],{"class":556},"@",[547,4251,698],{"class":659},[547,4253,2959],{"class":769},[547,4255,4171],{"class":655},[547,4257,4174],{"class":659},[547,4259,4261,4263,4265,4267,4269,4271,4273,4275,4277,4279,4281,4283,4286,4289,4291,4293,4296,4298],{"class":549,"line":4260},102,[547,4262,2874],{"class":655},[547,4264,1666],{"class":769},[547,4266,4143],{"class":659},[547,4268,2545],{"class":663},[547,4270,4149],{"class":659},[547,4272,692],{"class":659},[547,4274,4204],{"class":556},[547,4276,698],{"class":659},[547,4278,4159],{"class":659},[547,4280,2545],{"class":663},[547,4282,922],{"class":659},[547,4284,4285],{"class":663},"length",[547,4287,4288],{"class":659}," \u003C",[547,4290,1438],{"class":663},[547,4292,922],{"class":659},[547,4294,4295],{"class":663},"minimumPasswordLength",[547,4297,1186],{"class":769},[547,4299,1539],{"class":659},[547,4301,4303,4305],{"class":549,"line":4302},103,[547,4304,2891],{"class":655},[547,4306,4174],{"class":659},[547,4308,4310],{"class":549,"line":4309},104,[547,4311,2930],{"class":659},[547,4313,4315,4317,4319,4321,4323,4325],{"class":549,"line":4314},105,[547,4316,1033],{"class":655},[547,4318,660],{"class":659},[547,4320,2532],{"class":663},[547,4322,667],{"class":659},[547,4324,2545],{"class":663},[547,4326,4327],{"class":659}," };\n",[547,4329,4331],{"class":549,"line":4330},106,[547,4332,949],{"class":659},[547,4334,4336],{"class":549,"line":4335},107,[547,4337,731],{"emptyLinePlaceholder":730},[547,4339,4341,4343,4345,4348,4350,4352,4354,4356,4358,4360,4362,4364,4366,4368,4370,4372,4374,4376,4378,4380,4382,4384,4386,4388],{"class":549,"line":4340},108,[547,4342,760],{"class":747},[547,4344,763],{"class":747},[547,4346,4347],{"class":769}," toProfile",[547,4349,893],{"class":659},[547,4351,3343],{"class":896},[547,4353,773],{"class":659},[547,4355,2478],{"class":553},[547,4357,1116],{"class":659},[547,4359,660],{"class":659},[547,4361,3127],{"class":769},[547,4363,773],{"class":659},[547,4365,776],{"class":553},[547,4367,2115],{"class":659},[547,4369,2532],{"class":769},[547,4371,773],{"class":659},[547,4373,776],{"class":553},[547,4375,2115],{"class":659},[547,4377,3589],{"class":769},[547,4379,773],{"class":659},[547,4381,766],{"class":747},[547,4383,776],{"class":553},[547,4385,2685],{"class":663},[547,4387,1189],{"class":659},[547,4389,754],{"class":659},[547,4391,4393,4395,4397,4399,4401,4403,4405,4407,4409,4411,4413,4415,4417,4419,4421,4423,4425,4427,4429,4431],{"class":549,"line":4392},109,[547,4394,1033],{"class":655},[547,4396,660],{"class":659},[547,4398,3127],{"class":769},[547,4400,773],{"class":659},[547,4402,3012],{"class":663},[547,4404,922],{"class":659},[547,4406,3136],{"class":663},[547,4408,667],{"class":659},[547,4410,2532],{"class":769},[547,4412,773],{"class":659},[547,4414,3012],{"class":663},[547,4416,922],{"class":659},[547,4418,2956],{"class":663},[547,4420,667],{"class":659},[547,4422,3589],{"class":769},[547,4424,773],{"class":659},[547,4426,3012],{"class":663},[547,4428,922],{"class":659},[547,4430,3603],{"class":663},[547,4432,4327],{"class":659},[547,4434,4436],{"class":549,"line":4435},110,[547,4437,949],{"class":659},[547,4439,4441],{"class":549,"line":4440},111,[547,4442,1283],{"class":659},[4444,4445,4447,1896,4453,4455,4456,4459,4460,4462],"callout",{"type":4446},"warning",[503,4448,4449,4450,4452],{},"Always run ",[508,4451,2391],{}," on the no-account branch.",[508,4454,2388],{}," does real key-derivation work, so a wrong\npassword takes measurably longer than a lookup that finds nothing — and that gap tells an attacker which\nemails are registered (timing-based enumeration). ",[508,4457,4458],{},"await this.passwordHashing.simulate()"," burns an equivalent\nderivation on the missing-account path, so both failures take the same time and the flat ",[508,4461,2014],{}," reveals nothing.",[4444,4464,4466,1896,4469,4471,4472,4475,4476,4480,4481,4483,4484,4487],{"type":4465},"info",[503,4467,4468],{},"Hashing on the edge.",[508,4470,518],{}," imports ",[508,4473,4474],{},"node:crypto",", so it only runs on a Node-class deploy. For an edge\ndeploy (Cloudflare Workers, Vercel Edge, Deno Deploy), inject ",[503,4477,4478],{},[508,4479,522],{}," instead — PBKDF2-HMAC-SHA256 over\nWebCrypto only (600,000 iterations, the OWASP floor). Both implement the same async ",[508,4482,514],{},"\nport, so only the provider binding changes. To verify both formats from one hasher — e.g. while migrating an\nexisting scrypt store to pbkdf2 — inject ",[508,4485,4486],{},"new PasswordHashing([new Pbkdf2(), new Scrypt()])",": it hashes with\nthe first algorithm and verifies by dispatching on the stored hash's tag, so you re-hash old passwords on the\nnext successful login.",[529,4489,4491],{"id":4490},"read-the-principal-with-authcontext","Read the principal with AuthContext",[499,4493,4494,4495,4497,4498,4500,4501,4504,4505,4508,4509,4511],{},"Once the middleware has verified the token, any handler reads the caller by injecting ",[508,4496,510],{}," — exactly\nwhat ",[508,4499,2374],{}," did above: ",[508,4502,4503],{},"subject()"," returns ",[508,4506,4507],{},"undefined"," for an anonymous request, which the handler turns into a\n",[508,4510,2014],{}," before it ever touches the account store.",[499,4513,4514,4515,773],{},"These are the methods you'll reach for off ",[508,4516,510],{},[4518,4519,4520,4534],"table",{},[4521,4522,4523],"thead",{},[4524,4525,4526,4531],"tr",{},[4527,4528,4530],"th",{"align":4529},"left","Method",[4527,4532,4533],{"align":4529},"Returns",[4535,4536,4537,4554,4571,4581,4591,4603],"tbody",{},[4524,4538,4539,4544],{},[4540,4541,4542],"td",{"align":4529},[508,4543,4503],{},[4540,4545,4546,4547,4550,4551,4553],{"align":4529},"The token ",[508,4548,4549],{},"sub"," claim, or ",[508,4552,4507],{}," when anonymous",[4524,4555,4556,4561],{},[4540,4557,4558],{"align":4529},[508,4559,4560],{},"principal()",[4540,4562,4563,4564,4567,4568,4553],{"align":4529},"The ",[508,4565,4566],{},"AuthPrincipal",", or ",[508,4569,4570],{},"null",[4524,4572,4573,4578],{},[4540,4574,4575],{"align":4529},[508,4576,4577],{},"grantedScopes()",[4540,4579,4580],{"align":4529},"The caller's granted scope codes",[4524,4582,4583,4588],{},[4540,4584,4585],{"align":4529},[508,4586,4587],{},"isAllowed(requiredScopes)",[4540,4589,4590],{"align":4529},"Whether the principal grants every required scope",[4524,4592,4593,4598],{},[4540,4594,4595],{"align":4529},[508,4596,4597],{},"verify(token)",[4540,4599,4600,4601],{"align":4529},"Verify a raw token into an ",[508,4602,4566],{},[4524,4604,4605,4610],{},[4540,4606,4607],{"align":4529},[508,4608,4609],{},"bearerTokenFrom(request)",[4540,4611,4612,4613,4615],{"align":4529},"Delegates to the configured ",[508,4614,1315],{}," (header or cookie)",[529,4617,4619],{"id":4618},"generate-cryptographic-ids","Generate cryptographic ids",[499,4621,4622,4623,4626],{},"For opaque, non-guessable identifiers — session ids, one-time tokens, password-reset codes — reach for\n",[508,4624,4625],{},"RandomId.fromEntropySize",". It draws from the OS CSPRNG and encodes the bytes as lowercase, unpadded,\nURL-safe Base32:",[537,4628,4630],{"className":645,"code":4629,"language":648,"meta":543,"style":543},"import { RandomId } from \"@heximon\u002Fauth\";\n\nconst sessionId = RandomId.fromEntropySize(20); \u002F\u002F 20 bytes of entropy, RFC 4648 Base32\n",[508,4631,4632,4653,4657],{"__ignoreMap":543},[547,4633,4634,4636,4638,4641,4643,4645,4647,4649,4651],{"class":549,"line":550},[547,4635,656],{"class":655},[547,4637,660],{"class":659},[547,4639,4640],{"class":663}," RandomId",[547,4642,686],{"class":659},[547,4644,689],{"class":655},[547,4646,692],{"class":659},[547,4648,695],{"class":556},[547,4650,698],{"class":659},[547,4652,701],{"class":659},[547,4654,4655],{"class":549,"line":704},[547,4656,731],{"emptyLinePlaceholder":730},[547,4658,4659,4662,4665,4667,4669,4671,4674,4676,4679,4681,4683],{"class":549,"line":727},[547,4660,4661],{"class":747},"const",[547,4663,4664],{"class":663}," sessionId ",[547,4666,2688],{"class":659},[547,4668,4640],{"class":663},[547,4670,922],{"class":659},[547,4672,4673],{"class":1008},"fromEntropySize",[547,4675,893],{"class":663},[547,4677,4678],{"class":2627},"20",[547,4680,904],{"class":663},[547,4682,2115],{"class":659},[547,4684,4685],{"class":737}," \u002F\u002F 20 bytes of entropy, RFC 4648 Base32\n",[529,4687,4689],{"id":4688},"publish-a-jwks","Publish a JWKS",[499,4691,4692,4693,4695,4696,4699,4700,1309,4703,4706],{},"When other services verify your tokens, they need your ",[503,4694,637],{}," key — and only that.\n",[508,4697,4698],{},"JwkService.getPublicKeySet()"," returns an RFC 7517 JWK Set of the public keys alone. Private material is\nnever exposed: ",[508,4701,4702],{},"JwkService.load()",[508,4704,4705],{},"JWTVerifier.toPublicJWK()"," strip private members, and each token's\nheader embeds only the public components — the split is structural, not something you have to remember.",[499,4708,4709,4712,4713,4716,4717,4720],{},[508,4710,4711],{},"JwksController"," — already listed alongside ",[508,4714,4715],{},"AuthController"," in the module above — serves it at the\nconventional ",[508,4718,4719],{},"\u002F.well-known\u002Fjwks.json"," path:",[537,4722,4725],{"className":645,"code":4723,"filename":4724,"language":648,"meta":543,"style":543},"import { JwkService } from \"@heximon\u002Fauth\";\nimport type { Controller, Get } from \"@heximon\u002Fhttp\";\nimport { IdentityKeyPair } from \".\u002Fidentity-key-pair\";\n\nexport class JwksController implements Controller\u003C{ prefix: \"\u002F.well-known\" }> {\n  public constructor(private readonly keyPair: IdentityKeyPair) {}\n\n  public async jwks(action: Get\u003C\"\u002Fjwks.json\">): Promise\u003CResponse> {\n    const jwkService = new JwkService();\n\n    jwkService.load(this.keyPair.publicKey);\n\n    return action.respond(200, jwkService.getPublicKeySet());\n  }\n}\n","src\u002Fauth\u002Fjwks.controller.ts",[508,4726,4727,4747,4773,4793,4797,4827,4849,4853,4891,4908,4912,4936,4940,4967,4971],{"__ignoreMap":543},[547,4728,4729,4731,4733,4735,4737,4739,4741,4743,4745],{"class":549,"line":550},[547,4730,656],{"class":655},[547,4732,660],{"class":659},[547,4734,678],{"class":663},[547,4736,686],{"class":659},[547,4738,689],{"class":655},[547,4740,692],{"class":659},[547,4742,695],{"class":556},[547,4744,698],{"class":659},[547,4746,701],{"class":659},[547,4748,4749,4751,4753,4755,4757,4759,4761,4763,4765,4767,4769,4771],{"class":549,"line":704},[547,4750,656],{"class":655},[547,4752,670],{"class":655},[547,4754,660],{"class":659},[547,4756,2444],{"class":663},[547,4758,667],{"class":659},[547,4760,2449],{"class":663},[547,4762,686],{"class":659},[547,4764,689],{"class":655},[547,4766,692],{"class":659},[547,4768,2463],{"class":556},[547,4770,698],{"class":659},[547,4772,701],{"class":659},[547,4774,4775,4777,4779,4781,4783,4785,4787,4789,4791],{"class":549,"line":727},[547,4776,656],{"class":655},[547,4778,660],{"class":659},[547,4780,751],{"class":663},[547,4782,686],{"class":659},[547,4784,689],{"class":655},[547,4786,692],{"class":659},[547,4788,1468],{"class":556},[547,4790,698],{"class":659},[547,4792,701],{"class":659},[547,4794,4795],{"class":549,"line":734},[547,4796,731],{"emptyLinePlaceholder":730},[547,4798,4799,4801,4803,4805,4807,4809,4811,4813,4815,4817,4820,4822,4825],{"class":549,"line":741},[547,4800,744],{"class":655},[547,4802,748],{"class":747},[547,4804,1481],{"class":553},[547,4806,2570],{"class":747},[547,4808,2444],{"class":553},[547,4810,2575],{"class":659},[547,4812,2578],{"class":769},[547,4814,773],{"class":659},[547,4816,692],{"class":659},[547,4818,4819],{"class":556},"\u002F.well-known",[547,4821,698],{"class":659},[547,4823,4824],{"class":659}," }>",[547,4826,754],{"class":659},[547,4828,4829,4831,4833,4835,4837,4839,4841,4843,4845,4847],{"class":549,"line":757},[547,4830,826],{"class":747},[547,4832,890],{"class":747},[547,4834,893],{"class":659},[547,4836,626],{"class":747},[547,4838,766],{"class":747},[547,4840,919],{"class":896},[547,4842,773],{"class":659},[547,4844,751],{"class":553},[547,4846,904],{"class":659},[547,4848,2783],{"class":659},[547,4850,4851],{"class":549,"line":791},[547,4852,731],{"emptyLinePlaceholder":730},[547,4854,4855,4857,4859,4862,4864,4866,4868,4870,4872,4874,4877,4879,4881,4883,4885,4887,4889],{"class":549,"line":818},[547,4856,826],{"class":747},[547,4858,970],{"class":747},[547,4860,4861],{"class":769}," jwks",[547,4863,893],{"class":659},[547,4865,2801],{"class":896},[547,4867,773],{"class":659},[547,4869,2449],{"class":553},[547,4871,982],{"class":659},[547,4873,698],{"class":659},[547,4875,4876],{"class":556},"\u002Fjwks.json",[547,4878,698],{"class":659},[547,4880,2816],{"class":659},[547,4882,979],{"class":553},[547,4884,982],{"class":659},[547,4886,2823],{"class":553},[547,4888,988],{"class":659},[547,4890,754],{"class":659},[547,4892,4893,4895,4898,4900,4902,4904,4906],{"class":549,"line":823},[547,4894,996],{"class":747},[547,4896,4897],{"class":663}," jwkService",[547,4899,779],{"class":659},[547,4901,1157],{"class":659},[547,4903,678],{"class":1008},[547,4905,1254],{"class":769},[547,4907,701],{"class":659},[547,4909,4910],{"class":549,"line":853},[547,4911,731],{"emptyLinePlaceholder":730},[547,4913,4914,4917,4919,4922,4924,4926,4928,4930,4932,4934],{"class":549,"line":880},[547,4915,4916],{"class":663},"    jwkService",[547,4918,922],{"class":659},[547,4920,4921],{"class":1008},"load",[547,4923,893],{"class":769},[547,4925,2939],{"class":659},[547,4927,897],{"class":663},[547,4929,922],{"class":659},[547,4931,871],{"class":663},[547,4933,904],{"class":769},[547,4935,701],{"class":659},[547,4937,4938],{"class":549,"line":885},[547,4939,731],{"emptyLinePlaceholder":730},[547,4941,4942,4944,4946,4948,4950,4952,4954,4956,4958,4960,4963,4965],{"class":549,"line":909},[547,4943,1033],{"class":655},[547,4945,2850],{"class":663},[547,4947,922],{"class":659},[547,4949,2898],{"class":1008},[547,4951,893],{"class":769},[547,4953,3760],{"class":2627},[547,4955,667],{"class":659},[547,4957,4897],{"class":663},[547,4959,922],{"class":659},[547,4961,4962],{"class":1008},"getPublicKeySet",[547,4964,2863],{"class":769},[547,4966,701],{"class":659},[547,4968,4969],{"class":549,"line":929},[547,4970,949],{"class":659},[547,4972,4973],{"class":549,"line":946},[547,4974,1283],{"class":659},[529,4976,4978],{"id":4977},"see-also","See also",[1888,4980,4981,4996,5013],{},[1891,4982,4983,4985,4986,4988,4989,4991,4992,4995],{},[608,4984,102],{"href":103}," — declare per-route ",[508,4987,2187],{}," on a contract and enforce them\nautomatically with ",[508,4990,1988],{},", or check ",[508,4993,4994],{},"AuthContext.isAllowed()"," inline.",[1891,4997,4998,5000,5001,5004,5005,5008,5009,5012],{},[608,4999,57],{"href":58}," — how ",[508,5002,5003],{},"Controller",", the ",[508,5006,5007],{},"middlewares: [...]"," list, and ",[508,5010,5011],{},"HttpAction"," fit\ntogether, including the controller-level middleware that runs before every handler.",[1891,5014,5015,5022,5023,5025],{},[608,5016,5019],{"href":5017,"rel":5018},"https:\u002F\u002Fgithub.com\u002Fheximon\u002Fheximon\u002Ftree\u002Fmain\u002Fexamples\u002Fladder\u002FL07-auth",[612],[503,5020,5021],{},"Example L07 — auth","\n— a runnable register \u002F login \u002F me flow with the ",[508,5024,514],{}," port, a boot-generated ES256\nkey pair, a JWKS endpoint, and a scope-guarded admin route.",[5027,5028,5029],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":543,"searchDepth":704,"depth":704,"links":5031},[5032,5033,5034,5035,5036,5037,5038,5039,5040,5041],{"id":531,"depth":704,"text":532},{"id":617,"depth":704,"text":618},{"id":1303,"depth":704,"text":1304},{"id":1980,"depth":704,"text":1981},{"id":2191,"depth":704,"text":2192},{"id":2334,"depth":704,"text":2335},{"id":4490,"depth":704,"text":4491},{"id":4618,"depth":704,"text":4619},{"id":4688,"depth":704,"text":4689},{"id":4977,"depth":704,"text":4978},"Verify callers with JWT, hash passwords through the PasswordHashingAlgorithm port, read the request-scoped AuthContext, and list JWTAuthMiddleware directly in your app.","md",null,{},{"icon":100},{"title":97,"description":5042},"6biq-X6b7gL6wcF1OdUF6Kp1JigBlI6aMlyPVBArtb0",[5050,5052],{"title":92,"path":93,"stem":94,"description":5051,"icon":95,"children":-1},"Generate Drizzle migrations with stock drizzle-kit, then apply them with the injectable MigrationRunner, MigrationConfig, and a Task — one unified config drives both the CLI and the runtime.",{"title":102,"path":103,"stem":104,"description":5053,"icon":65,"children":-1},"Declare per-route scopes with Route.scopes, enforce them with GuardMiddleware, and run manual checks through AuthContext.isAllowed on inline routes.",1783300761903]