[{"data":1,"prerenderedAt":7419},["ShallowReactive",2],{"navigation_docs":3,"-docs-products-sites-authentication":984},[4,8,44,50,86,583,625,918],{"title":5,"path":6,"stem":7},"Home","\u002Fdocs","docs\u002Findex",{"title":9,"path":10,"stem":11,"children":12},"API usage","\u002Fdocs\u002Fapi-usage","docs\u002Fapi-usage\u002Findex",[13,14,20,26,32,38],{"title":9,"path":10,"stem":11},{"title":15,"path":16,"stem":17,"children":18},"Errors","\u002Fdocs\u002Fapi-usage\u002Ferrors","docs\u002Fapi-usage\u002Ferrors\u002Findex",[19],{"title":15,"path":16,"stem":17},{"title":21,"path":22,"stem":23,"children":24},"Retries & idempotency","\u002Fdocs\u002Fapi-usage\u002Fidempotency","docs\u002Fapi-usage\u002Fidempotency\u002Findex",[25],{"title":21,"path":22,"stem":23},{"title":27,"path":28,"stem":29,"children":30},"Pagination & filtering","\u002Fdocs\u002Fapi-usage\u002Fpagination","docs\u002Fapi-usage\u002Fpagination\u002Findex",[31],{"title":27,"path":28,"stem":29},{"title":33,"path":34,"stem":35,"children":36},"Rate limits","\u002Fdocs\u002Fapi-usage\u002Frate-limits","docs\u002Fapi-usage\u002Frate-limits\u002Findex",[37],{"title":33,"path":34,"stem":35},{"title":39,"path":40,"stem":41,"children":42},"Versioning & stability","\u002Fdocs\u002Fapi-usage\u002Fversioning","docs\u002Fapi-usage\u002Fversioning\u002Findex",[43],{"title":39,"path":40,"stem":41},{"title":45,"path":46,"stem":47,"children":48},"What's new","\u002Fdocs\u002Fchangelog","docs\u002Fchangelog\u002Findex",[49],{"title":45,"path":46,"stem":47},{"title":51,"path":52,"stem":53,"children":54},"Getting Started","\u002Fdocs\u002Fgetting-started","docs\u002Fgetting-started\u002Findex",[55,56,62,68,74,80],{"title":51,"path":52,"stem":53},{"title":57,"path":58,"stem":59,"children":60},"Architecture Overview","\u002Fdocs\u002Fgetting-started\u002Farchitecture","docs\u002Fgetting-started\u002Farchitecture\u002Findex",[61],{"title":57,"path":58,"stem":59},{"title":63,"path":64,"stem":65,"children":66},"Glossary","\u002Fdocs\u002Fgetting-started\u002Fglossary","docs\u002Fgetting-started\u002Fglossary\u002Findex",[67],{"title":63,"path":64,"stem":65},{"title":69,"path":70,"stem":71,"children":72},"Platform Overview","\u002Fdocs\u002Fgetting-started\u002Fplatform-overview","docs\u002Fgetting-started\u002Fplatform-overview\u002Findex",[73],{"title":69,"path":70,"stem":71},{"title":75,"path":76,"stem":77,"children":78},"Prerequisites","\u002Fdocs\u002Fgetting-started\u002Fprerequisites","docs\u002Fgetting-started\u002Fprerequisites\u002Findex",[79],{"title":75,"path":76,"stem":77},{"title":81,"path":82,"stem":83,"children":84},"Your First App in 15 Minutes","\u002Fdocs\u002Fgetting-started\u002Fquick-start","docs\u002Fgetting-started\u002Fquick-start\u002Findex",[85],{"title":81,"path":82,"stem":83},{"title":87,"path":88,"stem":89,"children":90},"Products","\u002Fdocs\u002Fproducts","docs\u002Fproducts\u002Findex",[91,92,98,170,200,218,254,320,517,565],{"title":87,"path":88,"stem":89},{"title":93,"path":94,"stem":95,"children":96},"AI Studio","\u002Fdocs\u002Fproducts\u002Fai","docs\u002Fproducts\u002Fai\u002Findex",[97],{"title":93,"path":94,"stem":95},{"title":99,"path":100,"stem":101,"children":102},"App Studio","\u002Fdocs\u002Fproducts\u002Fapps","docs\u002Fproducts\u002Fapps\u002Findex",[103,104,110,116,122,128,134,140,146,152,158,164],{"title":99,"path":100,"stem":101},{"title":105,"path":106,"stem":107,"children":108},"App Model","\u002Fdocs\u002Fproducts\u002Fapps\u002Fapp-model","docs\u002Fproducts\u002Fapps\u002Fapp-model\u002Findex",[109],{"title":105,"path":106,"stem":107},{"title":111,"path":112,"stem":113,"children":114},"Auto-generated data APIs","\u002Fdocs\u002Fproducts\u002Fapps\u002Fauto-generated-data-apis","docs\u002Fproducts\u002Fapps\u002Fauto-generated-data-apis\u002Findex",[115],{"title":111,"path":112,"stem":113},{"title":117,"path":118,"stem":119,"children":120},"Billing & Events","\u002Fdocs\u002Fproducts\u002Fapps\u002Fbilling-events","docs\u002Fproducts\u002Fapps\u002Fbilling-events\u002Findex",[121],{"title":117,"path":118,"stem":119},{"title":123,"path":124,"stem":125,"children":126},"Cockpit Integration","\u002Fdocs\u002Fproducts\u002Fapps\u002Fcockpit-integration","docs\u002Fproducts\u002Fapps\u002Fcockpit-integration\u002Findex",[127],{"title":123,"path":124,"stem":125},{"title":129,"path":130,"stem":131,"children":132},"App Model Concept","\u002Fdocs\u002Fproducts\u002Fapps\u002Fconcept","docs\u002Fproducts\u002Fapps\u002Fconcept\u002Findex",[133],{"title":129,"path":130,"stem":131},{"title":135,"path":136,"stem":137,"children":138},"App Lifecycle","\u002Fdocs\u002Fproducts\u002Fapps\u002Flifecycle","docs\u002Fproducts\u002Fapps\u002Flifecycle\u002Findex",[139],{"title":135,"path":136,"stem":137},{"title":141,"path":142,"stem":143,"children":144},"Manifest Reference","\u002Fdocs\u002Fproducts\u002Fapps\u002Fmanifest-reference","docs\u002Fproducts\u002Fapps\u002Fmanifest-reference\u002Findex",[145],{"title":141,"path":142,"stem":143},{"title":147,"path":148,"stem":149,"children":150},"Market Concept","\u002Fdocs\u002Fproducts\u002Fapps\u002Fmarket-concept","docs\u002Fproducts\u002Fapps\u002Fmarket-concept\u002Findex",[151],{"title":147,"path":148,"stem":149},{"title":153,"path":154,"stem":155,"children":156},"Policies","\u002Fdocs\u002Fproducts\u002Fapps\u002Fpolicies","docs\u002Fproducts\u002Fapps\u002Fpolicies\u002Findex",[157],{"title":153,"path":154,"stem":155},{"title":159,"path":160,"stem":161,"children":162},"Schema migrations","\u002Fdocs\u002Fproducts\u002Fapps\u002Fschema-migrator","docs\u002Fproducts\u002Fapps\u002Fschema-migrator\u002Findex",[163],{"title":159,"path":160,"stem":161},{"title":165,"path":166,"stem":167,"children":168},"Schema Reference","\u002Fdocs\u002Fproducts\u002Fapps\u002Fschema-reference","docs\u002Fproducts\u002Fapps\u002Fschema-reference\u002Findex",[169],{"title":165,"path":166,"stem":167},{"title":171,"path":172,"stem":173,"children":174},"Authentication","\u002Fdocs\u002Fproducts\u002Fauth","docs\u002Fproducts\u002Fauth\u002Findex",[175,176,182,188,194],{"title":171,"path":172,"stem":173},{"title":177,"path":178,"stem":179,"children":180},"API keys","\u002Fdocs\u002Fproducts\u002Fauth\u002Fapi-keys","docs\u002Fproducts\u002Fauth\u002Fapi-keys\u002Findex",[181],{"title":177,"path":178,"stem":179},{"title":183,"path":184,"stem":185,"children":186},"Multi-factor authentication","\u002Fdocs\u002Fproducts\u002Fauth\u002Fmfa","docs\u002Fproducts\u002Fauth\u002Fmfa\u002Findex",[187],{"title":183,"path":184,"stem":185},{"title":189,"path":190,"stem":191,"children":192},"Social sign-in","\u002Fdocs\u002Fproducts\u002Fauth\u002Foauth2","docs\u002Fproducts\u002Fauth\u002Foauth2\u002Findex",[193],{"title":189,"path":190,"stem":191},{"title":195,"path":196,"stem":197,"children":198},"Sessions","\u002Fdocs\u002Fproducts\u002Fauth\u002Fsessions","docs\u002Fproducts\u002Fauth\u002Fsessions\u002Findex",[199],{"title":195,"path":196,"stem":197},{"title":201,"path":202,"stem":203,"children":204},"Events","\u002Fdocs\u002Fproducts\u002Fevents","docs\u002Fproducts\u002Fevents\u002Findex",[205,206,212],{"title":201,"path":202,"stem":203},{"title":207,"path":208,"stem":209,"children":210},"Consuming events","\u002Fdocs\u002Fproducts\u002Fevents\u002Fconsuming-events","docs\u002Fproducts\u002Fevents\u002Fconsuming-events\u002Findex",[211],{"title":207,"path":208,"stem":209},{"title":213,"path":214,"stem":215,"children":216},"Event types","\u002Fdocs\u002Fproducts\u002Fevents\u002Fevent-types","docs\u002Fproducts\u002Fevents\u002Fevent-types\u002Findex",[217],{"title":213,"path":214,"stem":215},{"title":219,"path":220,"stem":221,"children":222},"Integration Studio","\u002Fdocs\u002Fproducts\u002Fintegration-studio","docs\u002Fproducts\u002Fintegration-studio\u002Findex",[223,224,230,236,242,248],{"title":219,"path":220,"stem":221},{"title":225,"path":226,"stem":227,"children":228},"Expression Syntax","\u002Fdocs\u002Fproducts\u002Fintegration-studio\u002Fexpression-syntax","docs\u002Fproducts\u002Fintegration-studio\u002Fexpression-syntax\u002Findex",[229],{"title":225,"path":226,"stem":227},{"title":231,"path":232,"stem":233,"children":234},"Node Types","\u002Fdocs\u002Fproducts\u002Fintegration-studio\u002Fnode-types","docs\u002Fproducts\u002Fintegration-studio\u002Fnode-types\u002Findex",[235],{"title":231,"path":232,"stem":233},{"title":237,"path":238,"stem":239,"children":240},"Dual-engine architecture","\u002Fdocs\u002Fproducts\u002Fintegration-studio\u002Foverview","docs\u002Fproducts\u002Fintegration-studio\u002Foverview\u002Findex",[241],{"title":237,"path":238,"stem":239},{"title":243,"path":244,"stem":245,"children":246},"Triggers","\u002Fdocs\u002Fproducts\u002Fintegration-studio\u002Ftriggers","docs\u002Fproducts\u002Fintegration-studio\u002Ftriggers\u002Findex",[247],{"title":243,"path":244,"stem":245},{"title":249,"path":250,"stem":251,"children":252},"Workflow Builder","\u002Fdocs\u002Fproducts\u002Fintegration-studio\u002Fworkflow-builder","docs\u002Fproducts\u002Fintegration-studio\u002Fworkflow-builder\u002Findex",[253],{"title":249,"path":250,"stem":251},{"title":255,"path":256,"stem":257,"children":258},"Network","\u002Fdocs\u002Fproducts\u002Fnetwork","docs\u002Fproducts\u002Fnetwork\u002Findex",[259,260,266,272,278,284,290,296,302,308,314],{"title":255,"path":256,"stem":257},{"title":261,"path":262,"stem":263,"children":264},"Caching","\u002Fdocs\u002Fproducts\u002Fnetwork\u002Fcaching","docs\u002Fproducts\u002Fnetwork\u002Fcaching\u002Findex",[265],{"title":261,"path":262,"stem":263},{"title":267,"path":268,"stem":269,"children":270},"Content delivery (CDN)","\u002Fdocs\u002Fproducts\u002Fnetwork\u002Fcdn","docs\u002Fproducts\u002Fnetwork\u002Fcdn\u002Findex",[271],{"title":267,"path":268,"stem":269},{"title":273,"path":274,"stem":275,"children":276},"Compression","\u002Fdocs\u002Fproducts\u002Fnetwork\u002Fcompression","docs\u002Fproducts\u002Fnetwork\u002Fcompression\u002Findex",[277],{"title":273,"path":274,"stem":275},{"title":279,"path":280,"stem":281,"children":282},"DDoS mitigation","\u002Fdocs\u002Fproducts\u002Fnetwork\u002Fddos","docs\u002Fproducts\u002Fnetwork\u002Fddos\u002Findex",[283],{"title":279,"path":280,"stem":281},{"title":285,"path":286,"stem":287,"children":288},"revenexx DNS service","\u002Fdocs\u002Fproducts\u002Fnetwork\u002Fdns","docs\u002Fproducts\u002Fnetwork\u002Fdns\u002Findex",[289],{"title":285,"path":286,"stem":287},{"title":291,"path":292,"stem":293,"children":294},"Edges","\u002Fdocs\u002Fproducts\u002Fnetwork\u002Fedges","docs\u002Fproducts\u002Fnetwork\u002Fedges\u002Findex",[295],{"title":291,"path":292,"stem":293},{"title":297,"path":298,"stem":299,"children":300},"Endpoints","\u002Fdocs\u002Fproducts\u002Fnetwork\u002Fendpoints","docs\u002Fproducts\u002Fnetwork\u002Fendpoints\u002Findex",[301],{"title":297,"path":298,"stem":299},{"title":303,"path":304,"stem":305,"children":306},"Regions","\u002Fdocs\u002Fproducts\u002Fnetwork\u002Fregions","docs\u002Fproducts\u002Fnetwork\u002Fregions\u002Findex",[307],{"title":303,"path":304,"stem":305},{"title":309,"path":310,"stem":311,"children":312},"Transport Layer Security (TLS)","\u002Fdocs\u002Fproducts\u002Fnetwork\u002Ftls","docs\u002Fproducts\u002Fnetwork\u002Ftls\u002Findex",[313],{"title":309,"path":310,"stem":311},{"title":315,"path":316,"stem":317,"children":318},"Web application firewall (WAF)","\u002Fdocs\u002Fproducts\u002Fnetwork\u002Fwaf","docs\u002Fproducts\u002Fnetwork\u002Fwaf\u002Findex",[319],{"title":315,"path":316,"stem":317},{"title":321,"path":322,"stem":323,"children":324},"Experience Studio","\u002Fdocs\u002Fproducts\u002Fsites","docs\u002Fproducts\u002Fsites\u002Findex",[325,326,332,337,343,349,355,361,367,373,379,385,391,397,403,409,487,505,511],{"title":321,"path":322,"stem":323},{"title":327,"path":328,"stem":329,"children":330},"Storefront Architecture","\u002Fdocs\u002Fproducts\u002Fsites\u002Farchitecture","docs\u002Fproducts\u002Fsites\u002Farchitecture\u002Findex",[331],{"title":327,"path":328,"stem":329},{"title":171,"path":333,"stem":334,"children":335},"\u002Fdocs\u002Fproducts\u002Fsites\u002Fauthentication","docs\u002Fproducts\u002Fsites\u002Fauthentication\u002Findex",[336],{"title":171,"path":333,"stem":334},{"title":338,"path":339,"stem":340,"children":341},"Blökkli Blocks","\u002Fdocs\u002Fproducts\u002Fsites\u002Fblokki-blocks","docs\u002Fproducts\u002Fsites\u002Fblokki-blocks\u002Findex",[342],{"title":338,"path":339,"stem":340},{"title":344,"path":345,"stem":346,"children":347},"Checkout","\u002Fdocs\u002Fproducts\u002Fsites\u002Fcheckout","docs\u002Fproducts\u002Fsites\u002Fcheckout\u002Findex",[348],{"title":344,"path":345,"stem":346},{"title":350,"path":351,"stem":352,"children":353},"Deploy from CLI","\u002Fdocs\u002Fproducts\u002Fsites\u002Fdeploy-from-cli","docs\u002Fproducts\u002Fsites\u002Fdeploy-from-cli\u002Findex",[354],{"title":350,"path":351,"stem":352},{"title":356,"path":357,"stem":358,"children":359},"Deploy from Git","\u002Fdocs\u002Fproducts\u002Fsites\u002Fdeploy-from-git","docs\u002Fproducts\u002Fsites\u002Fdeploy-from-git\u002Findex",[360],{"title":356,"path":357,"stem":358},{"title":362,"path":363,"stem":364,"children":365},"Deploy manually","\u002Fdocs\u002Fproducts\u002Fsites\u002Fdeploy-manually","docs\u002Fproducts\u002Fsites\u002Fdeploy-manually\u002Findex",[366],{"title":362,"path":363,"stem":364},{"title":368,"path":369,"stem":370,"children":371},"Deployments","\u002Fdocs\u002Fproducts\u002Fsites\u002Fdeployments","docs\u002Fproducts\u002Fsites\u002Fdeployments\u002Findex",[372],{"title":368,"path":369,"stem":370},{"title":374,"path":375,"stem":376,"children":377},"Develop revenexx Storefronts","\u002Fdocs\u002Fproducts\u002Fsites\u002Fdevelop","docs\u002Fproducts\u002Fsites\u002Fdevelop\u002Findex",[378],{"title":374,"path":375,"stem":376},{"title":380,"path":381,"stem":382,"children":383},"Domains","\u002Fdocs\u002Fproducts\u002Fsites\u002Fdomains","docs\u002Fproducts\u002Fsites\u002Fdomains\u002Findex",[384],{"title":380,"path":381,"stem":382},{"title":386,"path":387,"stem":388,"children":389},"Frameworks","\u002Fdocs\u002Fproducts\u002Fsites\u002Fframeworks","docs\u002Fproducts\u002Fsites\u002Fframeworks\u002Findex",[390],{"title":386,"path":387,"stem":388},{"title":392,"path":393,"stem":394,"children":395},"Instant rollbacks","\u002Fdocs\u002Fproducts\u002Fsites\u002Finstant-rollbacks","docs\u002Fproducts\u002Fsites\u002Finstant-rollbacks\u002Findex",[396],{"title":392,"path":393,"stem":394},{"title":398,"path":399,"stem":400,"children":401},"Logs","\u002Fdocs\u002Fproducts\u002Fsites\u002Flogs","docs\u002Fproducts\u002Fsites\u002Flogs\u002Findex",[402],{"title":398,"path":399,"stem":400},{"title":404,"path":405,"stem":406,"children":407},"Previews","\u002Fdocs\u002Fproducts\u002Fsites\u002Fpreviews","docs\u002Fproducts\u002Fsites\u002Fpreviews\u002Findex",[408],{"title":404,"path":405,"stem":406},{"title":410,"path":411,"stem":412,"children":413},"Start with Sites","\u002Fdocs\u002Fproducts\u002Fsites\u002Fquick-start","docs\u002Fproducts\u002Fsites\u002Fquick-start\u002Findex",[414,415,421,427,433,439,445,451,457,463,469,475,481],{"title":410,"path":411,"stem":412},{"title":416,"path":417,"stem":418,"children":419},"Deploy an Angular app to revenexx Storefronts","\u002Fdocs\u002Fproducts\u002Fsites\u002Fquick-start\u002Fangular","docs\u002Fproducts\u002Fsites\u002Fquick-start\u002Fangular\u002Findex",[420],{"title":416,"path":417,"stem":418},{"title":422,"path":423,"stem":424,"children":425},"Deploy a Astro app to revenexx Storefronts","\u002Fdocs\u002Fproducts\u002Fsites\u002Fquick-start\u002Fastro","docs\u002Fproducts\u002Fsites\u002Fquick-start\u002Fastro\u002Findex",[426],{"title":422,"path":423,"stem":424},{"title":428,"path":429,"stem":430,"children":431},"Deploy a Flutter Web app to revenexx Storefronts","\u002Fdocs\u002Fproducts\u002Fsites\u002Fquick-start\u002Fflutter","docs\u002Fproducts\u002Fsites\u002Fquick-start\u002Fflutter\u002Findex",[432],{"title":428,"path":429,"stem":430},{"title":434,"path":435,"stem":436,"children":437},"Deploy a Next.js app to revenexx Storefronts","\u002Fdocs\u002Fproducts\u002Fsites\u002Fquick-start\u002Fnextjs","docs\u002Fproducts\u002Fsites\u002Fquick-start\u002Fnextjs\u002Findex",[438],{"title":434,"path":435,"stem":436},{"title":440,"path":441,"stem":442,"children":443},"Deploy a Nuxt app to revenexx Storefronts","\u002Fdocs\u002Fproducts\u002Fsites\u002Fquick-start\u002Fnuxt","docs\u002Fproducts\u002Fsites\u002Fquick-start\u002Fnuxt\u002Findex",[444],{"title":440,"path":441,"stem":442},{"title":446,"path":447,"stem":448,"children":449},"Deploy a React Native app to revenexx Storefronts","\u002Fdocs\u002Fproducts\u002Fsites\u002Fquick-start\u002Freact-native","docs\u002Fproducts\u002Fsites\u002Fquick-start\u002Freact-native\u002Findex",[450],{"title":446,"path":447,"stem":448},{"title":452,"path":453,"stem":454,"children":455},"Deploy a React app to revenexx Storefronts","\u002Fdocs\u002Fproducts\u002Fsites\u002Fquick-start\u002Freact","docs\u002Fproducts\u002Fsites\u002Fquick-start\u002Freact\u002Findex",[456],{"title":452,"path":453,"stem":454},{"title":458,"path":459,"stem":460,"children":461},"Deploy a Remix app to revenexx Storefronts","\u002Fdocs\u002Fproducts\u002Fsites\u002Fquick-start\u002Fremix","docs\u002Fproducts\u002Fsites\u002Fquick-start\u002Fremix\u002Findex",[462],{"title":458,"path":459,"stem":460},{"title":464,"path":465,"stem":466,"children":467},"Deploy a SvelteKit app to revenexx Storefronts","\u002Fdocs\u002Fproducts\u002Fsites\u002Fquick-start\u002Fsveltekit","docs\u002Fproducts\u002Fsites\u002Fquick-start\u002Fsveltekit\u002Findex",[468],{"title":464,"path":465,"stem":466},{"title":470,"path":471,"stem":472,"children":473},"Deploy a TanStack Start app to revenexx Storefronts","\u002Fdocs\u002Fproducts\u002Fsites\u002Fquick-start\u002Ftanstack-start","docs\u002Fproducts\u002Fsites\u002Fquick-start\u002Ftanstack-start\u002Findex",[474],{"title":470,"path":471,"stem":472},{"title":476,"path":477,"stem":478,"children":479},"Deploy a Vanilla JS app to revenexx Storefronts","\u002Fdocs\u002Fproducts\u002Fsites\u002Fquick-start\u002Fvanilla","docs\u002Fproducts\u002Fsites\u002Fquick-start\u002Fvanilla\u002Findex",[480],{"title":476,"path":477,"stem":478},{"title":482,"path":483,"stem":484,"children":485},"Deploy a Vue.js app to revenexx Storefronts","\u002Fdocs\u002Fproducts\u002Fsites\u002Fquick-start\u002Fvue","docs\u002Fproducts\u002Fsites\u002Fquick-start\u002Fvue\u002Findex",[486],{"title":482,"path":483,"stem":484},{"title":488,"path":489,"stem":490,"children":491},"Rendering","\u002Fdocs\u002Fproducts\u002Fsites\u002Frendering","docs\u002Fproducts\u002Fsites\u002Frendering\u002Findex",[492,493,499],{"title":488,"path":489,"stem":490},{"title":494,"path":495,"stem":496,"children":497},"Server Side Rendering","\u002Fdocs\u002Fproducts\u002Fsites\u002Frendering\u002Fssr","docs\u002Fproducts\u002Fsites\u002Frendering\u002Fssr\u002Findex",[498],{"title":494,"path":495,"stem":496},{"title":500,"path":501,"stem":502,"children":503},"Static","\u002Fdocs\u002Fproducts\u002Fsites\u002Frendering\u002Fstatic","docs\u002Fproducts\u002Fsites\u002Frendering\u002Fstatic\u002Findex",[504],{"title":500,"path":501,"stem":502},{"title":506,"path":507,"stem":508,"children":509},"Templates","\u002Fdocs\u002Fproducts\u002Fsites\u002Ftemplates","docs\u002Fproducts\u002Fsites\u002Ftemplates\u002Findex",[510],{"title":506,"path":507,"stem":508},{"title":512,"path":513,"stem":514,"children":515},"Theming","\u002Fdocs\u002Fproducts\u002Fsites\u002Ftheming","docs\u002Fproducts\u002Fsites\u002Ftheming\u002Findex",[516],{"title":512,"path":513,"stem":514},{"title":518,"path":519,"stem":520,"children":521},"Storage","\u002Fdocs\u002Fproducts\u002Fstorage","docs\u002Fproducts\u002Fstorage\u002Findex",[522,523,529,535,541,547,553,559],{"title":518,"path":519,"stem":520},{"title":524,"path":525,"stem":526,"children":527},"Folders","\u002Fdocs\u002Fproducts\u002Fstorage\u002Fbuckets","docs\u002Fproducts\u002Fstorage\u002Fbuckets\u002Findex",[528],{"title":524,"path":525,"stem":526},{"title":530,"path":531,"stem":532,"children":533},"Signed URLs and access","\u002Fdocs\u002Fproducts\u002Fstorage\u002Ffile-tokens","docs\u002Fproducts\u002Fstorage\u002Ffile-tokens\u002Findex",[534],{"title":530,"path":531,"stem":532},{"title":536,"path":537,"stem":538,"children":539},"Serve and transform images","\u002Fdocs\u002Fproducts\u002Fstorage\u002Fimages","docs\u002Fproducts\u002Fstorage\u002Fimages\u002Findex",[540],{"title":536,"path":537,"stem":538},{"title":542,"path":543,"stem":544,"children":545},"3D assets","\u002Fdocs\u002Fproducts\u002Fstorage\u002Fmodel-viewer","docs\u002Fproducts\u002Fstorage\u002Fmodel-viewer\u002Findex",[546],{"title":542,"path":543,"stem":544},{"title":548,"path":549,"stem":550,"children":551},"Access control and visibility","\u002Fdocs\u002Fproducts\u002Fstorage\u002Fpermissions","docs\u002Fproducts\u002Fstorage\u002Fpermissions\u002Findex",[552],{"title":548,"path":549,"stem":550},{"title":554,"path":555,"stem":556,"children":557},"Quick start","\u002Fdocs\u002Fproducts\u002Fstorage\u002Fquick-start","docs\u002Fproducts\u002Fstorage\u002Fquick-start\u002Findex",[558],{"title":554,"path":555,"stem":556},{"title":560,"path":561,"stem":562,"children":563},"Upload and manage files","\u002Fdocs\u002Fproducts\u002Fstorage\u002Fupload-download","docs\u002Fproducts\u002Fstorage\u002Fupload-download\u002Findex",[564],{"title":560,"path":561,"stem":562},{"title":566,"path":567,"stem":568,"children":569},"Webhooks","\u002Fdocs\u002Fproducts\u002Fwebhooks","docs\u002Fproducts\u002Fwebhooks\u002Findex",[570,571,577],{"title":566,"path":567,"stem":568},{"title":572,"path":573,"stem":574,"children":575},"Delivery","\u002Fdocs\u002Fproducts\u002Fwebhooks\u002Fdelivery","docs\u002Fproducts\u002Fwebhooks\u002Fdelivery\u002Findex",[576],{"title":572,"path":573,"stem":574},{"title":578,"path":579,"stem":580,"children":581},"Security","\u002Fdocs\u002Fproducts\u002Fwebhooks\u002Fsecurity","docs\u002Fproducts\u002Fwebhooks\u002Fsecurity\u002Findex",[582],{"title":578,"path":579,"stem":580},{"title":584,"path":585,"stem":586,"children":587},"SDKs","\u002Fdocs\u002Fsdks","docs\u002Fsdks\u002Findex",[588,589,595,601,607,613,619],{"title":584,"path":585,"stem":586},{"title":590,"path":591,"stem":592,"children":593},"App SDK","\u002Fdocs\u002Fsdks\u002Fapp-sdk","docs\u002Fsdks\u002Fapp-sdk\u002Findex",[594],{"title":590,"path":591,"stem":592},{"title":596,"path":597,"stem":598,"children":599},"CLI","\u002Fdocs\u002Fsdks\u002Fcli","docs\u002Fsdks\u002Fcli\u002Findex",[600],{"title":596,"path":597,"stem":598},{"title":602,"path":603,"stem":604,"children":605},"Integration Node SDK","\u002Fdocs\u002Fsdks\u002Fintegration-nodes","docs\u002Fsdks\u002Fintegration-nodes\u002Findex",[606],{"title":602,"path":603,"stem":604},{"title":608,"path":609,"stem":610,"children":611},"Node SDK","\u002Fdocs\u002Fsdks\u002Fnode","docs\u002Fsdks\u002Fnode\u002Findex",[612],{"title":608,"path":609,"stem":610},{"title":614,"path":615,"stem":616,"children":617},"PHP SDK","\u002Fdocs\u002Fsdks\u002Fphp","docs\u002Fsdks\u002Fphp\u002Findex",[618],{"title":614,"path":615,"stem":616},{"title":620,"path":621,"stem":622,"children":623},"Web \u002F JavaScript SDK","\u002Fdocs\u002Fsdks\u002Fweb","docs\u002Fsdks\u002Fweb\u002Findex",[624],{"title":620,"path":621,"stem":622},{"title":626,"path":627,"stem":628,"children":629},"Tooling","\u002Fdocs\u002Ftooling","docs\u002Ftooling\u002Findex",[630,631,637,864],{"title":626,"path":627,"stem":628},{"title":632,"path":633,"stem":634,"children":635},"Command Center","\u002Fdocs\u002Ftooling\u002Fcommand-center","docs\u002Ftooling\u002Fcommand-center\u002Findex",[636],{"title":632,"path":633,"stem":634},{"title":638,"path":639,"stem":640,"children":641},"Command line","\u002Fdocs\u002Ftooling\u002Fcommand-line","docs\u002Ftooling\u002Fcommand-line\u002Findex",[642,643,649,654,660,666,672,678,684,828,834,840,846,852,858],{"title":638,"path":639,"stem":640},{"title":644,"path":645,"stem":646,"children":647},"Aliases","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Faliases","docs\u002Ftooling\u002Fcommand-line\u002Faliases\u002Findex",[648],{"title":644,"path":645,"stem":646},{"title":171,"path":650,"stem":651,"children":652},"\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Fauthentication","docs\u002Ftooling\u002Fcommand-line\u002Fauthentication\u002Findex",[653],{"title":171,"path":650,"stem":651},{"title":655,"path":656,"stem":657,"children":658},"Commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Fcommands","docs\u002Ftooling\u002Fcommand-line\u002Fcommands\u002Findex",[659],{"title":655,"path":656,"stem":657},{"title":661,"path":662,"stem":663,"children":664},"Installation","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Finstallation","docs\u002Ftooling\u002Fcommand-line\u002Finstallation\u002Findex",[665],{"title":661,"path":662,"stem":663},{"title":667,"path":668,"stem":669,"children":670},"Interactive use","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Finteractive","docs\u002Ftooling\u002Fcommand-line\u002Finteractive\u002Findex",[671],{"title":667,"path":668,"stem":669},{"title":673,"path":674,"stem":675,"children":676},"Non-interactive use","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Fnon-interactive","docs\u002Ftooling\u002Fcommand-line\u002Fnon-interactive\u002Findex",[677],{"title":673,"path":674,"stem":675},{"title":679,"path":680,"stem":681,"children":682},"Project configuration","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Fproject-configuration","docs\u002Ftooling\u002Fcommand-line\u002Fproject-configuration\u002Findex",[683],{"title":679,"path":680,"stem":681},{"title":685,"path":686,"stem":687,"children":688},"Command reference","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Findex",[689,690,696,702,708,714,720,726,732,738,744,750,756,762,768,774,780,786,792,798,804,810,816,822],{"title":685,"path":686,"stem":687},{"title":691,"path":692,"stem":693,"children":694},"About commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fabout","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fabout\u002Findex",[695],{"title":691,"path":692,"stem":693},{"title":697,"path":698,"stem":699,"children":700},"Apps commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fapps","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fapps\u002Findex",[701],{"title":697,"path":698,"stem":699},{"title":703,"path":704,"stem":705,"children":706},"Carts commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fcarts","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fcarts\u002Findex",[707],{"title":703,"path":704,"stem":705},{"title":709,"path":710,"stem":711,"children":712},"Channels commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fchannels","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fchannels\u002Findex",[713],{"title":709,"path":710,"stem":711},{"title":715,"path":716,"stem":717,"children":718},"Create commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fcreate","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fcreate\u002Findex",[719],{"title":715,"path":716,"stem":717},{"title":721,"path":722,"stem":723,"children":724},"Customers commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fcustomers","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fcustomers\u002Findex",[725],{"title":721,"path":722,"stem":723},{"title":727,"path":728,"stem":729,"children":730},"Deploy commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fdeploy","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fdeploy\u002Findex",[731],{"title":727,"path":728,"stem":729},{"title":733,"path":734,"stem":735,"children":736},"Forms commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fforms","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fforms\u002Findex",[737],{"title":733,"path":734,"stem":735},{"title":739,"path":740,"stem":741,"children":742},"Inventories commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Finventories","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Finventories\u002Findex",[743],{"title":739,"path":740,"stem":741},{"title":745,"path":746,"stem":747,"children":748},"Markets commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fmarkets","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fmarkets\u002Findex",[749],{"title":745,"path":746,"stem":747},{"title":751,"path":752,"stem":753,"children":754},"Order lists commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Forderlists","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Forderlists\u002Findex",[755],{"title":751,"path":752,"stem":753},{"title":757,"path":758,"stem":759,"children":760},"Orders commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Forders","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Forders\u002Findex",[761],{"title":757,"path":758,"stem":759},{"title":763,"path":764,"stem":765,"children":766},"Pages commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fpages","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fpages\u002Findex",[767],{"title":763,"path":764,"stem":765},{"title":769,"path":770,"stem":771,"children":772},"Payments commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fpayments","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fpayments\u002Findex",[773],{"title":769,"path":770,"stem":771},{"title":775,"path":776,"stem":777,"children":778},"Prices commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fprices","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fprices\u002Findex",[779],{"title":775,"path":776,"stem":777},{"title":781,"path":782,"stem":783,"children":784},"Products commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fproducts","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fproducts\u002Findex",[785],{"title":781,"path":782,"stem":783},{"title":787,"path":788,"stem":789,"children":790},"Search commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fsearch","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fsearch\u002Findex",[791],{"title":787,"path":788,"stem":789},{"title":793,"path":794,"stem":795,"children":796},"Settings commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fsettings","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fsettings\u002Findex",[797],{"title":793,"path":794,"stem":795},{"title":799,"path":800,"stem":801,"children":802},"Shipping commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fshipping","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fshipping\u002Findex",[803],{"title":799,"path":800,"stem":801},{"title":805,"path":806,"stem":807,"children":808},"Sites commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fsites","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fsites\u002Findex",[809],{"title":805,"path":806,"stem":807},{"title":811,"path":812,"stem":813,"children":814},"Skills commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fskills","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fskills\u002Findex",[815],{"title":811,"path":812,"stem":813},{"title":817,"path":818,"stem":819,"children":820},"Storage commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fstorage","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Fstorage\u002Findex",[821],{"title":817,"path":818,"stem":819},{"title":823,"path":824,"stem":825,"children":826},"Tokens commands","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Freference\u002Ftokens","docs\u002Ftooling\u002Fcommand-line\u002Freference\u002Ftokens\u002Findex",[827],{"title":823,"path":824,"stem":825},{"title":829,"path":830,"stem":831,"children":832},"Interactive shell (REPL)","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Frepl","docs\u002Ftooling\u002Fcommand-line\u002Frepl\u002Findex",[833],{"title":829,"path":830,"stem":831},{"title":835,"path":836,"stem":837,"children":838},"Scaffolding","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Fscaffolding","docs\u002Ftooling\u002Fcommand-line\u002Fscaffolding\u002Findex",[839],{"title":835,"path":836,"stem":837},{"title":841,"path":842,"stem":843,"children":844},"Scripting & output","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Fscripting","docs\u002Ftooling\u002Fcommand-line\u002Fscripting\u002Findex",[845],{"title":841,"path":842,"stem":843},{"title":847,"path":848,"stem":849,"children":850},"Skills","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Fskills","docs\u002Ftooling\u002Fcommand-line\u002Fskills\u002Findex",[851],{"title":847,"path":848,"stem":849},{"title":853,"path":854,"stem":855,"children":856},"Full-screen app (TUI)","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Ftui","docs\u002Ftooling\u002Fcommand-line\u002Ftui\u002Findex",[857],{"title":853,"path":854,"stem":855},{"title":859,"path":860,"stem":861,"children":862},"Type generation","\u002Fdocs\u002Ftooling\u002Fcommand-line\u002Ftype-generation","docs\u002Ftooling\u002Fcommand-line\u002Ftype-generation\u002Findex",[863],{"title":859,"path":860,"stem":861},{"title":865,"path":866,"stem":867,"children":868},"Model Context Protocol","\u002Fdocs\u002Ftooling\u002Fmcp","docs\u002Ftooling\u002Fmcp\u002Findex",[869,870,876,882,888,894,900,906,912],{"title":865,"path":866,"stem":867},{"title":871,"path":872,"stem":873,"children":874},"revenexx docs MCP in Google Antigravity","\u002Fdocs\u002Ftooling\u002Fmcp\u002Fantigravity","docs\u002Ftooling\u002Fmcp\u002Fantigravity\u002Findex",[875],{"title":871,"path":872,"stem":873},{"title":877,"path":878,"stem":879,"children":880},"revenexx docs MCP in Claude Code","\u002Fdocs\u002Ftooling\u002Fmcp\u002Fclaude-code","docs\u002Ftooling\u002Fmcp\u002Fclaude-code\u002Findex",[881],{"title":877,"path":878,"stem":879},{"title":883,"path":884,"stem":885,"children":886},"revenexx docs MCP in Claude Desktop","\u002Fdocs\u002Ftooling\u002Fmcp\u002Fclaude-desktop","docs\u002Ftooling\u002Fmcp\u002Fclaude-desktop\u002Findex",[887],{"title":883,"path":884,"stem":885},{"title":889,"path":890,"stem":891,"children":892},"revenexx docs MCP in Cursor","\u002Fdocs\u002Ftooling\u002Fmcp\u002Fcursor","docs\u002Ftooling\u002Fmcp\u002Fcursor\u002Findex",[893],{"title":889,"path":890,"stem":891},{"title":895,"path":896,"stem":897,"children":898},"revenexx docs MCP in OpenCode","\u002Fdocs\u002Ftooling\u002Fmcp\u002Fopencode","docs\u002Ftooling\u002Fmcp\u002Fopencode\u002Findex",[899],{"title":895,"path":896,"stem":897},{"title":901,"path":902,"stem":903,"children":904},"revenexx docs MCP in VS Code","\u002Fdocs\u002Ftooling\u002Fmcp\u002Fvscode","docs\u002Ftooling\u002Fmcp\u002Fvscode\u002Findex",[905],{"title":901,"path":902,"stem":903},{"title":907,"path":908,"stem":909,"children":910},"revenexx docs MCP in Windsurf","\u002Fdocs\u002Ftooling\u002Fmcp\u002Fwindsurf","docs\u002Ftooling\u002Fmcp\u002Fwindsurf\u002Findex",[911],{"title":907,"path":908,"stem":909},{"title":913,"path":914,"stem":915,"children":916},"revenexx docs MCP in Zenflow","\u002Fdocs\u002Ftooling\u002Fmcp\u002Fzenflow","docs\u002Ftooling\u002Fmcp\u002Fzenflow\u002Findex",[917],{"title":913,"path":914,"stem":915},{"title":919,"path":920,"stem":921,"children":922},"Tutorials","\u002Fdocs\u002Ftutorials","docs\u002Ftutorials\u002Findex",[923,924,948,954],{"title":919,"path":920,"stem":921},{"title":925,"path":926,"stem":927,"children":928},"Build a revenexx App","\u002Fdocs\u002Ftutorials\u002Fapps","docs\u002Ftutorials\u002Fapps\u002Findex",[929,930,936,942],{"title":925,"path":926,"stem":927},{"title":931,"path":932,"stem":933,"children":934},"Add a data model","\u002Fdocs\u002Ftutorials\u002Fapps\u002Fadd-a-data-model","docs\u002Ftutorials\u002Fapps\u002Fadd-a-data-model\u002Findex",[935],{"title":931,"path":932,"stem":933},{"title":937,"path":938,"stem":939,"children":940},"Build your first app","\u002Fdocs\u002Ftutorials\u002Fapps\u002Fbuild-your-first-app","docs\u002Ftutorials\u002Fapps\u002Fbuild-your-first-app\u002Findex",[941],{"title":937,"path":938,"stem":939},{"title":943,"path":944,"stem":945,"children":946},"Deploy with the CLI","\u002Fdocs\u002Ftutorials\u002Fapps\u002Fdeploy-with-the-cli","docs\u002Ftutorials\u002Fapps\u002Fdeploy-with-the-cli\u002Findex",[947],{"title":943,"path":944,"stem":945},{"title":949,"path":950,"stem":951,"children":952},"Examples","\u002Fdocs\u002Ftutorials\u002Fexamples","docs\u002Ftutorials\u002Fexamples\u002Findex",[953],{"title":949,"path":950,"stem":951},{"title":955,"path":956,"stem":957,"children":958},"Build a storefront Theme","\u002Fdocs\u002Ftutorials\u002Fthemes","docs\u002Ftutorials\u002Fthemes\u002Findex",[959,960,966,972,978],{"title":955,"path":956,"stem":957},{"title":961,"path":962,"stem":963,"children":964},"Build your first Theme","\u002Fdocs\u002Ftutorials\u002Fthemes\u002Fbuild-your-first-theme","docs\u002Ftutorials\u002Fthemes\u002Fbuild-your-first-theme\u002Findex",[965],{"title":961,"path":962,"stem":963},{"title":967,"path":968,"stem":969,"children":970},"Customize blocks","\u002Fdocs\u002Ftutorials\u002Fthemes\u002Fcustomize-blocks","docs\u002Ftutorials\u002Fthemes\u002Fcustomize-blocks\u002Findex",[971],{"title":967,"path":968,"stem":969},{"title":973,"path":974,"stem":975,"children":976},"Deploy your storefront","\u002Fdocs\u002Ftutorials\u002Fthemes\u002Fdeploy-your-storefront","docs\u002Ftutorials\u002Fthemes\u002Fdeploy-your-storefront\u002Findex",[977],{"title":973,"path":974,"stem":975},{"title":979,"path":980,"stem":981,"children":982},"Theme tokens and styling","\u002Fdocs\u002Ftutorials\u002Fthemes\u002Ftheme-tokens-and-styling","docs\u002Ftutorials\u002Fthemes\u002Ftheme-tokens-and-styling\u002Findex",[983],{"title":979,"path":980,"stem":981},{"id":985,"title":171,"body":986,"description":7411,"extension":7412,"landing":7413,"links":7413,"meta":7414,"navigation":1396,"path":333,"seo":7416,"sitemap":7417,"stem":334,"__hash__":7418},"docs\u002Fdocs\u002Fproducts\u002Fsites\u002Fauthentication\u002Findex.md",{"type":987,"value":988,"toc":7387},"minimark",[989,998,1018,1029,1032,1037,1047,1051,1054,1059,1062,1827,1831,1834,1841,2546,2550,2557,2583,2590,2605,2615,2800,2804,2807,2811,2814,3829,3833,3839,3845,4474,4478,4485,4489,4492,4947,4951,4957,5435,5439,5444,6040,6044,6050,6411,6415,6422,6427,6647,6651,6662,6758,6761,6849,6853,6856,6883,6898,6901,6906,7137,7141,7146,7222,7227,7350,7354,7383],[990,991,992,993,997],"p",{},"This page is for ",[994,995,996],"strong",{},"frontend developers"," wiring up authentication in a storefront. It covers buyer-side identity — login, registration, password recovery for the people placing orders.",[999,1000,1001,1004,1005,1008,1009,1012,1013,1017],"note",{},[994,1002,1003],{},"Two different identity systems",", easy to mix up: buyers in storefronts authenticate through ",[994,1006,1007],{},"Customers",", the platform's buyer identity reached via the gateway. Admin users in Cockpit sign in through ",[994,1010,1011],{},"ID"," (",[1014,1015,1016],"code",{},"id.revenexx.com","), the platform's SSO. This page is about buyers only. If you're integrating Cockpit \u002F Console \u002F SSO, that's a different topic and not covered here.",[990,1019,1020,1021,1024,1025,1028],{},"You don't roll your own password hashing or JWT signing — the platform SDK handles that. Your job is the UI (forms, validation, error states) and the BFF endpoints that call the SDK. The code examples below show the pattern; the actual primitives (",[1014,1022,1023],{},"bcrypt",", ",[1014,1026,1027],{},"jwt.sign",", the raw token store) live inside the SDK, not in your storefront code.",[990,1030,1031],{},"The flows on this page — login, registration, forgot\u002Freset password — are what the default template provides. Every B2B project ends up extending at least one of them: tying registration to a customer-approval workflow, adding SAML for enterprise customers, supporting magic-link login, or restricting login to invited users only.",[1033,1034,1036],"h2",{"id":1035},"authentication-architecture","Authentication Architecture",[1038,1039,1044],"pre",{"className":1040,"code":1042,"language":1043},[1041],"language-text","┌──────────────────┐\n│  Storefront      │\n│  (Login UI)      │\n└────────┬─────────┘\n         │\n    HTTP\u002FHTTPS\n         │\n┌────────▼────────────────┐\n│  Auth Server (Cockpit)  │\n│  - Validate credentials │\n│  - Issue JWT tokens     │\n│  - Tenant isolation     │\n└────────┬────────────────┘\n         │\n┌────────▼────────────────┐\n│  Platform data          │\n│  - Users                │\n│  - Tenant scoped        │\n└─────────────────────────┘\n","text",[1014,1045,1042],{"__ignoreMap":1046},"",[1033,1048,1050],{"id":1049},"login-flow","Login Flow",[990,1052,1053],{},"Login has three parts, and it's worth seeing them as a chain: the browser collects credentials, a BFF endpoint verifies them and mints a token, and that token then rides along on every subsequent request to prove who the user is. The code below walks each part in turn; the thing to watch is that the password only ever exists on the server side of that chain.",[1055,1056,1058],"h3",{"id":1057},"_1-user-enters-credentials","1. User Enters Credentials",[990,1060,1061],{},"The form is deliberately ordinary — an email field, a password field, and links out to the forgot-password and registration flows. Its only real job is to collect the two values and POST them to the BFF, while showing a loading state and surfacing an error if the call fails:",[1038,1063,1067],{"className":1064,"code":1065,"language":1066,"meta":1046,"style":1046},"language-vue shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003Ctemplate>\n  \u003Cform @submit=\"handleLogin\">\n    \u003Cinput \n      v-model=\"email\" \n      type=\"email\" \n      placeholder=\"your@email.com\" \n      required\n    \u002F>\n    \u003Cinput \n      v-model=\"password\" \n      type=\"password\" \n      placeholder=\"Password\" \n      required\n    \u002F>\n    \u003Cbutton type=\"submit\" :disabled=\"loading\">Sign In\u003C\u002Fbutton>\n    \u003Ca href=\"\u002Fforgot-password\">Forgot password?\u003C\u002Fa>\n    \u003Cp>Don't have an account? \u003Ca href=\"\u002Fregister\">Sign up\u003C\u002Fa>\u003C\u002Fp>\n  \u003C\u002Fform>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nconst email = ref('')\nconst password = ref('')\nconst loading = ref(false)\nconst error = ref('')\n\nconst handleLogin = async () => {\n  loading.value = true\n  error.value = ''\n  \n  try {\n    const { token, user } = await $fetch('\u002Fapi\u002Fauth\u002Flogin', {\n      method: 'POST',\n      body: { email, password }\n    })\n    \n    \u002F\u002F Store token\n    sessionStorage.setItem('auth_token', token)\n    \n    \u002F\u002F Redirect to account page\n    navigateTo('\u002Faccount')\n  } catch (err) {\n    error.value = err.data.message || 'Invalid email or password'\n  } finally {\n    loading.value = false\n  }\n}\n\u003C\u002Fscript>\n","vue",[1014,1068,1069,1085,1112,1124,1141,1157,1174,1180,1186,1195,1211,1226,1242,1247,1252,1298,1329,1372,1382,1391,1398,1411,1435,1453,1473,1491,1496,1518,1536,1551,1557,1566,1609,1629,1650,1658,1664,1671,1697,1702,1708,1725,1745,1781,1791,1806,1812,1818],{"__ignoreMap":1046},[1070,1071,1074,1078,1082],"span",{"class":1072,"line":1073},"line",1,[1070,1075,1077],{"class":1076},"sMK4o","\u003C",[1070,1079,1081],{"class":1080},"swJcz","template",[1070,1083,1084],{"class":1076},">\n",[1070,1086,1088,1091,1094,1098,1101,1104,1108,1110],{"class":1072,"line":1087},2,[1070,1089,1090],{"class":1076},"  \u003C",[1070,1092,1093],{"class":1080},"form",[1070,1095,1097],{"class":1096},"spNyl"," @submit",[1070,1099,1100],{"class":1076},"=",[1070,1102,1103],{"class":1076},"\"",[1070,1105,1107],{"class":1106},"sfazB","handleLogin",[1070,1109,1103],{"class":1076},[1070,1111,1084],{"class":1076},[1070,1113,1115,1118,1121],{"class":1072,"line":1114},3,[1070,1116,1117],{"class":1076},"    \u003C",[1070,1119,1120],{"class":1080},"input",[1070,1122,1123],{"class":1076}," \n",[1070,1125,1127,1130,1132,1134,1137,1139],{"class":1072,"line":1126},4,[1070,1128,1129],{"class":1096},"      v-model",[1070,1131,1100],{"class":1076},[1070,1133,1103],{"class":1076},[1070,1135,1136],{"class":1106},"email",[1070,1138,1103],{"class":1076},[1070,1140,1123],{"class":1076},[1070,1142,1144,1147,1149,1151,1153,1155],{"class":1072,"line":1143},5,[1070,1145,1146],{"class":1096},"      type",[1070,1148,1100],{"class":1076},[1070,1150,1103],{"class":1076},[1070,1152,1136],{"class":1106},[1070,1154,1103],{"class":1076},[1070,1156,1123],{"class":1076},[1070,1158,1160,1163,1165,1167,1170,1172],{"class":1072,"line":1159},6,[1070,1161,1162],{"class":1096},"      placeholder",[1070,1164,1100],{"class":1076},[1070,1166,1103],{"class":1076},[1070,1168,1169],{"class":1106},"your@email.com",[1070,1171,1103],{"class":1076},[1070,1173,1123],{"class":1076},[1070,1175,1177],{"class":1072,"line":1176},7,[1070,1178,1179],{"class":1096},"      required\n",[1070,1181,1183],{"class":1072,"line":1182},8,[1070,1184,1185],{"class":1076},"    \u002F>\n",[1070,1187,1189,1191,1193],{"class":1072,"line":1188},9,[1070,1190,1117],{"class":1076},[1070,1192,1120],{"class":1080},[1070,1194,1123],{"class":1076},[1070,1196,1198,1200,1202,1204,1207,1209],{"class":1072,"line":1197},10,[1070,1199,1129],{"class":1096},[1070,1201,1100],{"class":1076},[1070,1203,1103],{"class":1076},[1070,1205,1206],{"class":1106},"password",[1070,1208,1103],{"class":1076},[1070,1210,1123],{"class":1076},[1070,1212,1214,1216,1218,1220,1222,1224],{"class":1072,"line":1213},11,[1070,1215,1146],{"class":1096},[1070,1217,1100],{"class":1076},[1070,1219,1103],{"class":1076},[1070,1221,1206],{"class":1106},[1070,1223,1103],{"class":1076},[1070,1225,1123],{"class":1076},[1070,1227,1229,1231,1233,1235,1238,1240],{"class":1072,"line":1228},12,[1070,1230,1162],{"class":1096},[1070,1232,1100],{"class":1076},[1070,1234,1103],{"class":1076},[1070,1236,1237],{"class":1106},"Password",[1070,1239,1103],{"class":1076},[1070,1241,1123],{"class":1076},[1070,1243,1245],{"class":1072,"line":1244},13,[1070,1246,1179],{"class":1096},[1070,1248,1250],{"class":1072,"line":1249},14,[1070,1251,1185],{"class":1076},[1070,1253,1255,1257,1260,1263,1265,1267,1270,1272,1275,1277,1279,1282,1284,1287,1291,1294,1296],{"class":1072,"line":1254},15,[1070,1256,1117],{"class":1076},[1070,1258,1259],{"class":1080},"button",[1070,1261,1262],{"class":1096}," type",[1070,1264,1100],{"class":1076},[1070,1266,1103],{"class":1076},[1070,1268,1269],{"class":1106},"submit",[1070,1271,1103],{"class":1076},[1070,1273,1274],{"class":1096}," :disabled",[1070,1276,1100],{"class":1076},[1070,1278,1103],{"class":1076},[1070,1280,1281],{"class":1106},"loading",[1070,1283,1103],{"class":1076},[1070,1285,1286],{"class":1076},">",[1070,1288,1290],{"class":1289},"sTEyZ","Sign In",[1070,1292,1293],{"class":1076},"\u003C\u002F",[1070,1295,1259],{"class":1080},[1070,1297,1084],{"class":1076},[1070,1299,1301,1303,1306,1309,1311,1313,1316,1318,1320,1323,1325,1327],{"class":1072,"line":1300},16,[1070,1302,1117],{"class":1076},[1070,1304,1305],{"class":1080},"a",[1070,1307,1308],{"class":1096}," href",[1070,1310,1100],{"class":1076},[1070,1312,1103],{"class":1076},[1070,1314,1315],{"class":1106},"\u002Fforgot-password",[1070,1317,1103],{"class":1076},[1070,1319,1286],{"class":1076},[1070,1321,1322],{"class":1289},"Forgot password?",[1070,1324,1293],{"class":1076},[1070,1326,1305],{"class":1080},[1070,1328,1084],{"class":1076},[1070,1330,1332,1334,1336,1338,1341,1343,1345,1347,1349,1351,1354,1356,1358,1361,1363,1365,1368,1370],{"class":1072,"line":1331},17,[1070,1333,1117],{"class":1076},[1070,1335,990],{"class":1080},[1070,1337,1286],{"class":1076},[1070,1339,1340],{"class":1289},"Don't have an account? ",[1070,1342,1077],{"class":1076},[1070,1344,1305],{"class":1080},[1070,1346,1308],{"class":1096},[1070,1348,1100],{"class":1076},[1070,1350,1103],{"class":1076},[1070,1352,1353],{"class":1106},"\u002Fregister",[1070,1355,1103],{"class":1076},[1070,1357,1286],{"class":1076},[1070,1359,1360],{"class":1289},"Sign up",[1070,1362,1293],{"class":1076},[1070,1364,1305],{"class":1080},[1070,1366,1367],{"class":1076},">\u003C\u002F",[1070,1369,990],{"class":1080},[1070,1371,1084],{"class":1076},[1070,1373,1375,1378,1380],{"class":1072,"line":1374},18,[1070,1376,1377],{"class":1076},"  \u003C\u002F",[1070,1379,1093],{"class":1080},[1070,1381,1084],{"class":1076},[1070,1383,1385,1387,1389],{"class":1072,"line":1384},19,[1070,1386,1293],{"class":1076},[1070,1388,1081],{"class":1080},[1070,1390,1084],{"class":1076},[1070,1392,1394],{"class":1072,"line":1393},20,[1070,1395,1397],{"emptyLinePlaceholder":1396},true,"\n",[1070,1399,1401,1403,1406,1409],{"class":1072,"line":1400},21,[1070,1402,1077],{"class":1076},[1070,1404,1405],{"class":1080},"script",[1070,1407,1408],{"class":1096}," setup",[1070,1410,1084],{"class":1076},[1070,1412,1414,1417,1420,1422,1426,1429,1432],{"class":1072,"line":1413},22,[1070,1415,1416],{"class":1096},"const",[1070,1418,1419],{"class":1289}," email ",[1070,1421,1100],{"class":1076},[1070,1423,1425],{"class":1424},"s2Zo4"," ref",[1070,1427,1428],{"class":1289},"(",[1070,1430,1431],{"class":1076},"''",[1070,1433,1434],{"class":1289},")\n",[1070,1436,1438,1440,1443,1445,1447,1449,1451],{"class":1072,"line":1437},23,[1070,1439,1416],{"class":1096},[1070,1441,1442],{"class":1289}," password ",[1070,1444,1100],{"class":1076},[1070,1446,1425],{"class":1424},[1070,1448,1428],{"class":1289},[1070,1450,1431],{"class":1076},[1070,1452,1434],{"class":1289},[1070,1454,1456,1458,1461,1463,1465,1467,1471],{"class":1072,"line":1455},24,[1070,1457,1416],{"class":1096},[1070,1459,1460],{"class":1289}," loading ",[1070,1462,1100],{"class":1076},[1070,1464,1425],{"class":1424},[1070,1466,1428],{"class":1289},[1070,1468,1470],{"class":1469},"sfNiH","false",[1070,1472,1434],{"class":1289},[1070,1474,1476,1478,1481,1483,1485,1487,1489],{"class":1072,"line":1475},25,[1070,1477,1416],{"class":1096},[1070,1479,1480],{"class":1289}," error ",[1070,1482,1100],{"class":1076},[1070,1484,1425],{"class":1424},[1070,1486,1428],{"class":1289},[1070,1488,1431],{"class":1076},[1070,1490,1434],{"class":1289},[1070,1492,1494],{"class":1072,"line":1493},26,[1070,1495,1397],{"emptyLinePlaceholder":1396},[1070,1497,1499,1501,1504,1506,1509,1512,1515],{"class":1072,"line":1498},27,[1070,1500,1416],{"class":1096},[1070,1502,1503],{"class":1289}," handleLogin ",[1070,1505,1100],{"class":1076},[1070,1507,1508],{"class":1096}," async",[1070,1510,1511],{"class":1076}," ()",[1070,1513,1514],{"class":1096}," =>",[1070,1516,1517],{"class":1076}," {\n",[1070,1519,1521,1524,1527,1530,1533],{"class":1072,"line":1520},28,[1070,1522,1523],{"class":1289},"  loading",[1070,1525,1526],{"class":1076},".",[1070,1528,1529],{"class":1289},"value",[1070,1531,1532],{"class":1076}," =",[1070,1534,1535],{"class":1469}," true\n",[1070,1537,1539,1542,1544,1546,1548],{"class":1072,"line":1538},29,[1070,1540,1541],{"class":1289},"  error",[1070,1543,1526],{"class":1076},[1070,1545,1529],{"class":1289},[1070,1547,1532],{"class":1076},[1070,1549,1550],{"class":1076}," ''\n",[1070,1552,1554],{"class":1072,"line":1553},30,[1070,1555,1556],{"class":1080},"  \n",[1070,1558,1560,1564],{"class":1072,"line":1559},31,[1070,1561,1563],{"class":1562},"s7zQu","  try",[1070,1565,1517],{"class":1076},[1070,1567,1569,1572,1575,1578,1581,1584,1587,1589,1592,1595,1597,1600,1603,1605,1607],{"class":1072,"line":1568},32,[1070,1570,1571],{"class":1096},"    const",[1070,1573,1574],{"class":1076}," {",[1070,1576,1577],{"class":1289}," token",[1070,1579,1580],{"class":1076},",",[1070,1582,1583],{"class":1289}," user",[1070,1585,1586],{"class":1076}," }",[1070,1588,1532],{"class":1076},[1070,1590,1591],{"class":1562}," await",[1070,1593,1594],{"class":1424}," $fetch",[1070,1596,1428],{"class":1080},[1070,1598,1599],{"class":1076},"'",[1070,1601,1602],{"class":1106},"\u002Fapi\u002Fauth\u002Flogin",[1070,1604,1599],{"class":1076},[1070,1606,1580],{"class":1076},[1070,1608,1517],{"class":1076},[1070,1610,1612,1615,1618,1621,1624,1626],{"class":1072,"line":1611},33,[1070,1613,1614],{"class":1080},"      method",[1070,1616,1617],{"class":1076},":",[1070,1619,1620],{"class":1076}," '",[1070,1622,1623],{"class":1106},"POST",[1070,1625,1599],{"class":1076},[1070,1627,1628],{"class":1076},",\n",[1070,1630,1632,1635,1637,1639,1642,1644,1647],{"class":1072,"line":1631},34,[1070,1633,1634],{"class":1080},"      body",[1070,1636,1617],{"class":1076},[1070,1638,1574],{"class":1076},[1070,1640,1641],{"class":1289}," email",[1070,1643,1580],{"class":1076},[1070,1645,1646],{"class":1289}," password",[1070,1648,1649],{"class":1076}," }\n",[1070,1651,1653,1656],{"class":1072,"line":1652},35,[1070,1654,1655],{"class":1076},"    }",[1070,1657,1434],{"class":1080},[1070,1659,1661],{"class":1072,"line":1660},36,[1070,1662,1663],{"class":1080},"    \n",[1070,1665,1667],{"class":1072,"line":1666},37,[1070,1668,1670],{"class":1669},"sHwdD","    \u002F\u002F Store token\n",[1070,1672,1674,1677,1679,1682,1684,1686,1689,1691,1693,1695],{"class":1072,"line":1673},38,[1070,1675,1676],{"class":1289},"    sessionStorage",[1070,1678,1526],{"class":1076},[1070,1680,1681],{"class":1424},"setItem",[1070,1683,1428],{"class":1080},[1070,1685,1599],{"class":1076},[1070,1687,1688],{"class":1106},"auth_token",[1070,1690,1599],{"class":1076},[1070,1692,1580],{"class":1076},[1070,1694,1577],{"class":1289},[1070,1696,1434],{"class":1080},[1070,1698,1700],{"class":1072,"line":1699},39,[1070,1701,1663],{"class":1080},[1070,1703,1705],{"class":1072,"line":1704},40,[1070,1706,1707],{"class":1669},"    \u002F\u002F Redirect to account page\n",[1070,1709,1711,1714,1716,1718,1721,1723],{"class":1072,"line":1710},41,[1070,1712,1713],{"class":1424},"    navigateTo",[1070,1715,1428],{"class":1080},[1070,1717,1599],{"class":1076},[1070,1719,1720],{"class":1106},"\u002Faccount",[1070,1722,1599],{"class":1076},[1070,1724,1434],{"class":1080},[1070,1726,1728,1731,1734,1736,1739,1742],{"class":1072,"line":1727},42,[1070,1729,1730],{"class":1076},"  }",[1070,1732,1733],{"class":1562}," catch",[1070,1735,1012],{"class":1080},[1070,1737,1738],{"class":1289},"err",[1070,1740,1741],{"class":1080},") ",[1070,1743,1744],{"class":1076},"{\n",[1070,1746,1748,1751,1753,1755,1757,1760,1762,1765,1767,1770,1773,1775,1778],{"class":1072,"line":1747},43,[1070,1749,1750],{"class":1289},"    error",[1070,1752,1526],{"class":1076},[1070,1754,1529],{"class":1289},[1070,1756,1532],{"class":1076},[1070,1758,1759],{"class":1289}," err",[1070,1761,1526],{"class":1076},[1070,1763,1764],{"class":1289},"data",[1070,1766,1526],{"class":1076},[1070,1768,1769],{"class":1289},"message",[1070,1771,1772],{"class":1076}," ||",[1070,1774,1620],{"class":1076},[1070,1776,1777],{"class":1106},"Invalid email or password",[1070,1779,1780],{"class":1076},"'\n",[1070,1782,1784,1786,1789],{"class":1072,"line":1783},44,[1070,1785,1730],{"class":1076},[1070,1787,1788],{"class":1562}," finally",[1070,1790,1517],{"class":1076},[1070,1792,1794,1797,1799,1801,1803],{"class":1072,"line":1793},45,[1070,1795,1796],{"class":1289},"    loading",[1070,1798,1526],{"class":1076},[1070,1800,1529],{"class":1289},[1070,1802,1532],{"class":1076},[1070,1804,1805],{"class":1469}," false\n",[1070,1807,1809],{"class":1072,"line":1808},46,[1070,1810,1811],{"class":1076},"  }\n",[1070,1813,1815],{"class":1072,"line":1814},47,[1070,1816,1817],{"class":1076},"}\n",[1070,1819,1821,1823,1825],{"class":1072,"line":1820},48,[1070,1822,1293],{"class":1076},[1070,1824,1405],{"class":1080},[1070,1826,1084],{"class":1076},[1055,1828,1830],{"id":1829},"_2-server-side-authentication","2. Server-Side Authentication",[990,1832,1833],{},"This is where the actual verification happens, and where the security-sensitive work stays. The route looks the user up (automatically scoped to the tenant, so a login can only match a user in the current tenant), compares the submitted password against the stored hash, checks the account is active, and only then signs a JWT carrying the user's identity and tenant. Note the deliberately vague \"invalid email or password\" message in both failure branches — it avoids telling an attacker whether an email exists.",[990,1835,1836],{},[994,1837,1838,1839],{},"Backend Route: ",[1014,1840,1602],{},[1038,1842,1846],{"className":1843,"code":1844,"language":1845,"meta":1046,"style":1046},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","export default defineEventHandler(async (event) => {\n  const { email, password } = await readBody(event)\n  \n  \u002F\u002F Fetch user from Cockpit (automatically scoped to the tenant)\n  const user = await cockpit.users.findByEmail(email)\n  if (!user) {\n    throw createError({\n      statusCode: 401,\n      message: 'Invalid email or password'\n    })\n  }\n  \n  \u002F\u002F Verify password\n  const passwordValid = await bcrypt.compare(password, user.password_hash)\n  if (!passwordValid) {\n    throw createError({\n      statusCode: 401,\n      message: 'Invalid email or password'\n    })\n  }\n  \n  \u002F\u002F Check if account is active\n  if (user.status !== 'active') {\n    throw createError({\n      statusCode: 403,\n      message: 'Account is inactive. Contact support.'\n    })\n  }\n  \n  \u002F\u002F Generate JWT token\n  const token = jwt.sign(\n    {\n      user_id: user.id,\n      tenant_id: user.tenant_id,\n      email: user.email,\n      role: user.role\n    },\n    process.env.JWT_SECRET,\n    { expiresIn: '7d' }\n  )\n  \n  \u002F\u002F Set secure httpOnly cookie (optional, for session)\n  setCookie(event, 'auth_token', token, {\n    httpOnly: true,\n    secure: true,\n    sameSite: 'strict',\n    maxAge: 7 * 24 * 60 * 60 \u002F\u002F 7 days\n  })\n  \n  return {\n    token,\n    user: {\n      id: user.id,\n      email: user.email,\n      name: user.name,\n      role: user.role\n    }\n  }\n})\n","typescript",[1014,1847,1848,1877,1905,1909,1914,1943,1960,1972,1985,1998,2004,2008,2012,2017,2051,2066,2076,2086,2098,2104,2108,2112,2117,2144,2154,2165,2178,2184,2188,2192,2197,2216,2221,2237,2253,2268,2282,2287,2304,2323,2328,2332,2337,2362,2374,2385,2401,2429,2435,2440,2448,2456,2466,2482,2497,2514,2527,2533,2538],{"__ignoreMap":1046},[1070,1849,1850,1853,1856,1859,1861,1864,1866,1870,1873,1875],{"class":1072,"line":1073},[1070,1851,1852],{"class":1562},"export",[1070,1854,1855],{"class":1562}," default",[1070,1857,1858],{"class":1424}," defineEventHandler",[1070,1860,1428],{"class":1289},[1070,1862,1863],{"class":1096},"async",[1070,1865,1012],{"class":1076},[1070,1867,1869],{"class":1868},"sHdIc","event",[1070,1871,1872],{"class":1076},")",[1070,1874,1514],{"class":1096},[1070,1876,1517],{"class":1076},[1070,1878,1879,1882,1884,1886,1888,1890,1892,1894,1896,1899,1901,1903],{"class":1072,"line":1087},[1070,1880,1881],{"class":1096},"  const",[1070,1883,1574],{"class":1076},[1070,1885,1641],{"class":1289},[1070,1887,1580],{"class":1076},[1070,1889,1646],{"class":1289},[1070,1891,1586],{"class":1076},[1070,1893,1532],{"class":1076},[1070,1895,1591],{"class":1562},[1070,1897,1898],{"class":1424}," readBody",[1070,1900,1428],{"class":1080},[1070,1902,1869],{"class":1289},[1070,1904,1434],{"class":1080},[1070,1906,1907],{"class":1072,"line":1114},[1070,1908,1556],{"class":1080},[1070,1910,1911],{"class":1072,"line":1126},[1070,1912,1913],{"class":1669},"  \u002F\u002F Fetch user from Cockpit (automatically scoped to the tenant)\n",[1070,1915,1916,1918,1920,1922,1924,1927,1929,1932,1934,1937,1939,1941],{"class":1072,"line":1143},[1070,1917,1881],{"class":1096},[1070,1919,1583],{"class":1289},[1070,1921,1532],{"class":1076},[1070,1923,1591],{"class":1562},[1070,1925,1926],{"class":1289}," cockpit",[1070,1928,1526],{"class":1076},[1070,1930,1931],{"class":1289},"users",[1070,1933,1526],{"class":1076},[1070,1935,1936],{"class":1424},"findByEmail",[1070,1938,1428],{"class":1080},[1070,1940,1136],{"class":1289},[1070,1942,1434],{"class":1080},[1070,1944,1945,1948,1950,1953,1956,1958],{"class":1072,"line":1159},[1070,1946,1947],{"class":1562},"  if",[1070,1949,1012],{"class":1080},[1070,1951,1952],{"class":1076},"!",[1070,1954,1955],{"class":1289},"user",[1070,1957,1741],{"class":1080},[1070,1959,1744],{"class":1076},[1070,1961,1962,1965,1968,1970],{"class":1072,"line":1176},[1070,1963,1964],{"class":1562},"    throw",[1070,1966,1967],{"class":1424}," createError",[1070,1969,1428],{"class":1080},[1070,1971,1744],{"class":1076},[1070,1973,1974,1977,1979,1983],{"class":1072,"line":1182},[1070,1975,1976],{"class":1080},"      statusCode",[1070,1978,1617],{"class":1076},[1070,1980,1982],{"class":1981},"sbssI"," 401",[1070,1984,1628],{"class":1076},[1070,1986,1987,1990,1992,1994,1996],{"class":1072,"line":1188},[1070,1988,1989],{"class":1080},"      message",[1070,1991,1617],{"class":1076},[1070,1993,1620],{"class":1076},[1070,1995,1777],{"class":1106},[1070,1997,1780],{"class":1076},[1070,1999,2000,2002],{"class":1072,"line":1197},[1070,2001,1655],{"class":1076},[1070,2003,1434],{"class":1080},[1070,2005,2006],{"class":1072,"line":1213},[1070,2007,1811],{"class":1076},[1070,2009,2010],{"class":1072,"line":1228},[1070,2011,1556],{"class":1080},[1070,2013,2014],{"class":1072,"line":1244},[1070,2015,2016],{"class":1669},"  \u002F\u002F Verify password\n",[1070,2018,2019,2021,2024,2026,2028,2031,2033,2036,2038,2040,2042,2044,2046,2049],{"class":1072,"line":1249},[1070,2020,1881],{"class":1096},[1070,2022,2023],{"class":1289}," passwordValid",[1070,2025,1532],{"class":1076},[1070,2027,1591],{"class":1562},[1070,2029,2030],{"class":1289}," bcrypt",[1070,2032,1526],{"class":1076},[1070,2034,2035],{"class":1424},"compare",[1070,2037,1428],{"class":1080},[1070,2039,1206],{"class":1289},[1070,2041,1580],{"class":1076},[1070,2043,1583],{"class":1289},[1070,2045,1526],{"class":1076},[1070,2047,2048],{"class":1289},"password_hash",[1070,2050,1434],{"class":1080},[1070,2052,2053,2055,2057,2059,2062,2064],{"class":1072,"line":1254},[1070,2054,1947],{"class":1562},[1070,2056,1012],{"class":1080},[1070,2058,1952],{"class":1076},[1070,2060,2061],{"class":1289},"passwordValid",[1070,2063,1741],{"class":1080},[1070,2065,1744],{"class":1076},[1070,2067,2068,2070,2072,2074],{"class":1072,"line":1300},[1070,2069,1964],{"class":1562},[1070,2071,1967],{"class":1424},[1070,2073,1428],{"class":1080},[1070,2075,1744],{"class":1076},[1070,2077,2078,2080,2082,2084],{"class":1072,"line":1331},[1070,2079,1976],{"class":1080},[1070,2081,1617],{"class":1076},[1070,2083,1982],{"class":1981},[1070,2085,1628],{"class":1076},[1070,2087,2088,2090,2092,2094,2096],{"class":1072,"line":1374},[1070,2089,1989],{"class":1080},[1070,2091,1617],{"class":1076},[1070,2093,1620],{"class":1076},[1070,2095,1777],{"class":1106},[1070,2097,1780],{"class":1076},[1070,2099,2100,2102],{"class":1072,"line":1384},[1070,2101,1655],{"class":1076},[1070,2103,1434],{"class":1080},[1070,2105,2106],{"class":1072,"line":1393},[1070,2107,1811],{"class":1076},[1070,2109,2110],{"class":1072,"line":1400},[1070,2111,1556],{"class":1080},[1070,2113,2114],{"class":1072,"line":1413},[1070,2115,2116],{"class":1669},"  \u002F\u002F Check if account is active\n",[1070,2118,2119,2121,2123,2125,2127,2130,2133,2135,2138,2140,2142],{"class":1072,"line":1437},[1070,2120,1947],{"class":1562},[1070,2122,1012],{"class":1080},[1070,2124,1955],{"class":1289},[1070,2126,1526],{"class":1076},[1070,2128,2129],{"class":1289},"status",[1070,2131,2132],{"class":1076}," !==",[1070,2134,1620],{"class":1076},[1070,2136,2137],{"class":1106},"active",[1070,2139,1599],{"class":1076},[1070,2141,1741],{"class":1080},[1070,2143,1744],{"class":1076},[1070,2145,2146,2148,2150,2152],{"class":1072,"line":1455},[1070,2147,1964],{"class":1562},[1070,2149,1967],{"class":1424},[1070,2151,1428],{"class":1080},[1070,2153,1744],{"class":1076},[1070,2155,2156,2158,2160,2163],{"class":1072,"line":1475},[1070,2157,1976],{"class":1080},[1070,2159,1617],{"class":1076},[1070,2161,2162],{"class":1981}," 403",[1070,2164,1628],{"class":1076},[1070,2166,2167,2169,2171,2173,2176],{"class":1072,"line":1493},[1070,2168,1989],{"class":1080},[1070,2170,1617],{"class":1076},[1070,2172,1620],{"class":1076},[1070,2174,2175],{"class":1106},"Account is inactive. Contact support.",[1070,2177,1780],{"class":1076},[1070,2179,2180,2182],{"class":1072,"line":1498},[1070,2181,1655],{"class":1076},[1070,2183,1434],{"class":1080},[1070,2185,2186],{"class":1072,"line":1520},[1070,2187,1811],{"class":1076},[1070,2189,2190],{"class":1072,"line":1538},[1070,2191,1556],{"class":1080},[1070,2193,2194],{"class":1072,"line":1553},[1070,2195,2196],{"class":1669},"  \u002F\u002F Generate JWT token\n",[1070,2198,2199,2201,2203,2205,2208,2210,2213],{"class":1072,"line":1559},[1070,2200,1881],{"class":1096},[1070,2202,1577],{"class":1289},[1070,2204,1532],{"class":1076},[1070,2206,2207],{"class":1289}," jwt",[1070,2209,1526],{"class":1076},[1070,2211,2212],{"class":1424},"sign",[1070,2214,2215],{"class":1080},"(\n",[1070,2217,2218],{"class":1072,"line":1568},[1070,2219,2220],{"class":1076},"    {\n",[1070,2222,2223,2226,2228,2230,2232,2235],{"class":1072,"line":1611},[1070,2224,2225],{"class":1080},"      user_id",[1070,2227,1617],{"class":1076},[1070,2229,1583],{"class":1289},[1070,2231,1526],{"class":1076},[1070,2233,2234],{"class":1289},"id",[1070,2236,1628],{"class":1076},[1070,2238,2239,2242,2244,2246,2248,2251],{"class":1072,"line":1631},[1070,2240,2241],{"class":1080},"      tenant_id",[1070,2243,1617],{"class":1076},[1070,2245,1583],{"class":1289},[1070,2247,1526],{"class":1076},[1070,2249,2250],{"class":1289},"tenant_id",[1070,2252,1628],{"class":1076},[1070,2254,2255,2258,2260,2262,2264,2266],{"class":1072,"line":1652},[1070,2256,2257],{"class":1080},"      email",[1070,2259,1617],{"class":1076},[1070,2261,1583],{"class":1289},[1070,2263,1526],{"class":1076},[1070,2265,1136],{"class":1289},[1070,2267,1628],{"class":1076},[1070,2269,2270,2273,2275,2277,2279],{"class":1072,"line":1660},[1070,2271,2272],{"class":1080},"      role",[1070,2274,1617],{"class":1076},[1070,2276,1583],{"class":1289},[1070,2278,1526],{"class":1076},[1070,2280,2281],{"class":1289},"role\n",[1070,2283,2284],{"class":1072,"line":1666},[1070,2285,2286],{"class":1076},"    },\n",[1070,2288,2289,2292,2294,2297,2299,2302],{"class":1072,"line":1673},[1070,2290,2291],{"class":1289},"    process",[1070,2293,1526],{"class":1076},[1070,2295,2296],{"class":1289},"env",[1070,2298,1526],{"class":1076},[1070,2300,2301],{"class":1289},"JWT_SECRET",[1070,2303,1628],{"class":1076},[1070,2305,2306,2309,2312,2314,2316,2319,2321],{"class":1072,"line":1699},[1070,2307,2308],{"class":1076},"    {",[1070,2310,2311],{"class":1080}," expiresIn",[1070,2313,1617],{"class":1076},[1070,2315,1620],{"class":1076},[1070,2317,2318],{"class":1106},"7d",[1070,2320,1599],{"class":1076},[1070,2322,1649],{"class":1076},[1070,2324,2325],{"class":1072,"line":1704},[1070,2326,2327],{"class":1080},"  )\n",[1070,2329,2330],{"class":1072,"line":1710},[1070,2331,1556],{"class":1080},[1070,2333,2334],{"class":1072,"line":1727},[1070,2335,2336],{"class":1669},"  \u002F\u002F Set secure httpOnly cookie (optional, for session)\n",[1070,2338,2339,2342,2344,2346,2348,2350,2352,2354,2356,2358,2360],{"class":1072,"line":1747},[1070,2340,2341],{"class":1424},"  setCookie",[1070,2343,1428],{"class":1080},[1070,2345,1869],{"class":1289},[1070,2347,1580],{"class":1076},[1070,2349,1620],{"class":1076},[1070,2351,1688],{"class":1106},[1070,2353,1599],{"class":1076},[1070,2355,1580],{"class":1076},[1070,2357,1577],{"class":1289},[1070,2359,1580],{"class":1076},[1070,2361,1517],{"class":1076},[1070,2363,2364,2367,2369,2372],{"class":1072,"line":1783},[1070,2365,2366],{"class":1080},"    httpOnly",[1070,2368,1617],{"class":1076},[1070,2370,2371],{"class":1469}," true",[1070,2373,1628],{"class":1076},[1070,2375,2376,2379,2381,2383],{"class":1072,"line":1793},[1070,2377,2378],{"class":1080},"    secure",[1070,2380,1617],{"class":1076},[1070,2382,2371],{"class":1469},[1070,2384,1628],{"class":1076},[1070,2386,2387,2390,2392,2394,2397,2399],{"class":1072,"line":1808},[1070,2388,2389],{"class":1080},"    sameSite",[1070,2391,1617],{"class":1076},[1070,2393,1620],{"class":1076},[1070,2395,2396],{"class":1106},"strict",[1070,2398,1599],{"class":1076},[1070,2400,1628],{"class":1076},[1070,2402,2403,2406,2408,2411,2414,2417,2419,2422,2424,2426],{"class":1072,"line":1814},[1070,2404,2405],{"class":1080},"    maxAge",[1070,2407,1617],{"class":1076},[1070,2409,2410],{"class":1981}," 7",[1070,2412,2413],{"class":1076}," *",[1070,2415,2416],{"class":1981}," 24",[1070,2418,2413],{"class":1076},[1070,2420,2421],{"class":1981}," 60",[1070,2423,2413],{"class":1076},[1070,2425,2421],{"class":1981},[1070,2427,2428],{"class":1669}," \u002F\u002F 7 days\n",[1070,2430,2431,2433],{"class":1072,"line":1820},[1070,2432,1730],{"class":1076},[1070,2434,1434],{"class":1080},[1070,2436,2438],{"class":1072,"line":2437},49,[1070,2439,1556],{"class":1080},[1070,2441,2443,2446],{"class":1072,"line":2442},50,[1070,2444,2445],{"class":1562},"  return",[1070,2447,1517],{"class":1076},[1070,2449,2451,2454],{"class":1072,"line":2450},51,[1070,2452,2453],{"class":1289},"    token",[1070,2455,1628],{"class":1076},[1070,2457,2459,2462,2464],{"class":1072,"line":2458},52,[1070,2460,2461],{"class":1080},"    user",[1070,2463,1617],{"class":1076},[1070,2465,1517],{"class":1076},[1070,2467,2469,2472,2474,2476,2478,2480],{"class":1072,"line":2468},53,[1070,2470,2471],{"class":1080},"      id",[1070,2473,1617],{"class":1076},[1070,2475,1583],{"class":1289},[1070,2477,1526],{"class":1076},[1070,2479,2234],{"class":1289},[1070,2481,1628],{"class":1076},[1070,2483,2485,2487,2489,2491,2493,2495],{"class":1072,"line":2484},54,[1070,2486,2257],{"class":1080},[1070,2488,1617],{"class":1076},[1070,2490,1583],{"class":1289},[1070,2492,1526],{"class":1076},[1070,2494,1136],{"class":1289},[1070,2496,1628],{"class":1076},[1070,2498,2500,2503,2505,2507,2509,2512],{"class":1072,"line":2499},55,[1070,2501,2502],{"class":1080},"      name",[1070,2504,1617],{"class":1076},[1070,2506,1583],{"class":1289},[1070,2508,1526],{"class":1076},[1070,2510,2511],{"class":1289},"name",[1070,2513,1628],{"class":1076},[1070,2515,2517,2519,2521,2523,2525],{"class":1072,"line":2516},56,[1070,2518,2272],{"class":1080},[1070,2520,1617],{"class":1076},[1070,2522,1583],{"class":1289},[1070,2524,1526],{"class":1076},[1070,2526,2281],{"class":1289},[1070,2528,2530],{"class":1072,"line":2529},57,[1070,2531,2532],{"class":1076},"    }\n",[1070,2534,2536],{"class":1072,"line":2535},58,[1070,2537,1811],{"class":1076},[1070,2539,2541,2544],{"class":1072,"line":2540},59,[1070,2542,2543],{"class":1076},"}",[1070,2545,1434],{"class":1289},[1055,2547,2549],{"id":2548},"_3-token-storage-usage","3. Token Storage & Usage",[990,2551,2552,2553,2556],{},"Once you have a token, where you keep it is a genuine security decision rather than a detail. Storing it in ",[1014,2554,2555],{},"localStorage"," is simple and works, but the token is readable by any JavaScript on the page — so a single XSS bug hands it to an attacker:",[1038,2558,2560],{"className":1843,"code":2559,"language":1845,"meta":1046,"style":1046},"localStorage.setItem('auth_token', token)\n",[1014,2561,2562],{"__ignoreMap":1046},[1070,2563,2564,2566,2568,2570,2572,2574,2576,2578,2580],{"class":1072,"line":1073},[1070,2565,2555],{"class":1289},[1070,2567,1526],{"class":1076},[1070,2569,1681],{"class":1424},[1070,2571,1428],{"class":1289},[1070,2573,1599],{"class":1076},[1070,2575,1688],{"class":1106},[1070,2577,1599],{"class":1076},[1070,2579,1580],{"class":1076},[1070,2581,2582],{"class":1289}," token)\n",[990,2584,2585,2586,2589],{},"The safer option, and the recommended one, is an ",[1014,2587,2588],{},"httpOnly"," cookie. The server sets it, JavaScript can't read it (which neutralizes the XSS risk), and the browser attaches it to every request automatically — at the cost of needing CSRF protection, which you want anyway:",[1038,2591,2593],{"className":1843,"code":2592,"language":1845,"meta":1046,"style":1046},"\u002F\u002F Server sets httpOnly cookie automatically (no JS access)\n\u002F\u002F Browser sends it automatically with all requests\n",[1014,2594,2595,2600],{"__ignoreMap":1046},[1070,2596,2597],{"class":1072,"line":1073},[1070,2598,2599],{"class":1669},"\u002F\u002F Server sets httpOnly cookie automatically (no JS access)\n",[1070,2601,2602],{"class":1072,"line":1087},[1070,2603,2604],{"class":1669},"\u002F\u002F Browser sends it automatically with all requests\n",[990,2606,2607,2608,2610,2611,2614],{},"When you do read the token in JS — for the ",[1014,2609,2555],{}," approach — you attach it as a bearer header on outgoing requests, which is cleanest to centralize in a ",[1014,2612,2613],{},"$fetch"," wrapper so you set it once rather than on every call:",[1038,2616,2618],{"className":1843,"code":2617,"language":1845,"meta":1046,"style":1046},"const $fetch = $fetch.create({\n  onRequest({ request, options }) {\n    const token = sessionStorage.getItem('auth_token')\n    if (token) {\n      options.headers = options.headers || {}\n      options.headers.Authorization = `Bearer ${token}`\n    }\n  }\n})\n\n\u002F\u002F All requests now include auth header\nconst cart = await $fetch('\u002Fapi\u002Fcart')\n",[1014,2619,2620,2640,2661,2687,2701,2724,2753,2757,2761,2767,2771,2776],{"__ignoreMap":1046},[1070,2621,2622,2624,2627,2629,2631,2633,2636,2638],{"class":1072,"line":1073},[1070,2623,1416],{"class":1096},[1070,2625,2626],{"class":1289}," $fetch ",[1070,2628,1100],{"class":1076},[1070,2630,1594],{"class":1289},[1070,2632,1526],{"class":1076},[1070,2634,2635],{"class":1424},"create",[1070,2637,1428],{"class":1289},[1070,2639,1744],{"class":1076},[1070,2641,2642,2645,2648,2651,2653,2656,2659],{"class":1072,"line":1087},[1070,2643,2644],{"class":1080},"  onRequest",[1070,2646,2647],{"class":1076},"({",[1070,2649,2650],{"class":1868}," request",[1070,2652,1580],{"class":1076},[1070,2654,2655],{"class":1868}," options",[1070,2657,2658],{"class":1076}," })",[1070,2660,1517],{"class":1076},[1070,2662,2663,2665,2667,2669,2672,2674,2677,2679,2681,2683,2685],{"class":1072,"line":1114},[1070,2664,1571],{"class":1096},[1070,2666,1577],{"class":1289},[1070,2668,1532],{"class":1076},[1070,2670,2671],{"class":1289}," sessionStorage",[1070,2673,1526],{"class":1076},[1070,2675,2676],{"class":1424},"getItem",[1070,2678,1428],{"class":1080},[1070,2680,1599],{"class":1076},[1070,2682,1688],{"class":1106},[1070,2684,1599],{"class":1076},[1070,2686,1434],{"class":1080},[1070,2688,2689,2692,2694,2697,2699],{"class":1072,"line":1126},[1070,2690,2691],{"class":1562},"    if",[1070,2693,1012],{"class":1080},[1070,2695,2696],{"class":1289},"token",[1070,2698,1741],{"class":1080},[1070,2700,1744],{"class":1076},[1070,2702,2703,2706,2708,2711,2713,2715,2717,2719,2721],{"class":1072,"line":1143},[1070,2704,2705],{"class":1289},"      options",[1070,2707,1526],{"class":1076},[1070,2709,2710],{"class":1289},"headers",[1070,2712,1532],{"class":1076},[1070,2714,2655],{"class":1289},[1070,2716,1526],{"class":1076},[1070,2718,2710],{"class":1289},[1070,2720,1772],{"class":1076},[1070,2722,2723],{"class":1076}," {}\n",[1070,2725,2726,2728,2730,2732,2734,2737,2739,2742,2745,2748,2750],{"class":1072,"line":1159},[1070,2727,2705],{"class":1289},[1070,2729,1526],{"class":1076},[1070,2731,2710],{"class":1289},[1070,2733,1526],{"class":1076},[1070,2735,2736],{"class":1289},"Authorization",[1070,2738,1532],{"class":1076},[1070,2740,2741],{"class":1076}," `",[1070,2743,2744],{"class":1106},"Bearer ",[1070,2746,2747],{"class":1076},"${",[1070,2749,2696],{"class":1289},[1070,2751,2752],{"class":1076},"}`\n",[1070,2754,2755],{"class":1072,"line":1176},[1070,2756,2532],{"class":1076},[1070,2758,2759],{"class":1072,"line":1182},[1070,2760,1811],{"class":1076},[1070,2762,2763,2765],{"class":1072,"line":1188},[1070,2764,2543],{"class":1076},[1070,2766,1434],{"class":1289},[1070,2768,2769],{"class":1072,"line":1197},[1070,2770,1397],{"emptyLinePlaceholder":1396},[1070,2772,2773],{"class":1072,"line":1213},[1070,2774,2775],{"class":1669},"\u002F\u002F All requests now include auth header\n",[1070,2777,2778,2780,2783,2785,2787,2789,2791,2793,2796,2798],{"class":1072,"line":1228},[1070,2779,1416],{"class":1096},[1070,2781,2782],{"class":1289}," cart ",[1070,2784,1100],{"class":1076},[1070,2786,1591],{"class":1562},[1070,2788,1594],{"class":1424},[1070,2790,1428],{"class":1289},[1070,2792,1599],{"class":1076},[1070,2794,2795],{"class":1106},"\u002Fapi\u002Fcart",[1070,2797,1599],{"class":1076},[1070,2799,1434],{"class":1289},[1033,2801,2803],{"id":2802},"registration-flow","Registration Flow",[990,2805,2806],{},"Registration mirrors login closely — a form that POSTs to a BFF endpoint, which creates the user and signs a token — with two extra concerns. Client-side, you validate the obvious things early (passwords match, minimum length, terms accepted) so the user gets instant feedback without a round trip. Server-side, you re-validate everything regardless, because client checks are a convenience, not a security boundary.",[1055,2808,2810],{"id":2809},"_1-user-creates-account","1. User Creates Account",[990,2812,2813],{},"The form gathers the usual fields and does its first-pass validation right in the submit handler before calling the API:",[1038,2815,2817],{"className":1064,"code":2816,"language":1066,"meta":1046,"style":1046},"\u003Ctemplate>\n  \u003Cform @submit=\"handleRegister\">\n    \u003Cinput \n      v-model=\"firstName\" \n      type=\"text\" \n      placeholder=\"First Name\" \n      required\n    \u002F>\n    \u003Cinput \n      v-model=\"lastName\" \n      type=\"text\" \n      placeholder=\"Last Name\" \n      required\n    \u002F>\n    \u003Cinput \n      v-model=\"email\" \n      type=\"email\" \n      placeholder=\"your@email.com\" \n      required\n    \u002F>\n    \u003Cinput \n      v-model=\"password\" \n      type=\"password\" \n      placeholder=\"Password (min 8 chars)\" \n      minlength=\"8\"\n      required\n    \u002F>\n    \u003Cinput \n      v-model=\"passwordConfirm\" \n      type=\"password\" \n      placeholder=\"Confirm Password\" \n      required\n    \u002F>\n    \u003Clabel>\n      \u003Cinput v-model=\"agreeTerms\" type=\"checkbox\" required \u002F>\n      I agree to the Terms & Conditions\n    \u003C\u002Flabel>\n    \u003Cbutton type=\"submit\" :disabled=\"loading\">Create Account\u003C\u002Fbutton>\n  \u003C\u002Fform>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nconst firstName = ref('')\nconst lastName = ref('')\nconst email = ref('')\nconst password = ref('')\nconst passwordConfirm = ref('')\nconst agreeTerms = ref(false)\nconst loading = ref(false)\n\nconst handleRegister = async () => {\n  if (password.value !== passwordConfirm.value) {\n    error.value = 'Passwords do not match'\n    return\n  }\n  \n  if (password.value.length \u003C 8) {\n    error.value = 'Password must be at least 8 characters'\n    return\n  }\n  \n  loading.value = true\n  \n  try {\n    const { token } = await $fetch('\u002Fapi\u002Fauth\u002Fregister', {\n      method: 'POST',\n      body: {\n        first_name: firstName.value,\n        last_name: lastName.value,\n        email: email.value,\n        password: password.value,\n        agree_terms: agreeTerms.value\n      }\n    })\n    \n    sessionStorage.setItem('auth_token', token)\n    navigateTo('\u002Faccount')\n  } catch (err) {\n    error.value = err.data.message\n  } finally {\n    loading.value = false\n  }\n}\n\u003C\u002Fscript>\n",[1014,2818,2819,2827,2846,2854,2869,2883,2898,2902,2906,2914,2929,2943,2958,2962,2966,2974,2988,3002,3016,3020,3024,3032,3046,3060,3075,3090,3094,3098,3106,3121,3135,3150,3154,3158,3167,3203,3208,3217,3254,3262,3270,3274,3284,3301,3318,3334,3350,3367,3384,3400,3404,3421,3446,3463,3468,3472,3476,3503,3520,3524,3529,3534,3547,3552,3559,3589,3604,3613,3630,3647,3663,3679,3695,3701,3708,3713,3736,3751,3766,3788,3797,3810,3815,3820],{"__ignoreMap":1046},[1070,2820,2821,2823,2825],{"class":1072,"line":1073},[1070,2822,1077],{"class":1076},[1070,2824,1081],{"class":1080},[1070,2826,1084],{"class":1076},[1070,2828,2829,2831,2833,2835,2837,2839,2842,2844],{"class":1072,"line":1087},[1070,2830,1090],{"class":1076},[1070,2832,1093],{"class":1080},[1070,2834,1097],{"class":1096},[1070,2836,1100],{"class":1076},[1070,2838,1103],{"class":1076},[1070,2840,2841],{"class":1106},"handleRegister",[1070,2843,1103],{"class":1076},[1070,2845,1084],{"class":1076},[1070,2847,2848,2850,2852],{"class":1072,"line":1114},[1070,2849,1117],{"class":1076},[1070,2851,1120],{"class":1080},[1070,2853,1123],{"class":1076},[1070,2855,2856,2858,2860,2862,2865,2867],{"class":1072,"line":1126},[1070,2857,1129],{"class":1096},[1070,2859,1100],{"class":1076},[1070,2861,1103],{"class":1076},[1070,2863,2864],{"class":1106},"firstName",[1070,2866,1103],{"class":1076},[1070,2868,1123],{"class":1076},[1070,2870,2871,2873,2875,2877,2879,2881],{"class":1072,"line":1143},[1070,2872,1146],{"class":1096},[1070,2874,1100],{"class":1076},[1070,2876,1103],{"class":1076},[1070,2878,1043],{"class":1106},[1070,2880,1103],{"class":1076},[1070,2882,1123],{"class":1076},[1070,2884,2885,2887,2889,2891,2894,2896],{"class":1072,"line":1159},[1070,2886,1162],{"class":1096},[1070,2888,1100],{"class":1076},[1070,2890,1103],{"class":1076},[1070,2892,2893],{"class":1106},"First Name",[1070,2895,1103],{"class":1076},[1070,2897,1123],{"class":1076},[1070,2899,2900],{"class":1072,"line":1176},[1070,2901,1179],{"class":1096},[1070,2903,2904],{"class":1072,"line":1182},[1070,2905,1185],{"class":1076},[1070,2907,2908,2910,2912],{"class":1072,"line":1188},[1070,2909,1117],{"class":1076},[1070,2911,1120],{"class":1080},[1070,2913,1123],{"class":1076},[1070,2915,2916,2918,2920,2922,2925,2927],{"class":1072,"line":1197},[1070,2917,1129],{"class":1096},[1070,2919,1100],{"class":1076},[1070,2921,1103],{"class":1076},[1070,2923,2924],{"class":1106},"lastName",[1070,2926,1103],{"class":1076},[1070,2928,1123],{"class":1076},[1070,2930,2931,2933,2935,2937,2939,2941],{"class":1072,"line":1213},[1070,2932,1146],{"class":1096},[1070,2934,1100],{"class":1076},[1070,2936,1103],{"class":1076},[1070,2938,1043],{"class":1106},[1070,2940,1103],{"class":1076},[1070,2942,1123],{"class":1076},[1070,2944,2945,2947,2949,2951,2954,2956],{"class":1072,"line":1228},[1070,2946,1162],{"class":1096},[1070,2948,1100],{"class":1076},[1070,2950,1103],{"class":1076},[1070,2952,2953],{"class":1106},"Last Name",[1070,2955,1103],{"class":1076},[1070,2957,1123],{"class":1076},[1070,2959,2960],{"class":1072,"line":1244},[1070,2961,1179],{"class":1096},[1070,2963,2964],{"class":1072,"line":1249},[1070,2965,1185],{"class":1076},[1070,2967,2968,2970,2972],{"class":1072,"line":1254},[1070,2969,1117],{"class":1076},[1070,2971,1120],{"class":1080},[1070,2973,1123],{"class":1076},[1070,2975,2976,2978,2980,2982,2984,2986],{"class":1072,"line":1300},[1070,2977,1129],{"class":1096},[1070,2979,1100],{"class":1076},[1070,2981,1103],{"class":1076},[1070,2983,1136],{"class":1106},[1070,2985,1103],{"class":1076},[1070,2987,1123],{"class":1076},[1070,2989,2990,2992,2994,2996,2998,3000],{"class":1072,"line":1331},[1070,2991,1146],{"class":1096},[1070,2993,1100],{"class":1076},[1070,2995,1103],{"class":1076},[1070,2997,1136],{"class":1106},[1070,2999,1103],{"class":1076},[1070,3001,1123],{"class":1076},[1070,3003,3004,3006,3008,3010,3012,3014],{"class":1072,"line":1374},[1070,3005,1162],{"class":1096},[1070,3007,1100],{"class":1076},[1070,3009,1103],{"class":1076},[1070,3011,1169],{"class":1106},[1070,3013,1103],{"class":1076},[1070,3015,1123],{"class":1076},[1070,3017,3018],{"class":1072,"line":1384},[1070,3019,1179],{"class":1096},[1070,3021,3022],{"class":1072,"line":1393},[1070,3023,1185],{"class":1076},[1070,3025,3026,3028,3030],{"class":1072,"line":1400},[1070,3027,1117],{"class":1076},[1070,3029,1120],{"class":1080},[1070,3031,1123],{"class":1076},[1070,3033,3034,3036,3038,3040,3042,3044],{"class":1072,"line":1413},[1070,3035,1129],{"class":1096},[1070,3037,1100],{"class":1076},[1070,3039,1103],{"class":1076},[1070,3041,1206],{"class":1106},[1070,3043,1103],{"class":1076},[1070,3045,1123],{"class":1076},[1070,3047,3048,3050,3052,3054,3056,3058],{"class":1072,"line":1437},[1070,3049,1146],{"class":1096},[1070,3051,1100],{"class":1076},[1070,3053,1103],{"class":1076},[1070,3055,1206],{"class":1106},[1070,3057,1103],{"class":1076},[1070,3059,1123],{"class":1076},[1070,3061,3062,3064,3066,3068,3071,3073],{"class":1072,"line":1455},[1070,3063,1162],{"class":1096},[1070,3065,1100],{"class":1076},[1070,3067,1103],{"class":1076},[1070,3069,3070],{"class":1106},"Password (min 8 chars)",[1070,3072,1103],{"class":1076},[1070,3074,1123],{"class":1076},[1070,3076,3077,3080,3082,3084,3087],{"class":1072,"line":1475},[1070,3078,3079],{"class":1096},"      minlength",[1070,3081,1100],{"class":1076},[1070,3083,1103],{"class":1076},[1070,3085,3086],{"class":1106},"8",[1070,3088,3089],{"class":1076},"\"\n",[1070,3091,3092],{"class":1072,"line":1493},[1070,3093,1179],{"class":1096},[1070,3095,3096],{"class":1072,"line":1498},[1070,3097,1185],{"class":1076},[1070,3099,3100,3102,3104],{"class":1072,"line":1520},[1070,3101,1117],{"class":1076},[1070,3103,1120],{"class":1080},[1070,3105,1123],{"class":1076},[1070,3107,3108,3110,3112,3114,3117,3119],{"class":1072,"line":1538},[1070,3109,1129],{"class":1096},[1070,3111,1100],{"class":1076},[1070,3113,1103],{"class":1076},[1070,3115,3116],{"class":1106},"passwordConfirm",[1070,3118,1103],{"class":1076},[1070,3120,1123],{"class":1076},[1070,3122,3123,3125,3127,3129,3131,3133],{"class":1072,"line":1553},[1070,3124,1146],{"class":1096},[1070,3126,1100],{"class":1076},[1070,3128,1103],{"class":1076},[1070,3130,1206],{"class":1106},[1070,3132,1103],{"class":1076},[1070,3134,1123],{"class":1076},[1070,3136,3137,3139,3141,3143,3146,3148],{"class":1072,"line":1559},[1070,3138,1162],{"class":1096},[1070,3140,1100],{"class":1076},[1070,3142,1103],{"class":1076},[1070,3144,3145],{"class":1106},"Confirm Password",[1070,3147,1103],{"class":1076},[1070,3149,1123],{"class":1076},[1070,3151,3152],{"class":1072,"line":1568},[1070,3153,1179],{"class":1096},[1070,3155,3156],{"class":1072,"line":1611},[1070,3157,1185],{"class":1076},[1070,3159,3160,3162,3165],{"class":1072,"line":1631},[1070,3161,1117],{"class":1076},[1070,3163,3164],{"class":1080},"label",[1070,3166,1084],{"class":1076},[1070,3168,3169,3172,3174,3177,3179,3181,3184,3186,3188,3190,3192,3195,3197,3200],{"class":1072,"line":1652},[1070,3170,3171],{"class":1076},"      \u003C",[1070,3173,1120],{"class":1080},[1070,3175,3176],{"class":1096}," v-model",[1070,3178,1100],{"class":1076},[1070,3180,1103],{"class":1076},[1070,3182,3183],{"class":1106},"agreeTerms",[1070,3185,1103],{"class":1076},[1070,3187,1262],{"class":1096},[1070,3189,1100],{"class":1076},[1070,3191,1103],{"class":1076},[1070,3193,3194],{"class":1106},"checkbox",[1070,3196,1103],{"class":1076},[1070,3198,3199],{"class":1096}," required",[1070,3201,3202],{"class":1076}," \u002F>\n",[1070,3204,3205],{"class":1072,"line":1660},[1070,3206,3207],{"class":1289},"      I agree to the Terms & Conditions\n",[1070,3209,3210,3213,3215],{"class":1072,"line":1666},[1070,3211,3212],{"class":1076},"    \u003C\u002F",[1070,3214,3164],{"class":1080},[1070,3216,1084],{"class":1076},[1070,3218,3219,3221,3223,3225,3227,3229,3231,3233,3235,3237,3239,3241,3243,3245,3248,3250,3252],{"class":1072,"line":1673},[1070,3220,1117],{"class":1076},[1070,3222,1259],{"class":1080},[1070,3224,1262],{"class":1096},[1070,3226,1100],{"class":1076},[1070,3228,1103],{"class":1076},[1070,3230,1269],{"class":1106},[1070,3232,1103],{"class":1076},[1070,3234,1274],{"class":1096},[1070,3236,1100],{"class":1076},[1070,3238,1103],{"class":1076},[1070,3240,1281],{"class":1106},[1070,3242,1103],{"class":1076},[1070,3244,1286],{"class":1076},[1070,3246,3247],{"class":1289},"Create Account",[1070,3249,1293],{"class":1076},[1070,3251,1259],{"class":1080},[1070,3253,1084],{"class":1076},[1070,3255,3256,3258,3260],{"class":1072,"line":1699},[1070,3257,1377],{"class":1076},[1070,3259,1093],{"class":1080},[1070,3261,1084],{"class":1076},[1070,3263,3264,3266,3268],{"class":1072,"line":1704},[1070,3265,1293],{"class":1076},[1070,3267,1081],{"class":1080},[1070,3269,1084],{"class":1076},[1070,3271,3272],{"class":1072,"line":1710},[1070,3273,1397],{"emptyLinePlaceholder":1396},[1070,3275,3276,3278,3280,3282],{"class":1072,"line":1727},[1070,3277,1077],{"class":1076},[1070,3279,1405],{"class":1080},[1070,3281,1408],{"class":1096},[1070,3283,1084],{"class":1076},[1070,3285,3286,3288,3291,3293,3295,3297,3299],{"class":1072,"line":1747},[1070,3287,1416],{"class":1096},[1070,3289,3290],{"class":1289}," firstName ",[1070,3292,1100],{"class":1076},[1070,3294,1425],{"class":1424},[1070,3296,1428],{"class":1289},[1070,3298,1431],{"class":1076},[1070,3300,1434],{"class":1289},[1070,3302,3303,3305,3308,3310,3312,3314,3316],{"class":1072,"line":1783},[1070,3304,1416],{"class":1096},[1070,3306,3307],{"class":1289}," lastName ",[1070,3309,1100],{"class":1076},[1070,3311,1425],{"class":1424},[1070,3313,1428],{"class":1289},[1070,3315,1431],{"class":1076},[1070,3317,1434],{"class":1289},[1070,3319,3320,3322,3324,3326,3328,3330,3332],{"class":1072,"line":1793},[1070,3321,1416],{"class":1096},[1070,3323,1419],{"class":1289},[1070,3325,1100],{"class":1076},[1070,3327,1425],{"class":1424},[1070,3329,1428],{"class":1289},[1070,3331,1431],{"class":1076},[1070,3333,1434],{"class":1289},[1070,3335,3336,3338,3340,3342,3344,3346,3348],{"class":1072,"line":1808},[1070,3337,1416],{"class":1096},[1070,3339,1442],{"class":1289},[1070,3341,1100],{"class":1076},[1070,3343,1425],{"class":1424},[1070,3345,1428],{"class":1289},[1070,3347,1431],{"class":1076},[1070,3349,1434],{"class":1289},[1070,3351,3352,3354,3357,3359,3361,3363,3365],{"class":1072,"line":1814},[1070,3353,1416],{"class":1096},[1070,3355,3356],{"class":1289}," passwordConfirm ",[1070,3358,1100],{"class":1076},[1070,3360,1425],{"class":1424},[1070,3362,1428],{"class":1289},[1070,3364,1431],{"class":1076},[1070,3366,1434],{"class":1289},[1070,3368,3369,3371,3374,3376,3378,3380,3382],{"class":1072,"line":1820},[1070,3370,1416],{"class":1096},[1070,3372,3373],{"class":1289}," agreeTerms ",[1070,3375,1100],{"class":1076},[1070,3377,1425],{"class":1424},[1070,3379,1428],{"class":1289},[1070,3381,1470],{"class":1469},[1070,3383,1434],{"class":1289},[1070,3385,3386,3388,3390,3392,3394,3396,3398],{"class":1072,"line":2437},[1070,3387,1416],{"class":1096},[1070,3389,1460],{"class":1289},[1070,3391,1100],{"class":1076},[1070,3393,1425],{"class":1424},[1070,3395,1428],{"class":1289},[1070,3397,1470],{"class":1469},[1070,3399,1434],{"class":1289},[1070,3401,3402],{"class":1072,"line":2442},[1070,3403,1397],{"emptyLinePlaceholder":1396},[1070,3405,3406,3408,3411,3413,3415,3417,3419],{"class":1072,"line":2450},[1070,3407,1416],{"class":1096},[1070,3409,3410],{"class":1289}," handleRegister ",[1070,3412,1100],{"class":1076},[1070,3414,1508],{"class":1096},[1070,3416,1511],{"class":1076},[1070,3418,1514],{"class":1096},[1070,3420,1517],{"class":1076},[1070,3422,3423,3425,3427,3429,3431,3433,3435,3438,3440,3442,3444],{"class":1072,"line":2458},[1070,3424,1947],{"class":1562},[1070,3426,1012],{"class":1080},[1070,3428,1206],{"class":1289},[1070,3430,1526],{"class":1076},[1070,3432,1529],{"class":1289},[1070,3434,2132],{"class":1076},[1070,3436,3437],{"class":1289}," passwordConfirm",[1070,3439,1526],{"class":1076},[1070,3441,1529],{"class":1289},[1070,3443,1741],{"class":1080},[1070,3445,1744],{"class":1076},[1070,3447,3448,3450,3452,3454,3456,3458,3461],{"class":1072,"line":2468},[1070,3449,1750],{"class":1289},[1070,3451,1526],{"class":1076},[1070,3453,1529],{"class":1289},[1070,3455,1532],{"class":1076},[1070,3457,1620],{"class":1076},[1070,3459,3460],{"class":1106},"Passwords do not match",[1070,3462,1780],{"class":1076},[1070,3464,3465],{"class":1072,"line":2484},[1070,3466,3467],{"class":1562},"    return\n",[1070,3469,3470],{"class":1072,"line":2499},[1070,3471,1811],{"class":1076},[1070,3473,3474],{"class":1072,"line":2516},[1070,3475,1556],{"class":1080},[1070,3477,3478,3480,3482,3484,3486,3488,3490,3493,3496,3499,3501],{"class":1072,"line":2529},[1070,3479,1947],{"class":1562},[1070,3481,1012],{"class":1080},[1070,3483,1206],{"class":1289},[1070,3485,1526],{"class":1076},[1070,3487,1529],{"class":1289},[1070,3489,1526],{"class":1076},[1070,3491,3492],{"class":1289},"length",[1070,3494,3495],{"class":1076}," \u003C",[1070,3497,3498],{"class":1981}," 8",[1070,3500,1741],{"class":1080},[1070,3502,1744],{"class":1076},[1070,3504,3505,3507,3509,3511,3513,3515,3518],{"class":1072,"line":2535},[1070,3506,1750],{"class":1289},[1070,3508,1526],{"class":1076},[1070,3510,1529],{"class":1289},[1070,3512,1532],{"class":1076},[1070,3514,1620],{"class":1076},[1070,3516,3517],{"class":1106},"Password must be at least 8 characters",[1070,3519,1780],{"class":1076},[1070,3521,3522],{"class":1072,"line":2540},[1070,3523,3467],{"class":1562},[1070,3525,3527],{"class":1072,"line":3526},60,[1070,3528,1811],{"class":1076},[1070,3530,3532],{"class":1072,"line":3531},61,[1070,3533,1556],{"class":1080},[1070,3535,3537,3539,3541,3543,3545],{"class":1072,"line":3536},62,[1070,3538,1523],{"class":1289},[1070,3540,1526],{"class":1076},[1070,3542,1529],{"class":1289},[1070,3544,1532],{"class":1076},[1070,3546,1535],{"class":1469},[1070,3548,3550],{"class":1072,"line":3549},63,[1070,3551,1556],{"class":1080},[1070,3553,3555,3557],{"class":1072,"line":3554},64,[1070,3556,1563],{"class":1562},[1070,3558,1517],{"class":1076},[1070,3560,3562,3564,3566,3568,3570,3572,3574,3576,3578,3580,3583,3585,3587],{"class":1072,"line":3561},65,[1070,3563,1571],{"class":1096},[1070,3565,1574],{"class":1076},[1070,3567,1577],{"class":1289},[1070,3569,1586],{"class":1076},[1070,3571,1532],{"class":1076},[1070,3573,1591],{"class":1562},[1070,3575,1594],{"class":1424},[1070,3577,1428],{"class":1080},[1070,3579,1599],{"class":1076},[1070,3581,3582],{"class":1106},"\u002Fapi\u002Fauth\u002Fregister",[1070,3584,1599],{"class":1076},[1070,3586,1580],{"class":1076},[1070,3588,1517],{"class":1076},[1070,3590,3592,3594,3596,3598,3600,3602],{"class":1072,"line":3591},66,[1070,3593,1614],{"class":1080},[1070,3595,1617],{"class":1076},[1070,3597,1620],{"class":1076},[1070,3599,1623],{"class":1106},[1070,3601,1599],{"class":1076},[1070,3603,1628],{"class":1076},[1070,3605,3607,3609,3611],{"class":1072,"line":3606},67,[1070,3608,1634],{"class":1080},[1070,3610,1617],{"class":1076},[1070,3612,1517],{"class":1076},[1070,3614,3616,3619,3621,3624,3626,3628],{"class":1072,"line":3615},68,[1070,3617,3618],{"class":1080},"        first_name",[1070,3620,1617],{"class":1076},[1070,3622,3623],{"class":1289}," firstName",[1070,3625,1526],{"class":1076},[1070,3627,1529],{"class":1289},[1070,3629,1628],{"class":1076},[1070,3631,3633,3636,3638,3641,3643,3645],{"class":1072,"line":3632},69,[1070,3634,3635],{"class":1080},"        last_name",[1070,3637,1617],{"class":1076},[1070,3639,3640],{"class":1289}," lastName",[1070,3642,1526],{"class":1076},[1070,3644,1529],{"class":1289},[1070,3646,1628],{"class":1076},[1070,3648,3650,3653,3655,3657,3659,3661],{"class":1072,"line":3649},70,[1070,3651,3652],{"class":1080},"        email",[1070,3654,1617],{"class":1076},[1070,3656,1641],{"class":1289},[1070,3658,1526],{"class":1076},[1070,3660,1529],{"class":1289},[1070,3662,1628],{"class":1076},[1070,3664,3666,3669,3671,3673,3675,3677],{"class":1072,"line":3665},71,[1070,3667,3668],{"class":1080},"        password",[1070,3670,1617],{"class":1076},[1070,3672,1646],{"class":1289},[1070,3674,1526],{"class":1076},[1070,3676,1529],{"class":1289},[1070,3678,1628],{"class":1076},[1070,3680,3682,3685,3687,3690,3692],{"class":1072,"line":3681},72,[1070,3683,3684],{"class":1080},"        agree_terms",[1070,3686,1617],{"class":1076},[1070,3688,3689],{"class":1289}," agreeTerms",[1070,3691,1526],{"class":1076},[1070,3693,3694],{"class":1289},"value\n",[1070,3696,3698],{"class":1072,"line":3697},73,[1070,3699,3700],{"class":1076},"      }\n",[1070,3702,3704,3706],{"class":1072,"line":3703},74,[1070,3705,1655],{"class":1076},[1070,3707,1434],{"class":1080},[1070,3709,3711],{"class":1072,"line":3710},75,[1070,3712,1663],{"class":1080},[1070,3714,3716,3718,3720,3722,3724,3726,3728,3730,3732,3734],{"class":1072,"line":3715},76,[1070,3717,1676],{"class":1289},[1070,3719,1526],{"class":1076},[1070,3721,1681],{"class":1424},[1070,3723,1428],{"class":1080},[1070,3725,1599],{"class":1076},[1070,3727,1688],{"class":1106},[1070,3729,1599],{"class":1076},[1070,3731,1580],{"class":1076},[1070,3733,1577],{"class":1289},[1070,3735,1434],{"class":1080},[1070,3737,3739,3741,3743,3745,3747,3749],{"class":1072,"line":3738},77,[1070,3740,1713],{"class":1424},[1070,3742,1428],{"class":1080},[1070,3744,1599],{"class":1076},[1070,3746,1720],{"class":1106},[1070,3748,1599],{"class":1076},[1070,3750,1434],{"class":1080},[1070,3752,3754,3756,3758,3760,3762,3764],{"class":1072,"line":3753},78,[1070,3755,1730],{"class":1076},[1070,3757,1733],{"class":1562},[1070,3759,1012],{"class":1080},[1070,3761,1738],{"class":1289},[1070,3763,1741],{"class":1080},[1070,3765,1744],{"class":1076},[1070,3767,3769,3771,3773,3775,3777,3779,3781,3783,3785],{"class":1072,"line":3768},79,[1070,3770,1750],{"class":1289},[1070,3772,1526],{"class":1076},[1070,3774,1529],{"class":1289},[1070,3776,1532],{"class":1076},[1070,3778,1759],{"class":1289},[1070,3780,1526],{"class":1076},[1070,3782,1764],{"class":1289},[1070,3784,1526],{"class":1076},[1070,3786,3787],{"class":1289},"message\n",[1070,3789,3791,3793,3795],{"class":1072,"line":3790},80,[1070,3792,1730],{"class":1076},[1070,3794,1788],{"class":1562},[1070,3796,1517],{"class":1076},[1070,3798,3800,3802,3804,3806,3808],{"class":1072,"line":3799},81,[1070,3801,1796],{"class":1289},[1070,3803,1526],{"class":1076},[1070,3805,1529],{"class":1289},[1070,3807,1532],{"class":1076},[1070,3809,1805],{"class":1469},[1070,3811,3813],{"class":1072,"line":3812},82,[1070,3814,1811],{"class":1076},[1070,3816,3818],{"class":1072,"line":3817},83,[1070,3819,1817],{"class":1076},[1070,3821,3823,3825,3827],{"class":1072,"line":3822},84,[1070,3824,1293],{"class":1076},[1070,3826,1405],{"class":1080},[1070,3828,1084],{"class":1076},[1055,3830,3832],{"id":3831},"_2-server-side-registration","2. Server-Side Registration",[990,3834,3835,3836,3838],{},"The server repeats the validation in earnest, rejects an email that's already registered, hashes the password before it ever touches the database, and creates the user — with ",[1014,3837,2250],{}," set automatically from context, so a registration always lands in the right tenant. Only then does it issue a token, exactly as login does:",[990,3840,3841],{},[994,3842,1838,3843],{},[1014,3844,3582],{},[1038,3846,3848],{"className":1843,"code":3847,"language":1845,"meta":1046,"style":1046},"export default defineEventHandler(async (event) => {\n  const { first_name, last_name, email, password, agree_terms } = \n    await readBody(event)\n  \n  \u002F\u002F Validate input\n  if (!email.includes('@')) {\n    throw createError({ statusCode: 400, message: 'Invalid email' })\n  }\n  if (password.length \u003C 8) {\n    throw createError({ statusCode: 400, message: 'Password too short' })\n  }\n  if (!agree_terms) {\n    throw createError({ statusCode: 400, message: 'Must agree to terms' })\n  }\n  \n  \u002F\u002F Check if email already exists\n  const existing = await cockpit.users.findByEmail(email)\n  if (existing) {\n    throw createError({\n      statusCode: 409,\n      message: 'Email already registered'\n    })\n  }\n  \n  \u002F\u002F Hash password\n  const passwordHash = await bcrypt.hash(password, 10)\n  \n  \u002F\u002F Create user (automatically scoped to the tenant)\n  const user = await cockpit.users.create({\n    first_name,\n    last_name,\n    email,\n    password_hash: passwordHash,\n    status: 'active',\n    \u002F\u002F tenant_id is set automatically from context\n  })\n  \n  \u002F\u002F Generate token\n  const token = jwt.sign(\n    {\n      user_id: user.id,\n      tenant_id: user.tenant_id,\n      email: user.email,\n      role: 'customer'\n    },\n    process.env.JWT_SECRET,\n    { expiresIn: '7d' }\n  )\n  \n  return { token, user }\n})\n",[1014,3849,3850,3872,3905,3918,3922,3927,3956,3993,3997,4017,4050,4054,4069,4102,4106,4110,4115,4142,4155,4165,4176,4189,4195,4199,4203,4208,4237,4241,4246,4270,4277,4284,4291,4302,4317,4322,4328,4332,4337,4353,4357,4371,4385,4399,4412,4416,4430,4446,4450,4454,4468],{"__ignoreMap":1046},[1070,3851,3852,3854,3856,3858,3860,3862,3864,3866,3868,3870],{"class":1072,"line":1073},[1070,3853,1852],{"class":1562},[1070,3855,1855],{"class":1562},[1070,3857,1858],{"class":1424},[1070,3859,1428],{"class":1289},[1070,3861,1863],{"class":1096},[1070,3863,1012],{"class":1076},[1070,3865,1869],{"class":1868},[1070,3867,1872],{"class":1076},[1070,3869,1514],{"class":1096},[1070,3871,1517],{"class":1076},[1070,3873,3874,3876,3878,3881,3883,3886,3888,3890,3892,3894,3896,3899,3901,3903],{"class":1072,"line":1087},[1070,3875,1881],{"class":1096},[1070,3877,1574],{"class":1076},[1070,3879,3880],{"class":1289}," first_name",[1070,3882,1580],{"class":1076},[1070,3884,3885],{"class":1289}," last_name",[1070,3887,1580],{"class":1076},[1070,3889,1641],{"class":1289},[1070,3891,1580],{"class":1076},[1070,3893,1646],{"class":1289},[1070,3895,1580],{"class":1076},[1070,3897,3898],{"class":1289}," agree_terms",[1070,3900,1586],{"class":1076},[1070,3902,1532],{"class":1076},[1070,3904,1123],{"class":1080},[1070,3906,3907,3910,3912,3914,3916],{"class":1072,"line":1114},[1070,3908,3909],{"class":1562},"    await",[1070,3911,1898],{"class":1424},[1070,3913,1428],{"class":1080},[1070,3915,1869],{"class":1289},[1070,3917,1434],{"class":1080},[1070,3919,3920],{"class":1072,"line":1126},[1070,3921,1556],{"class":1080},[1070,3923,3924],{"class":1072,"line":1143},[1070,3925,3926],{"class":1669},"  \u002F\u002F Validate input\n",[1070,3928,3929,3931,3933,3935,3937,3939,3942,3944,3946,3949,3951,3954],{"class":1072,"line":1159},[1070,3930,1947],{"class":1562},[1070,3932,1012],{"class":1080},[1070,3934,1952],{"class":1076},[1070,3936,1136],{"class":1289},[1070,3938,1526],{"class":1076},[1070,3940,3941],{"class":1424},"includes",[1070,3943,1428],{"class":1080},[1070,3945,1599],{"class":1076},[1070,3947,3948],{"class":1106},"@",[1070,3950,1599],{"class":1076},[1070,3952,3953],{"class":1080},")) ",[1070,3955,1744],{"class":1076},[1070,3957,3958,3960,3962,3964,3967,3970,3972,3975,3977,3980,3982,3984,3987,3989,3991],{"class":1072,"line":1176},[1070,3959,1964],{"class":1562},[1070,3961,1967],{"class":1424},[1070,3963,1428],{"class":1080},[1070,3965,3966],{"class":1076},"{",[1070,3968,3969],{"class":1080}," statusCode",[1070,3971,1617],{"class":1076},[1070,3973,3974],{"class":1981}," 400",[1070,3976,1580],{"class":1076},[1070,3978,3979],{"class":1080}," message",[1070,3981,1617],{"class":1076},[1070,3983,1620],{"class":1076},[1070,3985,3986],{"class":1106},"Invalid email",[1070,3988,1599],{"class":1076},[1070,3990,1586],{"class":1076},[1070,3992,1434],{"class":1080},[1070,3994,3995],{"class":1072,"line":1182},[1070,3996,1811],{"class":1076},[1070,3998,3999,4001,4003,4005,4007,4009,4011,4013,4015],{"class":1072,"line":1188},[1070,4000,1947],{"class":1562},[1070,4002,1012],{"class":1080},[1070,4004,1206],{"class":1289},[1070,4006,1526],{"class":1076},[1070,4008,3492],{"class":1289},[1070,4010,3495],{"class":1076},[1070,4012,3498],{"class":1981},[1070,4014,1741],{"class":1080},[1070,4016,1744],{"class":1076},[1070,4018,4019,4021,4023,4025,4027,4029,4031,4033,4035,4037,4039,4041,4044,4046,4048],{"class":1072,"line":1197},[1070,4020,1964],{"class":1562},[1070,4022,1967],{"class":1424},[1070,4024,1428],{"class":1080},[1070,4026,3966],{"class":1076},[1070,4028,3969],{"class":1080},[1070,4030,1617],{"class":1076},[1070,4032,3974],{"class":1981},[1070,4034,1580],{"class":1076},[1070,4036,3979],{"class":1080},[1070,4038,1617],{"class":1076},[1070,4040,1620],{"class":1076},[1070,4042,4043],{"class":1106},"Password too short",[1070,4045,1599],{"class":1076},[1070,4047,1586],{"class":1076},[1070,4049,1434],{"class":1080},[1070,4051,4052],{"class":1072,"line":1213},[1070,4053,1811],{"class":1076},[1070,4055,4056,4058,4060,4062,4065,4067],{"class":1072,"line":1228},[1070,4057,1947],{"class":1562},[1070,4059,1012],{"class":1080},[1070,4061,1952],{"class":1076},[1070,4063,4064],{"class":1289},"agree_terms",[1070,4066,1741],{"class":1080},[1070,4068,1744],{"class":1076},[1070,4070,4071,4073,4075,4077,4079,4081,4083,4085,4087,4089,4091,4093,4096,4098,4100],{"class":1072,"line":1244},[1070,4072,1964],{"class":1562},[1070,4074,1967],{"class":1424},[1070,4076,1428],{"class":1080},[1070,4078,3966],{"class":1076},[1070,4080,3969],{"class":1080},[1070,4082,1617],{"class":1076},[1070,4084,3974],{"class":1981},[1070,4086,1580],{"class":1076},[1070,4088,3979],{"class":1080},[1070,4090,1617],{"class":1076},[1070,4092,1620],{"class":1076},[1070,4094,4095],{"class":1106},"Must agree to terms",[1070,4097,1599],{"class":1076},[1070,4099,1586],{"class":1076},[1070,4101,1434],{"class":1080},[1070,4103,4104],{"class":1072,"line":1249},[1070,4105,1811],{"class":1076},[1070,4107,4108],{"class":1072,"line":1254},[1070,4109,1556],{"class":1080},[1070,4111,4112],{"class":1072,"line":1300},[1070,4113,4114],{"class":1669},"  \u002F\u002F Check if email already exists\n",[1070,4116,4117,4119,4122,4124,4126,4128,4130,4132,4134,4136,4138,4140],{"class":1072,"line":1331},[1070,4118,1881],{"class":1096},[1070,4120,4121],{"class":1289}," existing",[1070,4123,1532],{"class":1076},[1070,4125,1591],{"class":1562},[1070,4127,1926],{"class":1289},[1070,4129,1526],{"class":1076},[1070,4131,1931],{"class":1289},[1070,4133,1526],{"class":1076},[1070,4135,1936],{"class":1424},[1070,4137,1428],{"class":1080},[1070,4139,1136],{"class":1289},[1070,4141,1434],{"class":1080},[1070,4143,4144,4146,4148,4151,4153],{"class":1072,"line":1374},[1070,4145,1947],{"class":1562},[1070,4147,1012],{"class":1080},[1070,4149,4150],{"class":1289},"existing",[1070,4152,1741],{"class":1080},[1070,4154,1744],{"class":1076},[1070,4156,4157,4159,4161,4163],{"class":1072,"line":1384},[1070,4158,1964],{"class":1562},[1070,4160,1967],{"class":1424},[1070,4162,1428],{"class":1080},[1070,4164,1744],{"class":1076},[1070,4166,4167,4169,4171,4174],{"class":1072,"line":1393},[1070,4168,1976],{"class":1080},[1070,4170,1617],{"class":1076},[1070,4172,4173],{"class":1981}," 409",[1070,4175,1628],{"class":1076},[1070,4177,4178,4180,4182,4184,4187],{"class":1072,"line":1400},[1070,4179,1989],{"class":1080},[1070,4181,1617],{"class":1076},[1070,4183,1620],{"class":1076},[1070,4185,4186],{"class":1106},"Email already registered",[1070,4188,1780],{"class":1076},[1070,4190,4191,4193],{"class":1072,"line":1413},[1070,4192,1655],{"class":1076},[1070,4194,1434],{"class":1080},[1070,4196,4197],{"class":1072,"line":1437},[1070,4198,1811],{"class":1076},[1070,4200,4201],{"class":1072,"line":1455},[1070,4202,1556],{"class":1080},[1070,4204,4205],{"class":1072,"line":1475},[1070,4206,4207],{"class":1669},"  \u002F\u002F Hash password\n",[1070,4209,4210,4212,4215,4217,4219,4221,4223,4226,4228,4230,4232,4235],{"class":1072,"line":1493},[1070,4211,1881],{"class":1096},[1070,4213,4214],{"class":1289}," passwordHash",[1070,4216,1532],{"class":1076},[1070,4218,1591],{"class":1562},[1070,4220,2030],{"class":1289},[1070,4222,1526],{"class":1076},[1070,4224,4225],{"class":1424},"hash",[1070,4227,1428],{"class":1080},[1070,4229,1206],{"class":1289},[1070,4231,1580],{"class":1076},[1070,4233,4234],{"class":1981}," 10",[1070,4236,1434],{"class":1080},[1070,4238,4239],{"class":1072,"line":1498},[1070,4240,1556],{"class":1080},[1070,4242,4243],{"class":1072,"line":1520},[1070,4244,4245],{"class":1669},"  \u002F\u002F Create user (automatically scoped to the tenant)\n",[1070,4247,4248,4250,4252,4254,4256,4258,4260,4262,4264,4266,4268],{"class":1072,"line":1538},[1070,4249,1881],{"class":1096},[1070,4251,1583],{"class":1289},[1070,4253,1532],{"class":1076},[1070,4255,1591],{"class":1562},[1070,4257,1926],{"class":1289},[1070,4259,1526],{"class":1076},[1070,4261,1931],{"class":1289},[1070,4263,1526],{"class":1076},[1070,4265,2635],{"class":1424},[1070,4267,1428],{"class":1080},[1070,4269,1744],{"class":1076},[1070,4271,4272,4275],{"class":1072,"line":1553},[1070,4273,4274],{"class":1289},"    first_name",[1070,4276,1628],{"class":1076},[1070,4278,4279,4282],{"class":1072,"line":1559},[1070,4280,4281],{"class":1289},"    last_name",[1070,4283,1628],{"class":1076},[1070,4285,4286,4289],{"class":1072,"line":1568},[1070,4287,4288],{"class":1289},"    email",[1070,4290,1628],{"class":1076},[1070,4292,4293,4296,4298,4300],{"class":1072,"line":1611},[1070,4294,4295],{"class":1080},"    password_hash",[1070,4297,1617],{"class":1076},[1070,4299,4214],{"class":1289},[1070,4301,1628],{"class":1076},[1070,4303,4304,4307,4309,4311,4313,4315],{"class":1072,"line":1631},[1070,4305,4306],{"class":1080},"    status",[1070,4308,1617],{"class":1076},[1070,4310,1620],{"class":1076},[1070,4312,2137],{"class":1106},[1070,4314,1599],{"class":1076},[1070,4316,1628],{"class":1076},[1070,4318,4319],{"class":1072,"line":1652},[1070,4320,4321],{"class":1669},"    \u002F\u002F tenant_id is set automatically from context\n",[1070,4323,4324,4326],{"class":1072,"line":1660},[1070,4325,1730],{"class":1076},[1070,4327,1434],{"class":1080},[1070,4329,4330],{"class":1072,"line":1666},[1070,4331,1556],{"class":1080},[1070,4333,4334],{"class":1072,"line":1673},[1070,4335,4336],{"class":1669},"  \u002F\u002F Generate token\n",[1070,4338,4339,4341,4343,4345,4347,4349,4351],{"class":1072,"line":1699},[1070,4340,1881],{"class":1096},[1070,4342,1577],{"class":1289},[1070,4344,1532],{"class":1076},[1070,4346,2207],{"class":1289},[1070,4348,1526],{"class":1076},[1070,4350,2212],{"class":1424},[1070,4352,2215],{"class":1080},[1070,4354,4355],{"class":1072,"line":1704},[1070,4356,2220],{"class":1076},[1070,4358,4359,4361,4363,4365,4367,4369],{"class":1072,"line":1710},[1070,4360,2225],{"class":1080},[1070,4362,1617],{"class":1076},[1070,4364,1583],{"class":1289},[1070,4366,1526],{"class":1076},[1070,4368,2234],{"class":1289},[1070,4370,1628],{"class":1076},[1070,4372,4373,4375,4377,4379,4381,4383],{"class":1072,"line":1727},[1070,4374,2241],{"class":1080},[1070,4376,1617],{"class":1076},[1070,4378,1583],{"class":1289},[1070,4380,1526],{"class":1076},[1070,4382,2250],{"class":1289},[1070,4384,1628],{"class":1076},[1070,4386,4387,4389,4391,4393,4395,4397],{"class":1072,"line":1747},[1070,4388,2257],{"class":1080},[1070,4390,1617],{"class":1076},[1070,4392,1583],{"class":1289},[1070,4394,1526],{"class":1076},[1070,4396,1136],{"class":1289},[1070,4398,1628],{"class":1076},[1070,4400,4401,4403,4405,4407,4410],{"class":1072,"line":1783},[1070,4402,2272],{"class":1080},[1070,4404,1617],{"class":1076},[1070,4406,1620],{"class":1076},[1070,4408,4409],{"class":1106},"customer",[1070,4411,1780],{"class":1076},[1070,4413,4414],{"class":1072,"line":1793},[1070,4415,2286],{"class":1076},[1070,4417,4418,4420,4422,4424,4426,4428],{"class":1072,"line":1808},[1070,4419,2291],{"class":1289},[1070,4421,1526],{"class":1076},[1070,4423,2296],{"class":1289},[1070,4425,1526],{"class":1076},[1070,4427,2301],{"class":1289},[1070,4429,1628],{"class":1076},[1070,4431,4432,4434,4436,4438,4440,4442,4444],{"class":1072,"line":1814},[1070,4433,2308],{"class":1076},[1070,4435,2311],{"class":1080},[1070,4437,1617],{"class":1076},[1070,4439,1620],{"class":1076},[1070,4441,2318],{"class":1106},[1070,4443,1599],{"class":1076},[1070,4445,1649],{"class":1076},[1070,4447,4448],{"class":1072,"line":1820},[1070,4449,2327],{"class":1080},[1070,4451,4452],{"class":1072,"line":2437},[1070,4453,1556],{"class":1080},[1070,4455,4456,4458,4460,4462,4464,4466],{"class":1072,"line":2442},[1070,4457,2445],{"class":1562},[1070,4459,1574],{"class":1076},[1070,4461,1577],{"class":1289},[1070,4463,1580],{"class":1076},[1070,4465,1583],{"class":1289},[1070,4467,1649],{"class":1076},[1070,4469,4470,4472],{"class":1072,"line":2450},[1070,4471,2543],{"class":1076},[1070,4473,1434],{"class":1289},[1033,4475,4477],{"id":4476},"password-reset-flow","Password Reset Flow",[990,4479,4480,4481,4484],{},"Password reset is the most security-sensitive of the three flows, because it's a way to take over an account if it's done carelessly. The design rests on a short-lived, single-use token that's emailed to the address on file: the user requests a reset, the server emails a link containing the token, and only someone with access to that inbox can complete it. Two details do the security work — the server never reveals whether an email exists, and it stores only a ",[4482,4483,4225],"em",{}," of the token, so a leaked database can't be used to reset anyone's password. The flow runs in four steps.",[1055,4486,4488],{"id":4487},"_1-user-requests-password-reset","1. User Requests Password Reset",[990,4490,4491],{},"The first form just asks for an email. Whatever the outcome, the UI says the same reassuring thing — \"check your email\" — so it never leaks which addresses have accounts:",[1038,4493,4495],{"className":1064,"code":4494,"language":1066,"meta":1046,"style":1046},"\u003Ctemplate>\n  \u003Cform @submit=\"handleForgot\">\n    \u003Ch1>Forgot Password?\u003C\u002Fh1>\n    \u003Cp>Enter your email and we'll send you a link to reset your password.\u003C\u002Fp>\n    \u003Cinput \n      v-model=\"email\" \n      type=\"email\" \n      placeholder=\"your@email.com\" \n      required\n    \u002F>\n    \u003Cbutton type=\"submit\" :disabled=\"loading\">Send Reset Link\u003C\u002Fbutton>\n    \u003Ca href=\"\u002Flogin\">Back to Login\u003C\u002Fa>\n  \u003C\u002Fform>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nconst email = ref('')\nconst loading = ref(false)\nconst sent = ref(false)\n\nconst handleForgot = async () => {\n  loading.value = true\n  \n  try {\n    await $fetch('\u002Fapi\u002Fauth\u002Fforgot-password', {\n      method: 'POST',\n      body: { email: email.value }\n    })\n    \n    sent.value = true\n  } catch (err) {\n    error.value = 'Email not found'\n  } finally {\n    loading.value = false\n  }\n}\n\u003C\u002Fscript>\n",[1014,4496,4497,4505,4524,4542,4559,4567,4581,4595,4609,4613,4617,4654,4682,4690,4698,4702,4712,4728,4744,4761,4765,4782,4794,4798,4804,4823,4837,4857,4863,4867,4880,4894,4911,4919,4931,4935,4939],{"__ignoreMap":1046},[1070,4498,4499,4501,4503],{"class":1072,"line":1073},[1070,4500,1077],{"class":1076},[1070,4502,1081],{"class":1080},[1070,4504,1084],{"class":1076},[1070,4506,4507,4509,4511,4513,4515,4517,4520,4522],{"class":1072,"line":1087},[1070,4508,1090],{"class":1076},[1070,4510,1093],{"class":1080},[1070,4512,1097],{"class":1096},[1070,4514,1100],{"class":1076},[1070,4516,1103],{"class":1076},[1070,4518,4519],{"class":1106},"handleForgot",[1070,4521,1103],{"class":1076},[1070,4523,1084],{"class":1076},[1070,4525,4526,4528,4531,4533,4536,4538,4540],{"class":1072,"line":1114},[1070,4527,1117],{"class":1076},[1070,4529,4530],{"class":1080},"h1",[1070,4532,1286],{"class":1076},[1070,4534,4535],{"class":1289},"Forgot Password?",[1070,4537,1293],{"class":1076},[1070,4539,4530],{"class":1080},[1070,4541,1084],{"class":1076},[1070,4543,4544,4546,4548,4550,4553,4555,4557],{"class":1072,"line":1126},[1070,4545,1117],{"class":1076},[1070,4547,990],{"class":1080},[1070,4549,1286],{"class":1076},[1070,4551,4552],{"class":1289},"Enter your email and we'll send you a link to reset your password.",[1070,4554,1293],{"class":1076},[1070,4556,990],{"class":1080},[1070,4558,1084],{"class":1076},[1070,4560,4561,4563,4565],{"class":1072,"line":1143},[1070,4562,1117],{"class":1076},[1070,4564,1120],{"class":1080},[1070,4566,1123],{"class":1076},[1070,4568,4569,4571,4573,4575,4577,4579],{"class":1072,"line":1159},[1070,4570,1129],{"class":1096},[1070,4572,1100],{"class":1076},[1070,4574,1103],{"class":1076},[1070,4576,1136],{"class":1106},[1070,4578,1103],{"class":1076},[1070,4580,1123],{"class":1076},[1070,4582,4583,4585,4587,4589,4591,4593],{"class":1072,"line":1176},[1070,4584,1146],{"class":1096},[1070,4586,1100],{"class":1076},[1070,4588,1103],{"class":1076},[1070,4590,1136],{"class":1106},[1070,4592,1103],{"class":1076},[1070,4594,1123],{"class":1076},[1070,4596,4597,4599,4601,4603,4605,4607],{"class":1072,"line":1182},[1070,4598,1162],{"class":1096},[1070,4600,1100],{"class":1076},[1070,4602,1103],{"class":1076},[1070,4604,1169],{"class":1106},[1070,4606,1103],{"class":1076},[1070,4608,1123],{"class":1076},[1070,4610,4611],{"class":1072,"line":1188},[1070,4612,1179],{"class":1096},[1070,4614,4615],{"class":1072,"line":1197},[1070,4616,1185],{"class":1076},[1070,4618,4619,4621,4623,4625,4627,4629,4631,4633,4635,4637,4639,4641,4643,4645,4648,4650,4652],{"class":1072,"line":1213},[1070,4620,1117],{"class":1076},[1070,4622,1259],{"class":1080},[1070,4624,1262],{"class":1096},[1070,4626,1100],{"class":1076},[1070,4628,1103],{"class":1076},[1070,4630,1269],{"class":1106},[1070,4632,1103],{"class":1076},[1070,4634,1274],{"class":1096},[1070,4636,1100],{"class":1076},[1070,4638,1103],{"class":1076},[1070,4640,1281],{"class":1106},[1070,4642,1103],{"class":1076},[1070,4644,1286],{"class":1076},[1070,4646,4647],{"class":1289},"Send Reset Link",[1070,4649,1293],{"class":1076},[1070,4651,1259],{"class":1080},[1070,4653,1084],{"class":1076},[1070,4655,4656,4658,4660,4662,4664,4666,4669,4671,4673,4676,4678,4680],{"class":1072,"line":1228},[1070,4657,1117],{"class":1076},[1070,4659,1305],{"class":1080},[1070,4661,1308],{"class":1096},[1070,4663,1100],{"class":1076},[1070,4665,1103],{"class":1076},[1070,4667,4668],{"class":1106},"\u002Flogin",[1070,4670,1103],{"class":1076},[1070,4672,1286],{"class":1076},[1070,4674,4675],{"class":1289},"Back to Login",[1070,4677,1293],{"class":1076},[1070,4679,1305],{"class":1080},[1070,4681,1084],{"class":1076},[1070,4683,4684,4686,4688],{"class":1072,"line":1244},[1070,4685,1377],{"class":1076},[1070,4687,1093],{"class":1080},[1070,4689,1084],{"class":1076},[1070,4691,4692,4694,4696],{"class":1072,"line":1249},[1070,4693,1293],{"class":1076},[1070,4695,1081],{"class":1080},[1070,4697,1084],{"class":1076},[1070,4699,4700],{"class":1072,"line":1254},[1070,4701,1397],{"emptyLinePlaceholder":1396},[1070,4703,4704,4706,4708,4710],{"class":1072,"line":1300},[1070,4705,1077],{"class":1076},[1070,4707,1405],{"class":1080},[1070,4709,1408],{"class":1096},[1070,4711,1084],{"class":1076},[1070,4713,4714,4716,4718,4720,4722,4724,4726],{"class":1072,"line":1331},[1070,4715,1416],{"class":1096},[1070,4717,1419],{"class":1289},[1070,4719,1100],{"class":1076},[1070,4721,1425],{"class":1424},[1070,4723,1428],{"class":1289},[1070,4725,1431],{"class":1076},[1070,4727,1434],{"class":1289},[1070,4729,4730,4732,4734,4736,4738,4740,4742],{"class":1072,"line":1374},[1070,4731,1416],{"class":1096},[1070,4733,1460],{"class":1289},[1070,4735,1100],{"class":1076},[1070,4737,1425],{"class":1424},[1070,4739,1428],{"class":1289},[1070,4741,1470],{"class":1469},[1070,4743,1434],{"class":1289},[1070,4745,4746,4748,4751,4753,4755,4757,4759],{"class":1072,"line":1384},[1070,4747,1416],{"class":1096},[1070,4749,4750],{"class":1289}," sent ",[1070,4752,1100],{"class":1076},[1070,4754,1425],{"class":1424},[1070,4756,1428],{"class":1289},[1070,4758,1470],{"class":1469},[1070,4760,1434],{"class":1289},[1070,4762,4763],{"class":1072,"line":1393},[1070,4764,1397],{"emptyLinePlaceholder":1396},[1070,4766,4767,4769,4772,4774,4776,4778,4780],{"class":1072,"line":1400},[1070,4768,1416],{"class":1096},[1070,4770,4771],{"class":1289}," handleForgot ",[1070,4773,1100],{"class":1076},[1070,4775,1508],{"class":1096},[1070,4777,1511],{"class":1076},[1070,4779,1514],{"class":1096},[1070,4781,1517],{"class":1076},[1070,4783,4784,4786,4788,4790,4792],{"class":1072,"line":1413},[1070,4785,1523],{"class":1289},[1070,4787,1526],{"class":1076},[1070,4789,1529],{"class":1289},[1070,4791,1532],{"class":1076},[1070,4793,1535],{"class":1469},[1070,4795,4796],{"class":1072,"line":1437},[1070,4797,1556],{"class":1080},[1070,4799,4800,4802],{"class":1072,"line":1455},[1070,4801,1563],{"class":1562},[1070,4803,1517],{"class":1076},[1070,4805,4806,4808,4810,4812,4814,4817,4819,4821],{"class":1072,"line":1475},[1070,4807,3909],{"class":1562},[1070,4809,1594],{"class":1424},[1070,4811,1428],{"class":1080},[1070,4813,1599],{"class":1076},[1070,4815,4816],{"class":1106},"\u002Fapi\u002Fauth\u002Fforgot-password",[1070,4818,1599],{"class":1076},[1070,4820,1580],{"class":1076},[1070,4822,1517],{"class":1076},[1070,4824,4825,4827,4829,4831,4833,4835],{"class":1072,"line":1493},[1070,4826,1614],{"class":1080},[1070,4828,1617],{"class":1076},[1070,4830,1620],{"class":1076},[1070,4832,1623],{"class":1106},[1070,4834,1599],{"class":1076},[1070,4836,1628],{"class":1076},[1070,4838,4839,4841,4843,4845,4847,4849,4851,4853,4855],{"class":1072,"line":1498},[1070,4840,1634],{"class":1080},[1070,4842,1617],{"class":1076},[1070,4844,1574],{"class":1076},[1070,4846,1641],{"class":1080},[1070,4848,1617],{"class":1076},[1070,4850,1641],{"class":1289},[1070,4852,1526],{"class":1076},[1070,4854,1529],{"class":1289},[1070,4856,1649],{"class":1076},[1070,4858,4859,4861],{"class":1072,"line":1520},[1070,4860,1655],{"class":1076},[1070,4862,1434],{"class":1080},[1070,4864,4865],{"class":1072,"line":1538},[1070,4866,1663],{"class":1080},[1070,4868,4869,4872,4874,4876,4878],{"class":1072,"line":1553},[1070,4870,4871],{"class":1289},"    sent",[1070,4873,1526],{"class":1076},[1070,4875,1529],{"class":1289},[1070,4877,1532],{"class":1076},[1070,4879,1535],{"class":1469},[1070,4881,4882,4884,4886,4888,4890,4892],{"class":1072,"line":1559},[1070,4883,1730],{"class":1076},[1070,4885,1733],{"class":1562},[1070,4887,1012],{"class":1080},[1070,4889,1738],{"class":1289},[1070,4891,1741],{"class":1080},[1070,4893,1744],{"class":1076},[1070,4895,4896,4898,4900,4902,4904,4906,4909],{"class":1072,"line":1568},[1070,4897,1750],{"class":1289},[1070,4899,1526],{"class":1076},[1070,4901,1529],{"class":1289},[1070,4903,1532],{"class":1076},[1070,4905,1620],{"class":1076},[1070,4907,4908],{"class":1106},"Email not found",[1070,4910,1780],{"class":1076},[1070,4912,4913,4915,4917],{"class":1072,"line":1611},[1070,4914,1730],{"class":1076},[1070,4916,1788],{"class":1562},[1070,4918,1517],{"class":1076},[1070,4920,4921,4923,4925,4927,4929],{"class":1072,"line":1631},[1070,4922,1796],{"class":1289},[1070,4924,1526],{"class":1076},[1070,4926,1529],{"class":1289},[1070,4928,1532],{"class":1076},[1070,4930,1805],{"class":1469},[1070,4932,4933],{"class":1072,"line":1652},[1070,4934,1811],{"class":1076},[1070,4936,4937],{"class":1072,"line":1660},[1070,4938,1817],{"class":1076},[1070,4940,4941,4943,4945],{"class":1072,"line":1666},[1070,4942,1293],{"class":1076},[1070,4944,1405],{"class":1080},[1070,4946,1084],{"class":1076},[1055,4948,4950],{"id":4949},"_2-server-generates-reset-token","2. Server Generates Reset Token",[990,4952,4953],{},[994,4954,1838,4955],{},[1014,4956,4816],{},[1038,4958,4960],{"className":1843,"code":4959,"language":1845,"meta":1046,"style":1046},"export default defineEventHandler(async (event) => {\n  const { email } = await readBody(event)\n  \n  const user = await cockpit.users.findByEmail(email)\n  if (!user) {\n    \u002F\u002F Don't reveal if email exists (security)\n    return { message: 'Check your email for reset link' }\n  }\n  \n  \u002F\u002F Generate reset token (short-lived, one-time use)\n  const resetToken = crypto.randomBytes(32).toString('hex')\n  const resetTokenHash = crypto.createHash('sha256').update(resetToken).digest('hex')\n  \n  \u002F\u002F Store in DB (expires in 1 hour)\n  await cockpit.passwordReset.create({\n    user_id: user.id,\n    token_hash: resetTokenHash,\n    expires_at: new Date(Date.now() + 60 * 60 * 1000)\n  })\n  \n  \u002F\u002F Send email with reset link\n  const resetUrl = `https:\u002F\u002Fstorefront.example.com\u002Freset-password?token=${resetToken}`\n  await sendEmail({\n    to: user.email,\n    subject: 'Reset Your Password',\n    html: `\n      \u003Cp>Click the link below to reset your password (expires in 1 hour):\u003C\u002Fp>\n      \u003Ca href=\"${resetUrl}\">${resetUrl}\u003C\u002Fa>\n    `\n  })\n  \n  return { message: 'Reset email sent' }\n})\n",[1014,4961,4962,4984,5006,5010,5036,5050,5055,5075,5079,5083,5088,5128,5182,5186,5191,5211,5226,5237,5279,5285,5289,5294,5314,5325,5340,5356,5366,5371,5395,5400,5406,5410,5429],{"__ignoreMap":1046},[1070,4963,4964,4966,4968,4970,4972,4974,4976,4978,4980,4982],{"class":1072,"line":1073},[1070,4965,1852],{"class":1562},[1070,4967,1855],{"class":1562},[1070,4969,1858],{"class":1424},[1070,4971,1428],{"class":1289},[1070,4973,1863],{"class":1096},[1070,4975,1012],{"class":1076},[1070,4977,1869],{"class":1868},[1070,4979,1872],{"class":1076},[1070,4981,1514],{"class":1096},[1070,4983,1517],{"class":1076},[1070,4985,4986,4988,4990,4992,4994,4996,4998,5000,5002,5004],{"class":1072,"line":1087},[1070,4987,1881],{"class":1096},[1070,4989,1574],{"class":1076},[1070,4991,1641],{"class":1289},[1070,4993,1586],{"class":1076},[1070,4995,1532],{"class":1076},[1070,4997,1591],{"class":1562},[1070,4999,1898],{"class":1424},[1070,5001,1428],{"class":1080},[1070,5003,1869],{"class":1289},[1070,5005,1434],{"class":1080},[1070,5007,5008],{"class":1072,"line":1114},[1070,5009,1556],{"class":1080},[1070,5011,5012,5014,5016,5018,5020,5022,5024,5026,5028,5030,5032,5034],{"class":1072,"line":1126},[1070,5013,1881],{"class":1096},[1070,5015,1583],{"class":1289},[1070,5017,1532],{"class":1076},[1070,5019,1591],{"class":1562},[1070,5021,1926],{"class":1289},[1070,5023,1526],{"class":1076},[1070,5025,1931],{"class":1289},[1070,5027,1526],{"class":1076},[1070,5029,1936],{"class":1424},[1070,5031,1428],{"class":1080},[1070,5033,1136],{"class":1289},[1070,5035,1434],{"class":1080},[1070,5037,5038,5040,5042,5044,5046,5048],{"class":1072,"line":1143},[1070,5039,1947],{"class":1562},[1070,5041,1012],{"class":1080},[1070,5043,1952],{"class":1076},[1070,5045,1955],{"class":1289},[1070,5047,1741],{"class":1080},[1070,5049,1744],{"class":1076},[1070,5051,5052],{"class":1072,"line":1159},[1070,5053,5054],{"class":1669},"    \u002F\u002F Don't reveal if email exists (security)\n",[1070,5056,5057,5060,5062,5064,5066,5068,5071,5073],{"class":1072,"line":1176},[1070,5058,5059],{"class":1562},"    return",[1070,5061,1574],{"class":1076},[1070,5063,3979],{"class":1080},[1070,5065,1617],{"class":1076},[1070,5067,1620],{"class":1076},[1070,5069,5070],{"class":1106},"Check your email for reset link",[1070,5072,1599],{"class":1076},[1070,5074,1649],{"class":1076},[1070,5076,5077],{"class":1072,"line":1182},[1070,5078,1811],{"class":1076},[1070,5080,5081],{"class":1072,"line":1188},[1070,5082,1556],{"class":1080},[1070,5084,5085],{"class":1072,"line":1197},[1070,5086,5087],{"class":1669},"  \u002F\u002F Generate reset token (short-lived, one-time use)\n",[1070,5089,5090,5092,5095,5097,5100,5102,5105,5107,5110,5112,5114,5117,5119,5121,5124,5126],{"class":1072,"line":1213},[1070,5091,1881],{"class":1096},[1070,5093,5094],{"class":1289}," resetToken",[1070,5096,1532],{"class":1076},[1070,5098,5099],{"class":1289}," crypto",[1070,5101,1526],{"class":1076},[1070,5103,5104],{"class":1424},"randomBytes",[1070,5106,1428],{"class":1080},[1070,5108,5109],{"class":1981},"32",[1070,5111,1872],{"class":1080},[1070,5113,1526],{"class":1076},[1070,5115,5116],{"class":1424},"toString",[1070,5118,1428],{"class":1080},[1070,5120,1599],{"class":1076},[1070,5122,5123],{"class":1106},"hex",[1070,5125,1599],{"class":1076},[1070,5127,1434],{"class":1080},[1070,5129,5130,5132,5135,5137,5139,5141,5144,5146,5148,5151,5153,5155,5157,5160,5162,5165,5167,5169,5172,5174,5176,5178,5180],{"class":1072,"line":1228},[1070,5131,1881],{"class":1096},[1070,5133,5134],{"class":1289}," resetTokenHash",[1070,5136,1532],{"class":1076},[1070,5138,5099],{"class":1289},[1070,5140,1526],{"class":1076},[1070,5142,5143],{"class":1424},"createHash",[1070,5145,1428],{"class":1080},[1070,5147,1599],{"class":1076},[1070,5149,5150],{"class":1106},"sha256",[1070,5152,1599],{"class":1076},[1070,5154,1872],{"class":1080},[1070,5156,1526],{"class":1076},[1070,5158,5159],{"class":1424},"update",[1070,5161,1428],{"class":1080},[1070,5163,5164],{"class":1289},"resetToken",[1070,5166,1872],{"class":1080},[1070,5168,1526],{"class":1076},[1070,5170,5171],{"class":1424},"digest",[1070,5173,1428],{"class":1080},[1070,5175,1599],{"class":1076},[1070,5177,5123],{"class":1106},[1070,5179,1599],{"class":1076},[1070,5181,1434],{"class":1080},[1070,5183,5184],{"class":1072,"line":1244},[1070,5185,1556],{"class":1080},[1070,5187,5188],{"class":1072,"line":1249},[1070,5189,5190],{"class":1669},"  \u002F\u002F Store in DB (expires in 1 hour)\n",[1070,5192,5193,5196,5198,5200,5203,5205,5207,5209],{"class":1072,"line":1254},[1070,5194,5195],{"class":1562},"  await",[1070,5197,1926],{"class":1289},[1070,5199,1526],{"class":1076},[1070,5201,5202],{"class":1289},"passwordReset",[1070,5204,1526],{"class":1076},[1070,5206,2635],{"class":1424},[1070,5208,1428],{"class":1080},[1070,5210,1744],{"class":1076},[1070,5212,5213,5216,5218,5220,5222,5224],{"class":1072,"line":1300},[1070,5214,5215],{"class":1080},"    user_id",[1070,5217,1617],{"class":1076},[1070,5219,1583],{"class":1289},[1070,5221,1526],{"class":1076},[1070,5223,2234],{"class":1289},[1070,5225,1628],{"class":1076},[1070,5227,5228,5231,5233,5235],{"class":1072,"line":1331},[1070,5229,5230],{"class":1080},"    token_hash",[1070,5232,1617],{"class":1076},[1070,5234,5134],{"class":1289},[1070,5236,1628],{"class":1076},[1070,5238,5239,5242,5244,5247,5250,5252,5255,5257,5260,5263,5266,5268,5270,5272,5274,5277],{"class":1072,"line":1374},[1070,5240,5241],{"class":1080},"    expires_at",[1070,5243,1617],{"class":1076},[1070,5245,5246],{"class":1076}," new",[1070,5248,5249],{"class":1424}," Date",[1070,5251,1428],{"class":1080},[1070,5253,5254],{"class":1289},"Date",[1070,5256,1526],{"class":1076},[1070,5258,5259],{"class":1424},"now",[1070,5261,5262],{"class":1080},"() ",[1070,5264,5265],{"class":1076},"+",[1070,5267,2421],{"class":1981},[1070,5269,2413],{"class":1076},[1070,5271,2421],{"class":1981},[1070,5273,2413],{"class":1076},[1070,5275,5276],{"class":1981}," 1000",[1070,5278,1434],{"class":1080},[1070,5280,5281,5283],{"class":1072,"line":1384},[1070,5282,1730],{"class":1076},[1070,5284,1434],{"class":1080},[1070,5286,5287],{"class":1072,"line":1393},[1070,5288,1556],{"class":1080},[1070,5290,5291],{"class":1072,"line":1400},[1070,5292,5293],{"class":1669},"  \u002F\u002F Send email with reset link\n",[1070,5295,5296,5298,5301,5303,5305,5308,5310,5312],{"class":1072,"line":1413},[1070,5297,1881],{"class":1096},[1070,5299,5300],{"class":1289}," resetUrl",[1070,5302,1532],{"class":1076},[1070,5304,2741],{"class":1076},[1070,5306,5307],{"class":1106},"https:\u002F\u002Fstorefront.example.com\u002Freset-password?token=",[1070,5309,2747],{"class":1076},[1070,5311,5164],{"class":1289},[1070,5313,2752],{"class":1076},[1070,5315,5316,5318,5321,5323],{"class":1072,"line":1437},[1070,5317,5195],{"class":1562},[1070,5319,5320],{"class":1424}," sendEmail",[1070,5322,1428],{"class":1080},[1070,5324,1744],{"class":1076},[1070,5326,5327,5330,5332,5334,5336,5338],{"class":1072,"line":1455},[1070,5328,5329],{"class":1080},"    to",[1070,5331,1617],{"class":1076},[1070,5333,1583],{"class":1289},[1070,5335,1526],{"class":1076},[1070,5337,1136],{"class":1289},[1070,5339,1628],{"class":1076},[1070,5341,5342,5345,5347,5349,5352,5354],{"class":1072,"line":1475},[1070,5343,5344],{"class":1080},"    subject",[1070,5346,1617],{"class":1076},[1070,5348,1620],{"class":1076},[1070,5350,5351],{"class":1106},"Reset Your Password",[1070,5353,1599],{"class":1076},[1070,5355,1628],{"class":1076},[1070,5357,5358,5361,5363],{"class":1072,"line":1493},[1070,5359,5360],{"class":1080},"    html",[1070,5362,1617],{"class":1076},[1070,5364,5365],{"class":1076}," `\n",[1070,5367,5368],{"class":1072,"line":1498},[1070,5369,5370],{"class":1106},"      \u003Cp>Click the link below to reset your password (expires in 1 hour):\u003C\u002Fp>\n",[1070,5372,5373,5376,5378,5381,5383,5386,5388,5390,5392],{"class":1072,"line":1520},[1070,5374,5375],{"class":1106},"      \u003Ca href=\"",[1070,5377,2747],{"class":1076},[1070,5379,5380],{"class":1289},"resetUrl",[1070,5382,2543],{"class":1076},[1070,5384,5385],{"class":1106},"\">",[1070,5387,2747],{"class":1076},[1070,5389,5380],{"class":1289},[1070,5391,2543],{"class":1076},[1070,5393,5394],{"class":1106},"\u003C\u002Fa>\n",[1070,5396,5397],{"class":1072,"line":1538},[1070,5398,5399],{"class":1076},"    `\n",[1070,5401,5402,5404],{"class":1072,"line":1553},[1070,5403,1730],{"class":1076},[1070,5405,1434],{"class":1080},[1070,5407,5408],{"class":1072,"line":1559},[1070,5409,1556],{"class":1080},[1070,5411,5412,5414,5416,5418,5420,5422,5425,5427],{"class":1072,"line":1568},[1070,5413,2445],{"class":1562},[1070,5415,1574],{"class":1076},[1070,5417,3979],{"class":1080},[1070,5419,1617],{"class":1076},[1070,5421,1620],{"class":1076},[1070,5423,5424],{"class":1106},"Reset email sent",[1070,5426,1599],{"class":1076},[1070,5428,1649],{"class":1076},[1070,5430,5431,5433],{"class":1072,"line":1611},[1070,5432,2543],{"class":1076},[1070,5434,1434],{"class":1289},[1055,5436,5438],{"id":5437},"_3-user-clicks-reset-link-sets-new-password","3. User Clicks Reset Link & Sets New Password",[990,5440,5441],{},[994,5442,5443],{},"Form (pages\u002Freset-password.vue):",[1038,5445,5447],{"className":1064,"code":5446,"language":1066,"meta":1046,"style":1046},"\u003Ctemplate>\n  \u003Cform @submit=\"handleResetPassword\">\n    \u003Ch1>Reset Password\u003C\u002Fh1>\n    \u003Cinput \n      v-model=\"newPassword\" \n      type=\"password\" \n      placeholder=\"New Password\" \n      minlength=\"8\"\n      required\n    \u002F>\n    \u003Cinput \n      v-model=\"confirmPassword\" \n      type=\"password\" \n      placeholder=\"Confirm Password\" \n      required\n    \u002F>\n    \u003Cbutton type=\"submit\" :disabled=\"loading\">Set Password\u003C\u002Fbutton>\n  \u003C\u002Fform>\n\u003C\u002Ftemplate>\n\n\u003Cscript setup>\nconst route = useRoute()\nconst resetToken = route.query.token\n\nconst newPassword = ref('')\nconst confirmPassword = ref('')\nconst loading = ref(false)\n\nconst handleResetPassword = async () => {\n  if (newPassword.value !== confirmPassword.value) {\n    error.value = 'Passwords do not match'\n    return\n  }\n  \n  loading.value = true\n  \n  try {\n    await $fetch('\u002Fapi\u002Fauth\u002Freset-password', {\n      method: 'POST',\n      body: {\n        reset_token: resetToken,\n        new_password: newPassword.value\n      }\n    })\n    \n    navigateTo('\u002Flogin?message=Password reset successful')\n  } catch (err) {\n    error.value = 'Reset link expired or invalid'\n  } finally {\n    loading.value = false\n  }\n}\n\u003C\u002Fscript>\n",[1014,5448,5449,5457,5476,5493,5501,5516,5530,5545,5557,5561,5565,5573,5588,5602,5616,5620,5624,5661,5669,5677,5681,5691,5706,5728,5732,5749,5766,5782,5786,5803,5828,5844,5848,5852,5856,5868,5872,5878,5897,5911,5919,5930,5944,5948,5954,5958,5973,5987,6004,6012,6024,6028,6032],{"__ignoreMap":1046},[1070,5450,5451,5453,5455],{"class":1072,"line":1073},[1070,5452,1077],{"class":1076},[1070,5454,1081],{"class":1080},[1070,5456,1084],{"class":1076},[1070,5458,5459,5461,5463,5465,5467,5469,5472,5474],{"class":1072,"line":1087},[1070,5460,1090],{"class":1076},[1070,5462,1093],{"class":1080},[1070,5464,1097],{"class":1096},[1070,5466,1100],{"class":1076},[1070,5468,1103],{"class":1076},[1070,5470,5471],{"class":1106},"handleResetPassword",[1070,5473,1103],{"class":1076},[1070,5475,1084],{"class":1076},[1070,5477,5478,5480,5482,5484,5487,5489,5491],{"class":1072,"line":1114},[1070,5479,1117],{"class":1076},[1070,5481,4530],{"class":1080},[1070,5483,1286],{"class":1076},[1070,5485,5486],{"class":1289},"Reset Password",[1070,5488,1293],{"class":1076},[1070,5490,4530],{"class":1080},[1070,5492,1084],{"class":1076},[1070,5494,5495,5497,5499],{"class":1072,"line":1126},[1070,5496,1117],{"class":1076},[1070,5498,1120],{"class":1080},[1070,5500,1123],{"class":1076},[1070,5502,5503,5505,5507,5509,5512,5514],{"class":1072,"line":1143},[1070,5504,1129],{"class":1096},[1070,5506,1100],{"class":1076},[1070,5508,1103],{"class":1076},[1070,5510,5511],{"class":1106},"newPassword",[1070,5513,1103],{"class":1076},[1070,5515,1123],{"class":1076},[1070,5517,5518,5520,5522,5524,5526,5528],{"class":1072,"line":1159},[1070,5519,1146],{"class":1096},[1070,5521,1100],{"class":1076},[1070,5523,1103],{"class":1076},[1070,5525,1206],{"class":1106},[1070,5527,1103],{"class":1076},[1070,5529,1123],{"class":1076},[1070,5531,5532,5534,5536,5538,5541,5543],{"class":1072,"line":1176},[1070,5533,1162],{"class":1096},[1070,5535,1100],{"class":1076},[1070,5537,1103],{"class":1076},[1070,5539,5540],{"class":1106},"New Password",[1070,5542,1103],{"class":1076},[1070,5544,1123],{"class":1076},[1070,5546,5547,5549,5551,5553,5555],{"class":1072,"line":1182},[1070,5548,3079],{"class":1096},[1070,5550,1100],{"class":1076},[1070,5552,1103],{"class":1076},[1070,5554,3086],{"class":1106},[1070,5556,3089],{"class":1076},[1070,5558,5559],{"class":1072,"line":1188},[1070,5560,1179],{"class":1096},[1070,5562,5563],{"class":1072,"line":1197},[1070,5564,1185],{"class":1076},[1070,5566,5567,5569,5571],{"class":1072,"line":1213},[1070,5568,1117],{"class":1076},[1070,5570,1120],{"class":1080},[1070,5572,1123],{"class":1076},[1070,5574,5575,5577,5579,5581,5584,5586],{"class":1072,"line":1228},[1070,5576,1129],{"class":1096},[1070,5578,1100],{"class":1076},[1070,5580,1103],{"class":1076},[1070,5582,5583],{"class":1106},"confirmPassword",[1070,5585,1103],{"class":1076},[1070,5587,1123],{"class":1076},[1070,5589,5590,5592,5594,5596,5598,5600],{"class":1072,"line":1244},[1070,5591,1146],{"class":1096},[1070,5593,1100],{"class":1076},[1070,5595,1103],{"class":1076},[1070,5597,1206],{"class":1106},[1070,5599,1103],{"class":1076},[1070,5601,1123],{"class":1076},[1070,5603,5604,5606,5608,5610,5612,5614],{"class":1072,"line":1249},[1070,5605,1162],{"class":1096},[1070,5607,1100],{"class":1076},[1070,5609,1103],{"class":1076},[1070,5611,3145],{"class":1106},[1070,5613,1103],{"class":1076},[1070,5615,1123],{"class":1076},[1070,5617,5618],{"class":1072,"line":1254},[1070,5619,1179],{"class":1096},[1070,5621,5622],{"class":1072,"line":1300},[1070,5623,1185],{"class":1076},[1070,5625,5626,5628,5630,5632,5634,5636,5638,5640,5642,5644,5646,5648,5650,5652,5655,5657,5659],{"class":1072,"line":1331},[1070,5627,1117],{"class":1076},[1070,5629,1259],{"class":1080},[1070,5631,1262],{"class":1096},[1070,5633,1100],{"class":1076},[1070,5635,1103],{"class":1076},[1070,5637,1269],{"class":1106},[1070,5639,1103],{"class":1076},[1070,5641,1274],{"class":1096},[1070,5643,1100],{"class":1076},[1070,5645,1103],{"class":1076},[1070,5647,1281],{"class":1106},[1070,5649,1103],{"class":1076},[1070,5651,1286],{"class":1076},[1070,5653,5654],{"class":1289},"Set Password",[1070,5656,1293],{"class":1076},[1070,5658,1259],{"class":1080},[1070,5660,1084],{"class":1076},[1070,5662,5663,5665,5667],{"class":1072,"line":1374},[1070,5664,1377],{"class":1076},[1070,5666,1093],{"class":1080},[1070,5668,1084],{"class":1076},[1070,5670,5671,5673,5675],{"class":1072,"line":1384},[1070,5672,1293],{"class":1076},[1070,5674,1081],{"class":1080},[1070,5676,1084],{"class":1076},[1070,5678,5679],{"class":1072,"line":1393},[1070,5680,1397],{"emptyLinePlaceholder":1396},[1070,5682,5683,5685,5687,5689],{"class":1072,"line":1400},[1070,5684,1077],{"class":1076},[1070,5686,1405],{"class":1080},[1070,5688,1408],{"class":1096},[1070,5690,1084],{"class":1076},[1070,5692,5693,5695,5698,5700,5703],{"class":1072,"line":1413},[1070,5694,1416],{"class":1096},[1070,5696,5697],{"class":1289}," route ",[1070,5699,1100],{"class":1076},[1070,5701,5702],{"class":1424}," useRoute",[1070,5704,5705],{"class":1289},"()\n",[1070,5707,5708,5710,5713,5715,5718,5720,5723,5725],{"class":1072,"line":1437},[1070,5709,1416],{"class":1096},[1070,5711,5712],{"class":1289}," resetToken ",[1070,5714,1100],{"class":1076},[1070,5716,5717],{"class":1289}," route",[1070,5719,1526],{"class":1076},[1070,5721,5722],{"class":1289},"query",[1070,5724,1526],{"class":1076},[1070,5726,5727],{"class":1289},"token\n",[1070,5729,5730],{"class":1072,"line":1455},[1070,5731,1397],{"emptyLinePlaceholder":1396},[1070,5733,5734,5736,5739,5741,5743,5745,5747],{"class":1072,"line":1475},[1070,5735,1416],{"class":1096},[1070,5737,5738],{"class":1289}," newPassword ",[1070,5740,1100],{"class":1076},[1070,5742,1425],{"class":1424},[1070,5744,1428],{"class":1289},[1070,5746,1431],{"class":1076},[1070,5748,1434],{"class":1289},[1070,5750,5751,5753,5756,5758,5760,5762,5764],{"class":1072,"line":1493},[1070,5752,1416],{"class":1096},[1070,5754,5755],{"class":1289}," confirmPassword ",[1070,5757,1100],{"class":1076},[1070,5759,1425],{"class":1424},[1070,5761,1428],{"class":1289},[1070,5763,1431],{"class":1076},[1070,5765,1434],{"class":1289},[1070,5767,5768,5770,5772,5774,5776,5778,5780],{"class":1072,"line":1498},[1070,5769,1416],{"class":1096},[1070,5771,1460],{"class":1289},[1070,5773,1100],{"class":1076},[1070,5775,1425],{"class":1424},[1070,5777,1428],{"class":1289},[1070,5779,1470],{"class":1469},[1070,5781,1434],{"class":1289},[1070,5783,5784],{"class":1072,"line":1520},[1070,5785,1397],{"emptyLinePlaceholder":1396},[1070,5787,5788,5790,5793,5795,5797,5799,5801],{"class":1072,"line":1538},[1070,5789,1416],{"class":1096},[1070,5791,5792],{"class":1289}," handleResetPassword ",[1070,5794,1100],{"class":1076},[1070,5796,1508],{"class":1096},[1070,5798,1511],{"class":1076},[1070,5800,1514],{"class":1096},[1070,5802,1517],{"class":1076},[1070,5804,5805,5807,5809,5811,5813,5815,5817,5820,5822,5824,5826],{"class":1072,"line":1553},[1070,5806,1947],{"class":1562},[1070,5808,1012],{"class":1080},[1070,5810,5511],{"class":1289},[1070,5812,1526],{"class":1076},[1070,5814,1529],{"class":1289},[1070,5816,2132],{"class":1076},[1070,5818,5819],{"class":1289}," confirmPassword",[1070,5821,1526],{"class":1076},[1070,5823,1529],{"class":1289},[1070,5825,1741],{"class":1080},[1070,5827,1744],{"class":1076},[1070,5829,5830,5832,5834,5836,5838,5840,5842],{"class":1072,"line":1559},[1070,5831,1750],{"class":1289},[1070,5833,1526],{"class":1076},[1070,5835,1529],{"class":1289},[1070,5837,1532],{"class":1076},[1070,5839,1620],{"class":1076},[1070,5841,3460],{"class":1106},[1070,5843,1780],{"class":1076},[1070,5845,5846],{"class":1072,"line":1568},[1070,5847,3467],{"class":1562},[1070,5849,5850],{"class":1072,"line":1611},[1070,5851,1811],{"class":1076},[1070,5853,5854],{"class":1072,"line":1631},[1070,5855,1556],{"class":1080},[1070,5857,5858,5860,5862,5864,5866],{"class":1072,"line":1652},[1070,5859,1523],{"class":1289},[1070,5861,1526],{"class":1076},[1070,5863,1529],{"class":1289},[1070,5865,1532],{"class":1076},[1070,5867,1535],{"class":1469},[1070,5869,5870],{"class":1072,"line":1660},[1070,5871,1556],{"class":1080},[1070,5873,5874,5876],{"class":1072,"line":1666},[1070,5875,1563],{"class":1562},[1070,5877,1517],{"class":1076},[1070,5879,5880,5882,5884,5886,5888,5891,5893,5895],{"class":1072,"line":1673},[1070,5881,3909],{"class":1562},[1070,5883,1594],{"class":1424},[1070,5885,1428],{"class":1080},[1070,5887,1599],{"class":1076},[1070,5889,5890],{"class":1106},"\u002Fapi\u002Fauth\u002Freset-password",[1070,5892,1599],{"class":1076},[1070,5894,1580],{"class":1076},[1070,5896,1517],{"class":1076},[1070,5898,5899,5901,5903,5905,5907,5909],{"class":1072,"line":1699},[1070,5900,1614],{"class":1080},[1070,5902,1617],{"class":1076},[1070,5904,1620],{"class":1076},[1070,5906,1623],{"class":1106},[1070,5908,1599],{"class":1076},[1070,5910,1628],{"class":1076},[1070,5912,5913,5915,5917],{"class":1072,"line":1704},[1070,5914,1634],{"class":1080},[1070,5916,1617],{"class":1076},[1070,5918,1517],{"class":1076},[1070,5920,5921,5924,5926,5928],{"class":1072,"line":1710},[1070,5922,5923],{"class":1080},"        reset_token",[1070,5925,1617],{"class":1076},[1070,5927,5094],{"class":1289},[1070,5929,1628],{"class":1076},[1070,5931,5932,5935,5937,5940,5942],{"class":1072,"line":1727},[1070,5933,5934],{"class":1080},"        new_password",[1070,5936,1617],{"class":1076},[1070,5938,5939],{"class":1289}," newPassword",[1070,5941,1526],{"class":1076},[1070,5943,3694],{"class":1289},[1070,5945,5946],{"class":1072,"line":1747},[1070,5947,3700],{"class":1076},[1070,5949,5950,5952],{"class":1072,"line":1783},[1070,5951,1655],{"class":1076},[1070,5953,1434],{"class":1080},[1070,5955,5956],{"class":1072,"line":1793},[1070,5957,1663],{"class":1080},[1070,5959,5960,5962,5964,5966,5969,5971],{"class":1072,"line":1808},[1070,5961,1713],{"class":1424},[1070,5963,1428],{"class":1080},[1070,5965,1599],{"class":1076},[1070,5967,5968],{"class":1106},"\u002Flogin?message=Password reset successful",[1070,5970,1599],{"class":1076},[1070,5972,1434],{"class":1080},[1070,5974,5975,5977,5979,5981,5983,5985],{"class":1072,"line":1814},[1070,5976,1730],{"class":1076},[1070,5978,1733],{"class":1562},[1070,5980,1012],{"class":1080},[1070,5982,1738],{"class":1289},[1070,5984,1741],{"class":1080},[1070,5986,1744],{"class":1076},[1070,5988,5989,5991,5993,5995,5997,5999,6002],{"class":1072,"line":1820},[1070,5990,1750],{"class":1289},[1070,5992,1526],{"class":1076},[1070,5994,1529],{"class":1289},[1070,5996,1532],{"class":1076},[1070,5998,1620],{"class":1076},[1070,6000,6001],{"class":1106},"Reset link expired or invalid",[1070,6003,1780],{"class":1076},[1070,6005,6006,6008,6010],{"class":1072,"line":2437},[1070,6007,1730],{"class":1076},[1070,6009,1788],{"class":1562},[1070,6011,1517],{"class":1076},[1070,6013,6014,6016,6018,6020,6022],{"class":1072,"line":2442},[1070,6015,1796],{"class":1289},[1070,6017,1526],{"class":1076},[1070,6019,1529],{"class":1289},[1070,6021,1532],{"class":1076},[1070,6023,1805],{"class":1469},[1070,6025,6026],{"class":1072,"line":2450},[1070,6027,1811],{"class":1076},[1070,6029,6030],{"class":1072,"line":2458},[1070,6031,1817],{"class":1076},[1070,6033,6034,6036,6038],{"class":1072,"line":2468},[1070,6035,1293],{"class":1076},[1070,6037,1405],{"class":1080},[1070,6039,1084],{"class":1076},[1055,6041,6043],{"id":6042},"_4-server-validates-updates-password","4. Server Validates & Updates Password",[990,6045,6046],{},[994,6047,1838,6048],{},[1014,6049,5890],{},[1038,6051,6053],{"className":1843,"code":6052,"language":1845,"meta":1046,"style":1046},"export default defineEventHandler(async (event) => {\n  const { reset_token, new_password } = await readBody(event)\n  \n  \u002F\u002F Hash token to look up in DB\n  const resetTokenHash = crypto.createHash('sha256').update(reset_token).digest('hex')\n  \n  const resetRecord = await cockpit.passwordReset.findByHash(resetTokenHash)\n  if (!resetRecord || resetRecord.expires_at \u003C new Date()) {\n    throw createError({\n      statusCode: 400,\n      message: 'Reset link expired or invalid'\n    })\n  }\n  \n  \u002F\u002F Update user password\n  const newPasswordHash = await bcrypt.hash(new_password, 10)\n  await cockpit.users.update(resetRecord.user_id, {\n    password_hash: newPasswordHash\n  })\n  \n  \u002F\u002F Invalidate token (one-time use)\n  await cockpit.passwordReset.delete(resetRecord.id)\n  \n  return { message: 'Password reset successful' }\n})\n",[1014,6054,6055,6077,6105,6109,6114,6163,6167,6196,6227,6237,6247,6259,6265,6269,6273,6278,6306,6333,6342,6348,6352,6357,6382,6386,6405],{"__ignoreMap":1046},[1070,6056,6057,6059,6061,6063,6065,6067,6069,6071,6073,6075],{"class":1072,"line":1073},[1070,6058,1852],{"class":1562},[1070,6060,1855],{"class":1562},[1070,6062,1858],{"class":1424},[1070,6064,1428],{"class":1289},[1070,6066,1863],{"class":1096},[1070,6068,1012],{"class":1076},[1070,6070,1869],{"class":1868},[1070,6072,1872],{"class":1076},[1070,6074,1514],{"class":1096},[1070,6076,1517],{"class":1076},[1070,6078,6079,6081,6083,6086,6088,6091,6093,6095,6097,6099,6101,6103],{"class":1072,"line":1087},[1070,6080,1881],{"class":1096},[1070,6082,1574],{"class":1076},[1070,6084,6085],{"class":1289}," reset_token",[1070,6087,1580],{"class":1076},[1070,6089,6090],{"class":1289}," new_password",[1070,6092,1586],{"class":1076},[1070,6094,1532],{"class":1076},[1070,6096,1591],{"class":1562},[1070,6098,1898],{"class":1424},[1070,6100,1428],{"class":1080},[1070,6102,1869],{"class":1289},[1070,6104,1434],{"class":1080},[1070,6106,6107],{"class":1072,"line":1114},[1070,6108,1556],{"class":1080},[1070,6110,6111],{"class":1072,"line":1126},[1070,6112,6113],{"class":1669},"  \u002F\u002F Hash token to look up in DB\n",[1070,6115,6116,6118,6120,6122,6124,6126,6128,6130,6132,6134,6136,6138,6140,6142,6144,6147,6149,6151,6153,6155,6157,6159,6161],{"class":1072,"line":1143},[1070,6117,1881],{"class":1096},[1070,6119,5134],{"class":1289},[1070,6121,1532],{"class":1076},[1070,6123,5099],{"class":1289},[1070,6125,1526],{"class":1076},[1070,6127,5143],{"class":1424},[1070,6129,1428],{"class":1080},[1070,6131,1599],{"class":1076},[1070,6133,5150],{"class":1106},[1070,6135,1599],{"class":1076},[1070,6137,1872],{"class":1080},[1070,6139,1526],{"class":1076},[1070,6141,5159],{"class":1424},[1070,6143,1428],{"class":1080},[1070,6145,6146],{"class":1289},"reset_token",[1070,6148,1872],{"class":1080},[1070,6150,1526],{"class":1076},[1070,6152,5171],{"class":1424},[1070,6154,1428],{"class":1080},[1070,6156,1599],{"class":1076},[1070,6158,5123],{"class":1106},[1070,6160,1599],{"class":1076},[1070,6162,1434],{"class":1080},[1070,6164,6165],{"class":1072,"line":1159},[1070,6166,1556],{"class":1080},[1070,6168,6169,6171,6174,6176,6178,6180,6182,6184,6186,6189,6191,6194],{"class":1072,"line":1176},[1070,6170,1881],{"class":1096},[1070,6172,6173],{"class":1289}," resetRecord",[1070,6175,1532],{"class":1076},[1070,6177,1591],{"class":1562},[1070,6179,1926],{"class":1289},[1070,6181,1526],{"class":1076},[1070,6183,5202],{"class":1289},[1070,6185,1526],{"class":1076},[1070,6187,6188],{"class":1424},"findByHash",[1070,6190,1428],{"class":1080},[1070,6192,6193],{"class":1289},"resetTokenHash",[1070,6195,1434],{"class":1080},[1070,6197,6198,6200,6202,6204,6207,6209,6211,6213,6216,6218,6220,6222,6225],{"class":1072,"line":1182},[1070,6199,1947],{"class":1562},[1070,6201,1012],{"class":1080},[1070,6203,1952],{"class":1076},[1070,6205,6206],{"class":1289},"resetRecord",[1070,6208,1772],{"class":1076},[1070,6210,6173],{"class":1289},[1070,6212,1526],{"class":1076},[1070,6214,6215],{"class":1289},"expires_at",[1070,6217,3495],{"class":1076},[1070,6219,5246],{"class":1076},[1070,6221,5249],{"class":1424},[1070,6223,6224],{"class":1080},"()) ",[1070,6226,1744],{"class":1076},[1070,6228,6229,6231,6233,6235],{"class":1072,"line":1188},[1070,6230,1964],{"class":1562},[1070,6232,1967],{"class":1424},[1070,6234,1428],{"class":1080},[1070,6236,1744],{"class":1076},[1070,6238,6239,6241,6243,6245],{"class":1072,"line":1197},[1070,6240,1976],{"class":1080},[1070,6242,1617],{"class":1076},[1070,6244,3974],{"class":1981},[1070,6246,1628],{"class":1076},[1070,6248,6249,6251,6253,6255,6257],{"class":1072,"line":1213},[1070,6250,1989],{"class":1080},[1070,6252,1617],{"class":1076},[1070,6254,1620],{"class":1076},[1070,6256,6001],{"class":1106},[1070,6258,1780],{"class":1076},[1070,6260,6261,6263],{"class":1072,"line":1228},[1070,6262,1655],{"class":1076},[1070,6264,1434],{"class":1080},[1070,6266,6267],{"class":1072,"line":1244},[1070,6268,1811],{"class":1076},[1070,6270,6271],{"class":1072,"line":1249},[1070,6272,1556],{"class":1080},[1070,6274,6275],{"class":1072,"line":1254},[1070,6276,6277],{"class":1669},"  \u002F\u002F Update user password\n",[1070,6279,6280,6282,6285,6287,6289,6291,6293,6295,6297,6300,6302,6304],{"class":1072,"line":1300},[1070,6281,1881],{"class":1096},[1070,6283,6284],{"class":1289}," newPasswordHash",[1070,6286,1532],{"class":1076},[1070,6288,1591],{"class":1562},[1070,6290,2030],{"class":1289},[1070,6292,1526],{"class":1076},[1070,6294,4225],{"class":1424},[1070,6296,1428],{"class":1080},[1070,6298,6299],{"class":1289},"new_password",[1070,6301,1580],{"class":1076},[1070,6303,4234],{"class":1981},[1070,6305,1434],{"class":1080},[1070,6307,6308,6310,6312,6314,6316,6318,6320,6322,6324,6326,6329,6331],{"class":1072,"line":1331},[1070,6309,5195],{"class":1562},[1070,6311,1926],{"class":1289},[1070,6313,1526],{"class":1076},[1070,6315,1931],{"class":1289},[1070,6317,1526],{"class":1076},[1070,6319,5159],{"class":1424},[1070,6321,1428],{"class":1080},[1070,6323,6206],{"class":1289},[1070,6325,1526],{"class":1076},[1070,6327,6328],{"class":1289},"user_id",[1070,6330,1580],{"class":1076},[1070,6332,1517],{"class":1076},[1070,6334,6335,6337,6339],{"class":1072,"line":1374},[1070,6336,4295],{"class":1080},[1070,6338,1617],{"class":1076},[1070,6340,6341],{"class":1289}," newPasswordHash\n",[1070,6343,6344,6346],{"class":1072,"line":1384},[1070,6345,1730],{"class":1076},[1070,6347,1434],{"class":1080},[1070,6349,6350],{"class":1072,"line":1393},[1070,6351,1556],{"class":1080},[1070,6353,6354],{"class":1072,"line":1400},[1070,6355,6356],{"class":1669},"  \u002F\u002F Invalidate token (one-time use)\n",[1070,6358,6359,6361,6363,6365,6367,6369,6372,6374,6376,6378,6380],{"class":1072,"line":1413},[1070,6360,5195],{"class":1562},[1070,6362,1926],{"class":1289},[1070,6364,1526],{"class":1076},[1070,6366,5202],{"class":1289},[1070,6368,1526],{"class":1076},[1070,6370,6371],{"class":1424},"delete",[1070,6373,1428],{"class":1080},[1070,6375,6206],{"class":1289},[1070,6377,1526],{"class":1076},[1070,6379,2234],{"class":1289},[1070,6381,1434],{"class":1080},[1070,6383,6384],{"class":1072,"line":1437},[1070,6385,1556],{"class":1080},[1070,6387,6388,6390,6392,6394,6396,6398,6401,6403],{"class":1072,"line":1455},[1070,6389,2445],{"class":1562},[1070,6391,1574],{"class":1076},[1070,6393,3979],{"class":1080},[1070,6395,1617],{"class":1076},[1070,6397,1620],{"class":1076},[1070,6399,6400],{"class":1106},"Password reset successful",[1070,6402,1599],{"class":1076},[1070,6404,1649],{"class":1076},[1070,6406,6407,6409],{"class":1072,"line":1475},[1070,6408,2543],{"class":1076},[1070,6410,1434],{"class":1289},[1033,6412,6414],{"id":6413},"session-management","Session Management",[990,6416,6417,6418,6421],{},"Issuing a token is only half the story; every protected request afterwards has to check it. That splits into two pieces of middleware with distinct jobs. The first runs on every request and ",[4482,6419,6420],{},"identifies"," the user — it verifies the token and, if valid, attaches the decoded user to the request context (and quietly clears a bad cookie). It never blocks anything; it just establishes who, if anyone, is calling:",[990,6423,6424],{},[994,6425,6426],{},"Server middleware (server\u002Fmiddleware\u002Fauth.ts):",[1038,6428,6430],{"className":1843,"code":6429,"language":1845,"meta":1046,"style":1046},"export default defineEventHandler((event) => {\n  const token = getCookie(event, 'auth_token') || \n                event.headers.authorization?.split(' ')[1]\n  \n  if (token) {\n    try {\n      const decoded = jwt.verify(token, process.env.JWT_SECRET)\n      event.context.user = decoded\n    } catch (err) {\n      \u002F\u002F Token invalid or expired\n      deleteCookie(event, 'auth_token')\n    }\n  }\n})\n",[1014,6431,6432,6452,6482,6517,6521,6533,6540,6576,6595,6609,6614,6633,6637,6641],{"__ignoreMap":1046},[1070,6433,6434,6436,6438,6440,6442,6444,6446,6448,6450],{"class":1072,"line":1073},[1070,6435,1852],{"class":1562},[1070,6437,1855],{"class":1562},[1070,6439,1858],{"class":1424},[1070,6441,1428],{"class":1289},[1070,6443,1428],{"class":1076},[1070,6445,1869],{"class":1868},[1070,6447,1872],{"class":1076},[1070,6449,1514],{"class":1096},[1070,6451,1517],{"class":1076},[1070,6453,6454,6456,6458,6460,6463,6465,6467,6469,6471,6473,6475,6477,6480],{"class":1072,"line":1087},[1070,6455,1881],{"class":1096},[1070,6457,1577],{"class":1289},[1070,6459,1532],{"class":1076},[1070,6461,6462],{"class":1424}," getCookie",[1070,6464,1428],{"class":1080},[1070,6466,1869],{"class":1289},[1070,6468,1580],{"class":1076},[1070,6470,1620],{"class":1076},[1070,6472,1688],{"class":1106},[1070,6474,1599],{"class":1076},[1070,6476,1741],{"class":1080},[1070,6478,6479],{"class":1076},"||",[1070,6481,1123],{"class":1080},[1070,6483,6484,6487,6489,6491,6493,6496,6499,6502,6504,6506,6508,6511,6514],{"class":1072,"line":1114},[1070,6485,6486],{"class":1289},"                event",[1070,6488,1526],{"class":1076},[1070,6490,2710],{"class":1289},[1070,6492,1526],{"class":1076},[1070,6494,6495],{"class":1289},"authorization",[1070,6497,6498],{"class":1076},"?.",[1070,6500,6501],{"class":1424},"split",[1070,6503,1428],{"class":1080},[1070,6505,1599],{"class":1076},[1070,6507,1620],{"class":1076},[1070,6509,6510],{"class":1080},")[",[1070,6512,6513],{"class":1981},"1",[1070,6515,6516],{"class":1080},"]\n",[1070,6518,6519],{"class":1072,"line":1126},[1070,6520,1556],{"class":1080},[1070,6522,6523,6525,6527,6529,6531],{"class":1072,"line":1143},[1070,6524,1947],{"class":1562},[1070,6526,1012],{"class":1080},[1070,6528,2696],{"class":1289},[1070,6530,1741],{"class":1080},[1070,6532,1744],{"class":1076},[1070,6534,6535,6538],{"class":1072,"line":1159},[1070,6536,6537],{"class":1562},"    try",[1070,6539,1517],{"class":1076},[1070,6541,6542,6545,6548,6550,6552,6554,6557,6559,6561,6563,6566,6568,6570,6572,6574],{"class":1072,"line":1176},[1070,6543,6544],{"class":1096},"      const",[1070,6546,6547],{"class":1289}," decoded",[1070,6549,1532],{"class":1076},[1070,6551,2207],{"class":1289},[1070,6553,1526],{"class":1076},[1070,6555,6556],{"class":1424},"verify",[1070,6558,1428],{"class":1080},[1070,6560,2696],{"class":1289},[1070,6562,1580],{"class":1076},[1070,6564,6565],{"class":1289}," process",[1070,6567,1526],{"class":1076},[1070,6569,2296],{"class":1289},[1070,6571,1526],{"class":1076},[1070,6573,2301],{"class":1289},[1070,6575,1434],{"class":1080},[1070,6577,6578,6581,6583,6586,6588,6590,6592],{"class":1072,"line":1182},[1070,6579,6580],{"class":1289},"      event",[1070,6582,1526],{"class":1076},[1070,6584,6585],{"class":1289},"context",[1070,6587,1526],{"class":1076},[1070,6589,1955],{"class":1289},[1070,6591,1532],{"class":1076},[1070,6593,6594],{"class":1289}," decoded\n",[1070,6596,6597,6599,6601,6603,6605,6607],{"class":1072,"line":1188},[1070,6598,1655],{"class":1076},[1070,6600,1733],{"class":1562},[1070,6602,1012],{"class":1080},[1070,6604,1738],{"class":1289},[1070,6606,1741],{"class":1080},[1070,6608,1744],{"class":1076},[1070,6610,6611],{"class":1072,"line":1197},[1070,6612,6613],{"class":1669},"      \u002F\u002F Token invalid or expired\n",[1070,6615,6616,6619,6621,6623,6625,6627,6629,6631],{"class":1072,"line":1213},[1070,6617,6618],{"class":1424},"      deleteCookie",[1070,6620,1428],{"class":1080},[1070,6622,1869],{"class":1289},[1070,6624,1580],{"class":1076},[1070,6626,1620],{"class":1076},[1070,6628,1688],{"class":1106},[1070,6630,1599],{"class":1076},[1070,6632,1434],{"class":1080},[1070,6634,6635],{"class":1072,"line":1228},[1070,6636,2532],{"class":1076},[1070,6638,6639],{"class":1072,"line":1244},[1070,6640,1811],{"class":1076},[1070,6642,6643,6645],{"class":1072,"line":1249},[1070,6644,2543],{"class":1076},[1070,6646,1434],{"class":1289},[1055,6648,6650],{"id":6649},"route-protection","Route Protection",[990,6652,6653,6654,6657,6658,6661],{},"The second piece ",[4482,6655,6656],{},"enforces",". Where the first middleware merely set ",[1014,6659,6660],{},"event.context.user",", this guard rejects any request that doesn't have one — so you keep the \"who is calling\" logic in one place and the \"is calling allowed\" logic in another:",[1038,6663,6665],{"className":1843,"code":6664,"language":1845,"meta":1046,"style":1046},"export default defineEventHandler((event) => {\n  if (!event.context.user) {\n    throw createError({\n      statusCode: 401,\n      message: 'Not authenticated'\n    })\n  }\n})\n",[1014,6666,6667,6687,6709,6719,6729,6742,6748,6752],{"__ignoreMap":1046},[1070,6668,6669,6671,6673,6675,6677,6679,6681,6683,6685],{"class":1072,"line":1073},[1070,6670,1852],{"class":1562},[1070,6672,1855],{"class":1562},[1070,6674,1858],{"class":1424},[1070,6676,1428],{"class":1289},[1070,6678,1428],{"class":1076},[1070,6680,1869],{"class":1868},[1070,6682,1872],{"class":1076},[1070,6684,1514],{"class":1096},[1070,6686,1517],{"class":1076},[1070,6688,6689,6691,6693,6695,6697,6699,6701,6703,6705,6707],{"class":1072,"line":1087},[1070,6690,1947],{"class":1562},[1070,6692,1012],{"class":1080},[1070,6694,1952],{"class":1076},[1070,6696,1869],{"class":1289},[1070,6698,1526],{"class":1076},[1070,6700,6585],{"class":1289},[1070,6702,1526],{"class":1076},[1070,6704,1955],{"class":1289},[1070,6706,1741],{"class":1080},[1070,6708,1744],{"class":1076},[1070,6710,6711,6713,6715,6717],{"class":1072,"line":1114},[1070,6712,1964],{"class":1562},[1070,6714,1967],{"class":1424},[1070,6716,1428],{"class":1080},[1070,6718,1744],{"class":1076},[1070,6720,6721,6723,6725,6727],{"class":1072,"line":1126},[1070,6722,1976],{"class":1080},[1070,6724,1617],{"class":1076},[1070,6726,1982],{"class":1981},[1070,6728,1628],{"class":1076},[1070,6730,6731,6733,6735,6737,6740],{"class":1072,"line":1143},[1070,6732,1989],{"class":1080},[1070,6734,1617],{"class":1076},[1070,6736,1620],{"class":1076},[1070,6738,6739],{"class":1106},"Not authenticated",[1070,6741,1780],{"class":1076},[1070,6743,6744,6746],{"class":1072,"line":1159},[1070,6745,1655],{"class":1076},[1070,6747,1434],{"class":1080},[1070,6749,6750],{"class":1072,"line":1176},[1070,6751,1811],{"class":1076},[1070,6753,6754,6756],{"class":1072,"line":1182},[1070,6755,2543],{"class":1076},[1070,6757,1434],{"class":1289},[990,6759,6760],{},"A protected route then trusts that guarantee and simply uses the authenticated user:",[1038,6762,6764],{"className":1843,"code":6763,"language":1845,"meta":1046,"style":1046},"\u002F\u002F server\u002Fapi\u002Faccount\u002Fprofile.get.ts\nexport default defineEventHandler((event) => {\n  \u002F\u002F Middleware ensures user is authenticated\n  const userId = event.context.user.user_id\n  return cockpit.users.findById(userId)\n})\n",[1014,6765,6766,6771,6791,6796,6821,6843],{"__ignoreMap":1046},[1070,6767,6768],{"class":1072,"line":1073},[1070,6769,6770],{"class":1669},"\u002F\u002F server\u002Fapi\u002Faccount\u002Fprofile.get.ts\n",[1070,6772,6773,6775,6777,6779,6781,6783,6785,6787,6789],{"class":1072,"line":1087},[1070,6774,1852],{"class":1562},[1070,6776,1855],{"class":1562},[1070,6778,1858],{"class":1424},[1070,6780,1428],{"class":1289},[1070,6782,1428],{"class":1076},[1070,6784,1869],{"class":1868},[1070,6786,1872],{"class":1076},[1070,6788,1514],{"class":1096},[1070,6790,1517],{"class":1076},[1070,6792,6793],{"class":1072,"line":1114},[1070,6794,6795],{"class":1669},"  \u002F\u002F Middleware ensures user is authenticated\n",[1070,6797,6798,6800,6803,6805,6808,6810,6812,6814,6816,6818],{"class":1072,"line":1126},[1070,6799,1881],{"class":1096},[1070,6801,6802],{"class":1289}," userId",[1070,6804,1532],{"class":1076},[1070,6806,6807],{"class":1289}," event",[1070,6809,1526],{"class":1076},[1070,6811,6585],{"class":1289},[1070,6813,1526],{"class":1076},[1070,6815,1955],{"class":1289},[1070,6817,1526],{"class":1076},[1070,6819,6820],{"class":1289},"user_id\n",[1070,6822,6823,6825,6827,6829,6831,6833,6836,6838,6841],{"class":1072,"line":1143},[1070,6824,2445],{"class":1562},[1070,6826,1926],{"class":1289},[1070,6828,1526],{"class":1076},[1070,6830,1931],{"class":1289},[1070,6832,1526],{"class":1076},[1070,6834,6835],{"class":1424},"findById",[1070,6837,1428],{"class":1080},[1070,6839,6840],{"class":1289},"userId",[1070,6842,1434],{"class":1080},[1070,6844,6845,6847],{"class":1072,"line":1159},[1070,6846,2543],{"class":1076},[1070,6848,1434],{"class":1289},[1033,6850,6852],{"id":6851},"security-best-practices","Security Best Practices",[990,6854,6855],{},"Authentication is the one area where the defaults aren't optional polish — they're the difference between a safe storefront and a breached one. A handful of practices carry most of the weight.",[990,6857,6858,6859,6862,6863,6868,6869,6871,6872,6875,6876,6878,6879,6882],{},"Start with the transport and storage basics: serve every auth request over ",[994,6860,6861],{},"HTTPS",", keep tokens in ",[994,6864,6865,6867],{},[1014,6866,2588],{}," cookies"," rather than ",[1014,6870,2555],{}," so script can't read them, and pair that with ",[994,6873,6874],{},"CSRF protection"," on POST requests, since cookie-based auth is otherwise vulnerable to cross-site requests. Hash passwords with ",[994,6877,1023],{}," at 10+ salt rounds, and give tokens a bounded life — a ",[994,6880,6881],{},"seven-day JWT expiry",", after which the user logs in again — so a stolen token can't be used forever.",[990,6884,6885,6886,6889,6890,6893,6894,6897],{},"Then add the defences against abuse and misconfiguration: ",[994,6887,6888],{},"rate-limit"," login attempts (around five per minute per IP) to blunt brute-force and credential-stuffing attacks, set the ",[994,6891,6892],{},"secure response headers"," (HSTS, CSP, X-Frame-Options) that close off whole classes of attack, and ",[994,6895,6896],{},"log security events"," like failed logins and password resets so you can actually see an attack in progress.",[990,6899,6900],{},"Rate limiting is the one most often left out, so here's the shape of it:",[990,6902,6903],{},[994,6904,6905],{},"Example Rate Limiting:",[1038,6907,6909],{"className":1843,"code":6908,"language":1845,"meta":1046,"style":1046},"const loginAttempts = new Map()\n\nconst checkRateLimit = (ip) => {\n  const attempts = loginAttempts.get(ip) || []\n  const recentAttempts = attempts.filter(t => Date.now() - t \u003C 60000)\n  \n  if (recentAttempts.length >= 5) {\n    throw createError({\n      statusCode: 429,\n      message: 'Too many login attempts. Try again in 1 minute.'\n    })\n  }\n  \n  loginAttempts.set(ip, [...recentAttempts, Date.now()])\n}\n",[1014,6910,6911,6927,6931,6951,6979,7023,7027,7050,7060,7071,7084,7090,7094,7098,7133],{"__ignoreMap":1046},[1070,6912,6913,6915,6918,6920,6922,6925],{"class":1072,"line":1073},[1070,6914,1416],{"class":1096},[1070,6916,6917],{"class":1289}," loginAttempts ",[1070,6919,1100],{"class":1076},[1070,6921,5246],{"class":1076},[1070,6923,6924],{"class":1424}," Map",[1070,6926,5705],{"class":1289},[1070,6928,6929],{"class":1072,"line":1087},[1070,6930,1397],{"emptyLinePlaceholder":1396},[1070,6932,6933,6935,6938,6940,6942,6945,6947,6949],{"class":1072,"line":1114},[1070,6934,1416],{"class":1096},[1070,6936,6937],{"class":1289}," checkRateLimit ",[1070,6939,1100],{"class":1076},[1070,6941,1012],{"class":1076},[1070,6943,6944],{"class":1868},"ip",[1070,6946,1872],{"class":1076},[1070,6948,1514],{"class":1096},[1070,6950,1517],{"class":1076},[1070,6952,6953,6955,6958,6960,6963,6965,6968,6970,6972,6974,6976],{"class":1072,"line":1126},[1070,6954,1881],{"class":1096},[1070,6956,6957],{"class":1289}," attempts",[1070,6959,1532],{"class":1076},[1070,6961,6962],{"class":1289}," loginAttempts",[1070,6964,1526],{"class":1076},[1070,6966,6967],{"class":1424},"get",[1070,6969,1428],{"class":1080},[1070,6971,6944],{"class":1289},[1070,6973,1741],{"class":1080},[1070,6975,6479],{"class":1076},[1070,6977,6978],{"class":1080}," []\n",[1070,6980,6981,6983,6986,6988,6990,6992,6995,6997,7000,7002,7004,7006,7008,7010,7013,7016,7018,7021],{"class":1072,"line":1143},[1070,6982,1881],{"class":1096},[1070,6984,6985],{"class":1289}," recentAttempts",[1070,6987,1532],{"class":1076},[1070,6989,6957],{"class":1289},[1070,6991,1526],{"class":1076},[1070,6993,6994],{"class":1424},"filter",[1070,6996,1428],{"class":1080},[1070,6998,6999],{"class":1868},"t",[1070,7001,1514],{"class":1096},[1070,7003,5249],{"class":1289},[1070,7005,1526],{"class":1076},[1070,7007,5259],{"class":1424},[1070,7009,5262],{"class":1080},[1070,7011,7012],{"class":1076},"-",[1070,7014,7015],{"class":1289}," t",[1070,7017,3495],{"class":1076},[1070,7019,7020],{"class":1981}," 60000",[1070,7022,1434],{"class":1080},[1070,7024,7025],{"class":1072,"line":1159},[1070,7026,1556],{"class":1080},[1070,7028,7029,7031,7033,7036,7038,7040,7043,7046,7048],{"class":1072,"line":1176},[1070,7030,1947],{"class":1562},[1070,7032,1012],{"class":1080},[1070,7034,7035],{"class":1289},"recentAttempts",[1070,7037,1526],{"class":1076},[1070,7039,3492],{"class":1289},[1070,7041,7042],{"class":1076}," >=",[1070,7044,7045],{"class":1981}," 5",[1070,7047,1741],{"class":1080},[1070,7049,1744],{"class":1076},[1070,7051,7052,7054,7056,7058],{"class":1072,"line":1182},[1070,7053,1964],{"class":1562},[1070,7055,1967],{"class":1424},[1070,7057,1428],{"class":1080},[1070,7059,1744],{"class":1076},[1070,7061,7062,7064,7066,7069],{"class":1072,"line":1188},[1070,7063,1976],{"class":1080},[1070,7065,1617],{"class":1076},[1070,7067,7068],{"class":1981}," 429",[1070,7070,1628],{"class":1076},[1070,7072,7073,7075,7077,7079,7082],{"class":1072,"line":1197},[1070,7074,1989],{"class":1080},[1070,7076,1617],{"class":1076},[1070,7078,1620],{"class":1076},[1070,7080,7081],{"class":1106},"Too many login attempts. Try again in 1 minute.",[1070,7083,1780],{"class":1076},[1070,7085,7086,7088],{"class":1072,"line":1213},[1070,7087,1655],{"class":1076},[1070,7089,1434],{"class":1080},[1070,7091,7092],{"class":1072,"line":1228},[1070,7093,1811],{"class":1076},[1070,7095,7096],{"class":1072,"line":1244},[1070,7097,1556],{"class":1080},[1070,7099,7100,7103,7105,7108,7110,7112,7114,7117,7120,7122,7124,7126,7128,7130],{"class":1072,"line":1249},[1070,7101,7102],{"class":1289},"  loginAttempts",[1070,7104,1526],{"class":1076},[1070,7106,7107],{"class":1424},"set",[1070,7109,1428],{"class":1080},[1070,7111,6944],{"class":1289},[1070,7113,1580],{"class":1076},[1070,7115,7116],{"class":1080}," [",[1070,7118,7119],{"class":1076},"...",[1070,7121,7035],{"class":1289},[1070,7123,1580],{"class":1076},[1070,7125,5249],{"class":1289},[1070,7127,1526],{"class":1076},[1070,7129,5259],{"class":1424},[1070,7131,7132],{"class":1080},"()])\n",[1070,7134,7135],{"class":1072,"line":1254},[1070,7136,1817],{"class":1076},[1033,7138,7140],{"id":7139},"logout","Logout",[990,7142,7143],{},[994,7144,7145],{},"Frontend:",[1038,7147,7149],{"className":1843,"code":7148,"language":1845,"meta":1046,"style":1046},"const logout = async () => {\n  sessionStorage.removeItem('auth_token')\n  deleteCookie('auth_token')\n  navigateTo('\u002Flogin')\n}\n",[1014,7150,7151,7168,7188,7203,7218],{"__ignoreMap":1046},[1070,7152,7153,7155,7158,7160,7162,7164,7166],{"class":1072,"line":1073},[1070,7154,1416],{"class":1096},[1070,7156,7157],{"class":1289}," logout ",[1070,7159,1100],{"class":1076},[1070,7161,1508],{"class":1096},[1070,7163,1511],{"class":1076},[1070,7165,1514],{"class":1096},[1070,7167,1517],{"class":1076},[1070,7169,7170,7173,7175,7178,7180,7182,7184,7186],{"class":1072,"line":1087},[1070,7171,7172],{"class":1289},"  sessionStorage",[1070,7174,1526],{"class":1076},[1070,7176,7177],{"class":1424},"removeItem",[1070,7179,1428],{"class":1080},[1070,7181,1599],{"class":1076},[1070,7183,1688],{"class":1106},[1070,7185,1599],{"class":1076},[1070,7187,1434],{"class":1080},[1070,7189,7190,7193,7195,7197,7199,7201],{"class":1072,"line":1114},[1070,7191,7192],{"class":1424},"  deleteCookie",[1070,7194,1428],{"class":1080},[1070,7196,1599],{"class":1076},[1070,7198,1688],{"class":1106},[1070,7200,1599],{"class":1076},[1070,7202,1434],{"class":1080},[1070,7204,7205,7208,7210,7212,7214,7216],{"class":1072,"line":1126},[1070,7206,7207],{"class":1424},"  navigateTo",[1070,7209,1428],{"class":1080},[1070,7211,1599],{"class":1076},[1070,7213,4668],{"class":1106},[1070,7215,1599],{"class":1076},[1070,7217,1434],{"class":1080},[1070,7219,7220],{"class":1072,"line":1143},[1070,7221,1817],{"class":1076},[990,7223,7224],{},[994,7225,7226],{},"Backend (optional token revocation):",[1038,7228,7230],{"className":1843,"code":7229,"language":1845,"meta":1046,"style":1046},"export default defineEventHandler((event) => {\n  \u002F\u002F Invalidate token in blacklist\n  const token = getCookie(event, 'auth_token')\n  await cockpit.tokenBlacklist.add(token)\n  \n  deleteCookie(event, 'auth_token')\n  return { message: 'Logged out' }\n})\n",[1014,7231,7232,7252,7257,7281,7303,7307,7325,7344],{"__ignoreMap":1046},[1070,7233,7234,7236,7238,7240,7242,7244,7246,7248,7250],{"class":1072,"line":1073},[1070,7235,1852],{"class":1562},[1070,7237,1855],{"class":1562},[1070,7239,1858],{"class":1424},[1070,7241,1428],{"class":1289},[1070,7243,1428],{"class":1076},[1070,7245,1869],{"class":1868},[1070,7247,1872],{"class":1076},[1070,7249,1514],{"class":1096},[1070,7251,1517],{"class":1076},[1070,7253,7254],{"class":1072,"line":1087},[1070,7255,7256],{"class":1669},"  \u002F\u002F Invalidate token in blacklist\n",[1070,7258,7259,7261,7263,7265,7267,7269,7271,7273,7275,7277,7279],{"class":1072,"line":1114},[1070,7260,1881],{"class":1096},[1070,7262,1577],{"class":1289},[1070,7264,1532],{"class":1076},[1070,7266,6462],{"class":1424},[1070,7268,1428],{"class":1080},[1070,7270,1869],{"class":1289},[1070,7272,1580],{"class":1076},[1070,7274,1620],{"class":1076},[1070,7276,1688],{"class":1106},[1070,7278,1599],{"class":1076},[1070,7280,1434],{"class":1080},[1070,7282,7283,7285,7287,7289,7292,7294,7297,7299,7301],{"class":1072,"line":1126},[1070,7284,5195],{"class":1562},[1070,7286,1926],{"class":1289},[1070,7288,1526],{"class":1076},[1070,7290,7291],{"class":1289},"tokenBlacklist",[1070,7293,1526],{"class":1076},[1070,7295,7296],{"class":1424},"add",[1070,7298,1428],{"class":1080},[1070,7300,2696],{"class":1289},[1070,7302,1434],{"class":1080},[1070,7304,7305],{"class":1072,"line":1143},[1070,7306,1556],{"class":1080},[1070,7308,7309,7311,7313,7315,7317,7319,7321,7323],{"class":1072,"line":1159},[1070,7310,7192],{"class":1424},[1070,7312,1428],{"class":1080},[1070,7314,1869],{"class":1289},[1070,7316,1580],{"class":1076},[1070,7318,1620],{"class":1076},[1070,7320,1688],{"class":1106},[1070,7322,1599],{"class":1076},[1070,7324,1434],{"class":1080},[1070,7326,7327,7329,7331,7333,7335,7337,7340,7342],{"class":1072,"line":1176},[1070,7328,2445],{"class":1562},[1070,7330,1574],{"class":1076},[1070,7332,3979],{"class":1080},[1070,7334,1617],{"class":1076},[1070,7336,1620],{"class":1076},[1070,7338,7339],{"class":1106},"Logged out",[1070,7341,1599],{"class":1076},[1070,7343,1649],{"class":1076},[1070,7345,7346,7348],{"class":1072,"line":1182},[1070,7347,2543],{"class":1076},[1070,7349,1434],{"class":1289},[1033,7351,7353],{"id":7352},"next-steps","Next Steps",[7355,7356,7357,7366,7375],"ul",{},[7358,7359,7360,7365],"li",{},[994,7361,7362],{},[1305,7363,344],{"href":7364},"\u002Fdocs\u002Fproducts\u002Fsites\u002Fcheckout\u002F"," — Multi-step purchase flow",[7358,7367,7368,7374],{},[994,7369,7370],{},[1305,7371,7373],{"href":7372},"\u002Fdocs\u002Fproducts\u002Fsites\u002Farchitecture\u002F","Architecture"," — Storefront technical design",[7358,7376,7377,7382],{},[994,7378,7379],{},[1305,7380,512],{"href":7381},"\u002Fdocs\u002Fproducts\u002Fsites\u002Ftheming\u002F"," — Customizing login UI appearance",[7384,7385,7386],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}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 .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 .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 .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 .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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":1046,"searchDepth":1087,"depth":1087,"links":7388},[7389,7390,7395,7399,7405,7408,7409,7410],{"id":1035,"depth":1087,"text":1036},{"id":1049,"depth":1087,"text":1050,"children":7391},[7392,7393,7394],{"id":1057,"depth":1114,"text":1058},{"id":1829,"depth":1114,"text":1830},{"id":2548,"depth":1114,"text":2549},{"id":2802,"depth":1087,"text":2803,"children":7396},[7397,7398],{"id":2809,"depth":1114,"text":2810},{"id":3831,"depth":1114,"text":3832},{"id":4476,"depth":1087,"text":4477,"children":7400},[7401,7402,7403,7404],{"id":4487,"depth":1114,"text":4488},{"id":4949,"depth":1114,"text":4950},{"id":5437,"depth":1114,"text":5438},{"id":6042,"depth":1114,"text":6043},{"id":6413,"depth":1087,"text":6414,"children":7406},[7407],{"id":6649,"depth":1114,"text":6650},{"id":6851,"depth":1087,"text":6852},{"id":7139,"depth":1087,"text":7140},{"id":7352,"depth":1087,"text":7353},"User login, registration, and password management flows","md",null,{"status":7415},"published",{"title":171,"description":7411},{"loc":333},"Adsg78sS9HiKYfV-QkRxJgWvKgkz5JvGW2v2xgd2u5g",1785229258273]