[{"data":1,"prerenderedAt":2424},["ShallowReactive",2],{"navigation":3,"\u002Fapi\u002Fusers-and-security":342,"\u002Fapi\u002Fusers-and-security-surround":2419},[4,14,36,69,140,325],{"title":5,"path":6,"stem":7,"children":8},"Introduction","\u002Fgetting-started","1.getting-started\u002F1.index",[9,10],{"title":5,"path":6,"stem":7},{"title":11,"path":12,"stem":13},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation",{"title":15,"path":16,"stem":17,"children":18,"page":35},"Guides","\u002Fguides","2.guides",[19,23,27,31],{"title":20,"path":21,"stem":22},"Your First Layout","\u002Fguides\u002Fyour-first-layout","2.guides\u002F1.your-first-layout",{"title":24,"path":25,"stem":26},"Your First Page Template","\u002Fguides\u002Fyour-first-page-template","2.guides\u002F2.your-first-page-template",{"title":28,"path":29,"stem":30},"Your First Component","\u002Fguides\u002Fyour-first-component","2.guides\u002F3.your-first-component",{"title":32,"path":33,"stem":34},"Alternative UI Variants","\u002Fguides\u002Falternative-ui-variants","2.guides\u002F4.alternative-ui-variants",false,{"title":37,"path":38,"stem":39,"children":40,"page":35},"Core Concepts","\u002Fcore-concepts","3.core-concepts",[41,45,49,53,57,61,65],{"title":42,"path":43,"stem":44},"How It All Works","\u002Fcore-concepts\u002Farchitecture","3.core-concepts\u002F1.architecture",{"title":46,"path":47,"stem":48},"The Data Model","\u002Fcore-concepts\u002Fthe-data-model","3.core-concepts\u002F2.the-data-model",{"title":50,"path":51,"stem":52},"Layouts & Pages","\u002Fcore-concepts\u002Flayouts-and-pages","3.core-concepts\u002F3.layouts-and-pages",{"title":54,"path":55,"stem":56},"Dynamic Pages","\u002Fcore-concepts\u002Fdynamic-pages","3.core-concepts\u002F4.dynamic-pages",{"title":58,"path":59,"stem":60},"Components","\u002Fcore-concepts\u002Fcomponents","3.core-concepts\u002F5.components",{"title":62,"path":63,"stem":64},"Draft & Publish Workflow","\u002Fcore-concepts\u002Fdraft-and-publish","3.core-concepts\u002F6.draft-and-publish",{"title":66,"path":67,"stem":68},"The Admin Panel","\u002Fcore-concepts\u002Fadmin-panel","3.core-concepts\u002F7.admin-panel",{"title":70,"path":71,"stem":72,"children":73,"page":35},"Api","\u002Fapi","4.api",[74,78,116,120,124,128,132,136],{"title":75,"path":76,"stem":77},"Bundle Setup","\u002Fapi\u002Fbundle-setup","4.api\u002F1.bundle-setup",{"title":58,"path":79,"stem":80,"children":81,"page":35},"\u002Fapi\u002Fcomponents","4.api\u002F2.components",[82,86,103],{"title":83,"path":84,"stem":85},"Creating Components","\u002Fapi\u002Fcomponents\u002Fcreating-components","4.api\u002F2.components\u002F1.creating-components",{"title":87,"path":88,"stem":89,"children":90,"page":35},"Annotations","\u002Fapi\u002Fcomponents\u002Fannotations","4.api\u002F2.components\u002F2.annotations",[91,95,99],{"title":92,"path":93,"stem":94},"Publishable","\u002Fapi\u002Fcomponents\u002Fannotations\u002Fpublishable","4.api\u002F2.components\u002F2.annotations\u002F1.publishable",{"title":96,"path":97,"stem":98},"Uploadable","\u002Fapi\u002Fcomponents\u002Fannotations\u002Fuploadable","4.api\u002F2.components\u002F2.annotations\u002F2.uploadable",{"title":100,"path":101,"stem":102},"Timestamped","\u002Fapi\u002Fcomponents\u002Fannotations\u002Ftimestamped","4.api\u002F2.components\u002F2.annotations\u002F3.timestamped",{"title":104,"path":105,"stem":106,"children":107,"page":35},"Built Ins","\u002Fapi\u002Fcomponents\u002Fbuilt-ins","4.api\u002F2.components\u002F3.built-ins",[108,112],{"title":109,"path":110,"stem":111},"Collection Component","\u002Fapi\u002Fcomponents\u002Fbuilt-ins\u002Fcollection-component","4.api\u002F2.components\u002F3.built-ins\u002F1.collection-component",{"title":113,"path":114,"stem":115},"Form Component","\u002Fapi\u002Fcomponents\u002Fbuilt-ins\u002Fform-component","4.api\u002F2.components\u002F3.built-ins\u002F2.form-component",{"title":117,"path":118,"stem":119},"Dynamic & Nested Pages","\u002Fapi\u002Fdynamic-pages","4.api\u002F3.dynamic-pages",{"title":121,"path":122,"stem":123},"Users & Security","\u002Fapi\u002Fusers-and-security","4.api\u002F4.users-and-security",{"title":125,"path":126,"stem":127},"Data Fixtures","\u002Fapi\u002Fdata-fixtures","4.api\u002F5.data-fixtures",{"title":129,"path":130,"stem":131},"Configuration Reference","\u002Fapi\u002Fconfiguration","4.api\u002F6.configuration",{"title":133,"path":134,"stem":135},"Console Commands","\u002Fapi\u002Fconsole-commands","4.api\u002F7.console-commands",{"title":137,"path":138,"stem":139},"Debugging & Profiler","\u002Fapi\u002Fdebugging","4.api\u002F8.debugging",{"title":141,"path":142,"stem":143,"children":144,"page":35},"Nuxt Module","\u002Fnuxt-module","5.nuxt-module",[145,149,162,178,203,207,279,304,308],{"title":146,"path":147,"stem":148},"Module Setup","\u002Fnuxt-module\u002Fmodule-setup","5.nuxt-module\u002F1.module-setup",{"title":150,"path":151,"stem":152,"children":153,"page":35},"Configuration","\u002Fnuxt-module\u002Fconfiguration","5.nuxt-module\u002F2.configuration",[154,158],{"title":155,"path":156,"stem":157},"Nuxt Config","\u002Fnuxt-module\u002Fconfiguration\u002Fnuxt-config","5.nuxt-module\u002F2.configuration\u002F1.nuxt-config",{"title":159,"path":160,"stem":161},"Site Config & SEO","\u002Fnuxt-module\u002Fconfiguration\u002Fsite-config-and-seo","5.nuxt-module\u002F2.configuration\u002F2.site-config-and-seo",{"title":163,"path":164,"stem":165,"children":166,"page":35},"Building Your Ui","\u002Fnuxt-module\u002Fbuilding-your-ui","5.nuxt-module\u002F3.building-your-ui",[167,171,175],{"title":168,"path":169,"stem":170},"Layouts","\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcreating-layouts","5.nuxt-module\u002F3.building-your-ui\u002F1.creating-layouts",{"title":172,"path":173,"stem":174},"Page Templates","\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcreating-page-templates","5.nuxt-module\u002F3.building-your-ui\u002F2.creating-page-templates",{"title":83,"path":176,"stem":177},"\u002Fnuxt-module\u002Fbuilding-your-ui\u002Fcreating-components","5.nuxt-module\u002F3.building-your-ui\u002F3.creating-components",{"title":179,"path":180,"stem":181,"children":182,"page":35},"Cwa Components","\u002Fnuxt-module\u002Fcwa-components","5.nuxt-module\u002F4.cwa-components",[183,187,191,195,199],{"title":184,"path":185,"stem":186},"\u003CCwaComponentGroup \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-component-group","5.nuxt-module\u002F4.cwa-components\u002F1.cwa-component-group",{"title":188,"path":189,"stem":190},"\u003CCwaPage \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-page","5.nuxt-module\u002F4.cwa-components\u002F2.cwa-page",{"title":192,"path":193,"stem":194},"\u003CCwaLink \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-link","5.nuxt-module\u002F4.cwa-components\u002F3.cwa-link",{"title":196,"path":197,"stem":198},"\u003CCwaImage \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-image","5.nuxt-module\u002F4.cwa-components\u002F4.cwa-image",{"title":200,"path":201,"stem":202},"\u003CCwaDefaultLayout \u002F>","\u002Fnuxt-module\u002Fcwa-components\u002Fcwa-default-layout","5.nuxt-module\u002F4.cwa-components\u002F5.cwa-default-layout",{"title":204,"path":205,"stem":206},"The useCwa() API","\u002Fnuxt-module\u002Fcwa-api","5.nuxt-module\u002F5.cwa-api",{"title":208,"path":209,"stem":210,"children":211,"page":35},"Composables","\u002Fnuxt-module\u002Fcomposables","5.nuxt-module\u002F6.composables",[212,245,262],{"title":213,"path":214,"stem":215,"children":216,"page":35},"Component","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent","5.nuxt-module\u002F6.composables\u002F1.component",[217,221,225,229,233,237,241],{"title":218,"path":219,"stem":220},"Resource","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-resource","5.nuxt-module\u002F6.composables\u002F1.component\u002F1.use-cwa-resource",{"title":222,"path":223,"stem":224},"Collection Resource","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-collection-resource","5.nuxt-module\u002F6.composables\u002F1.component\u002F2.use-cwa-collection-resource",{"title":226,"path":227,"stem":228},"Image Resource","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-image-resource","5.nuxt-module\u002F6.composables\u002F1.component\u002F3.use-cwa-image-resource",{"title":230,"path":231,"stem":232},"Form","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-form","5.nuxt-module\u002F6.composables\u002F1.component\u002F4.use-cwa-form",{"title":234,"path":235,"stem":236},"Form Input","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-form-input","5.nuxt-module\u002F6.composables\u002F1.component\u002F5.use-cwa-form-input",{"title":238,"path":239,"stem":240},"Form Repeated","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-form-repeated","5.nuxt-module\u002F6.composables\u002F1.component\u002F6.use-cwa-form-repeated",{"title":242,"path":243,"stem":244},"Form Collection","\u002Fnuxt-module\u002Fcomposables\u002Fcomponent\u002Fuse-cwa-form-collection","5.nuxt-module\u002F6.composables\u002F1.component\u002F7.use-cwa-form-collection",{"title":246,"path":247,"stem":248,"children":249,"page":35},"Admin Manager","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager","5.nuxt-module\u002F6.composables\u002F2.admin-manager",[250,254,258],{"title":251,"path":252,"stem":253},"Manager Tab","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fuse-cwa-resource-manager-tab","5.nuxt-module\u002F6.composables\u002F2.admin-manager\u002F1.use-cwa-resource-manager-tab",{"title":255,"path":256,"stem":257},"Resource Model","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fuse-cwa-resource-model","5.nuxt-module\u002F6.composables\u002F2.admin-manager\u002F2.use-cwa-resource-model",{"title":259,"path":260,"stem":261},"Resource Upload","\u002Fnuxt-module\u002Fcomposables\u002Fadmin-manager\u002Fuse-cwa-resource-upload","5.nuxt-module\u002F6.composables\u002F2.admin-manager\u002F3.use-cwa-resource-upload",{"title":263,"path":264,"stem":265,"children":266,"page":35},"Utilities","\u002Fnuxt-module\u002Fcomposables\u002Futilities","5.nuxt-module\u002F6.composables\u002F3.utilities",[267,271,275],{"title":268,"path":269,"stem":270},"Resource Endpoint","\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-cwa-resource-endpoint","5.nuxt-module\u002F6.composables\u002F3.utilities\u002F1.use-cwa-resource-endpoint",{"title":272,"path":273,"stem":274},"Query Model","\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-query-bound-model","5.nuxt-module\u002F6.composables\u002F3.utilities\u002F2.use-query-bound-model",{"title":276,"path":277,"stem":278},"Resource Route","\u002Fnuxt-module\u002Fcomposables\u002Futilities\u002Fuse-cwa-resource-route","5.nuxt-module\u002F6.composables\u002F3.utilities\u002F3.use-cwa-resource-route",{"title":280,"path":281,"stem":282,"children":283,"page":35},"Component Helpers","\u002Fnuxt-module\u002Fcomponent-helpers","5.nuxt-module\u002F7.component-helpers",[284,288,292,296,300],{"title":285,"path":286,"stem":287},"Images & Media","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fimages-and-uploads","5.nuxt-module\u002F7.component-helpers\u002F1.images-and-uploads",{"title":289,"path":290,"stem":291},"Collections & Pagination","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fcollections-and-pagination","5.nuxt-module\u002F7.component-helpers\u002F2.collections-and-pagination",{"title":293,"path":294,"stem":295},"HTML Content","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fhtml-content","5.nuxt-module\u002F7.component-helpers\u002F3.html-content",{"title":297,"path":298,"stem":299},"Real-Time Updates","\u002Fnuxt-module\u002Fcomponent-helpers\u002Freal-time-updates","5.nuxt-module\u002F7.component-helpers\u002F4.real-time-updates",{"title":301,"path":302,"stem":303},"Forms","\u002Fnuxt-module\u002Fcomponent-helpers\u002Fforms","5.nuxt-module\u002F7.component-helpers\u002F5.forms",{"title":305,"path":306,"stem":307},"Authentication","\u002Fnuxt-module\u002Fauthentication","5.nuxt-module\u002F8.authentication",{"title":309,"path":310,"stem":311,"children":312,"page":35},"Cwa Layer","\u002Fnuxt-module\u002Fcwa-layer","5.nuxt-module\u002F9.cwa-layer",[313,317,321],{"title":314,"path":315,"stem":316},"Overview","\u002Fnuxt-module\u002Fcwa-layer\u002Foverview","5.nuxt-module\u002F9.cwa-layer\u002F1.overview",{"title":318,"path":319,"stem":320},"Auth Pages","\u002Fnuxt-module\u002Fcwa-layer\u002Fauth-pages","5.nuxt-module\u002F9.cwa-layer\u002F2.auth-pages",{"title":322,"path":323,"stem":324},"Admin Panel","\u002Fnuxt-module\u002Fcwa-layer\u002Fadmin-panel","5.nuxt-module\u002F9.cwa-layer\u002F3.admin-panel",{"title":326,"path":327,"stem":328,"children":329,"page":35},"Deployment","\u002Fdeployment","6.deployment",[330,334,338],{"title":331,"path":332,"stem":333},"Docker","\u002Fdeployment\u002Fdocker","6.deployment\u002F1.docker",{"title":335,"path":336,"stem":337},"Kubernetes & Helm","\u002Fdeployment\u002Fkubernetes","6.deployment\u002F2.kubernetes",{"title":339,"path":340,"stem":341},"CI\u002FCD","\u002Fdeployment\u002Fci-cd","6.deployment\u002F3.ci-cd",{"id":343,"title":121,"badge":344,"body":347,"description":2413,"extension":2414,"links":2415,"meta":2416,"navigation":445,"path":122,"seo":2417,"stem":123,"__hash__":2418},"docs\u002F4.api\u002F4.users-and-security.md",{"label":345,"color":346},"Draft","amber",{"type":348,"value":349,"toc":2395},"minimark",[350,359,364,386,390,400,634,639,768,783,787,790,859,866,877,882,897,901,904,1042,1046,1127,1131,1138,1528,1532,1538,1660,1667,1671,1753,1764,1768,1833,1837,1840,1977,1984,1993,1997,2000,2086,2110,2113,2143,2148,2159,2184,2198,2204,2209,2227,2230,2245,2249,2256,2262,2288,2291,2295,2308,2314,2364,2367,2391],[351,352,353,354,358],"p",{},"CWA uses cookie-based JWT authentication. The API sets a secure HttpOnly cookie on login; the Nuxt module reads auth state from the JWT payload. No ",[355,356,357],"code",{},"Authorization"," headers, no manual token storage — the browser handles it transparently.",[360,361,363],"h2",{"id":362},"the-authentication-flow","The Authentication Flow",[365,366,367,374,377,380,383],"ol",{},[368,369,370,371],"li",{},"Client sends credentials to ",[355,372,373],{},"POST \u002Flogin",[368,375,376],{},"API validates, issues a JWT and a refresh token — both as HttpOnly cookies",[368,378,379],{},"Every subsequent request sends the cookies automatically (same-origin or configured CORS)",[368,381,382],{},"When the JWT expires, the API auto-refreshes it using the refresh token cookie",[368,384,385],{},"The client never sees or stores the raw token values",[360,387,389],{"id":388},"abstractuser","AbstractUser",[351,391,392,393,396,397,399],{},"Your ",[355,394,395],{},"User"," entity (created by the Flex recipe) extends ",[355,398,389],{},":",[401,402,407],"pre",{"className":403,"code":404,"language":405,"meta":406,"style":406},"language-php shiki shiki-themes github-light github-dark material-theme-palenight","\u002F\u002F src\u002FEntity\u002FUser.php\nnamespace App\\Entity;\n\nuse ApiPlatform\\Metadata\\ApiResource;\nuse Doctrine\\ORM\\Mapping as ORM;\nuse Silverback\\ApiComponentsBundle\\Annotation as Silverback;\nuse Silverback\\ApiComponentsBundle\\Entity\\User\\AbstractUser;\n\n#[ORM\\Entity]\n#[ApiResource(\n    operations: [\u002F* restrict to ROLE_SUPER_ADMIN *\u002F]\n)]\nclass User extends AbstractUser\n{\n    \u002F\u002F Add custom fields here\n}\n","php","",[355,408,409,418,440,447,470,496,520,545,550,566,576,592,600,616,622,628],{"__ignoreMap":406},[410,411,414],"span",{"class":412,"line":413},"line",1,[410,415,417],{"class":416},"sTBSN","\u002F\u002F src\u002FEntity\u002FUser.php\n",[410,419,421,425,429,433,436],{"class":412,"line":420},2,[410,422,424],{"class":423},"stmX-","namespace",[410,426,428],{"class":427},"sRCss"," App",[410,430,432],{"class":431},"sn4go","\\",[410,434,435],{"class":427},"Entity",[410,437,439],{"class":438},"sOvfz",";\n",[410,441,443],{"class":412,"line":442},3,[410,444,446],{"emptyLinePlaceholder":445},true,"\n",[410,448,450,453,457,460,463,465,468],{"class":412,"line":449},4,[410,451,452],{"class":423},"use",[410,454,456],{"class":455},"sc2zw"," ApiPlatform",[410,458,432],{"class":459},"sBtbT",[410,461,462],{"class":455},"Metadata",[410,464,432],{"class":459},[410,466,467],{"class":455},"ApiResource",[410,469,439],{"class":438},[410,471,473,475,478,480,483,485,488,491,494],{"class":412,"line":472},5,[410,474,452],{"class":423},[410,476,477],{"class":455}," Doctrine",[410,479,432],{"class":459},[410,481,482],{"class":455},"ORM",[410,484,432],{"class":459},[410,486,487],{"class":455},"Mapping",[410,489,490],{"class":423}," as",[410,492,493],{"class":427}," ORM",[410,495,439],{"class":438},[410,497,499,501,504,506,509,511,514,516,518],{"class":412,"line":498},6,[410,500,452],{"class":423},[410,502,503],{"class":455}," Silverback",[410,505,432],{"class":459},[410,507,508],{"class":455},"ApiComponentsBundle",[410,510,432],{"class":459},[410,512,513],{"class":455},"Annotation",[410,515,490],{"class":423},[410,517,503],{"class":427},[410,519,439],{"class":438},[410,521,523,525,527,529,531,533,535,537,539,541,543],{"class":412,"line":522},7,[410,524,452],{"class":423},[410,526,503],{"class":455},[410,528,432],{"class":459},[410,530,508],{"class":455},[410,532,432],{"class":459},[410,534,435],{"class":455},[410,536,432],{"class":459},[410,538,395],{"class":455},[410,540,432],{"class":459},[410,542,389],{"class":455},[410,544,439],{"class":438},[410,546,548],{"class":412,"line":547},8,[410,549,446],{"emptyLinePlaceholder":445},[410,551,553,557,559,561,563],{"class":412,"line":552},9,[410,554,556],{"class":555},"sPB8G","#[",[410,558,482],{"class":455},[410,560,432],{"class":459},[410,562,435],{"class":455},[410,564,565],{"class":555},"]\n",[410,567,569,571,573],{"class":412,"line":568},10,[410,570,556],{"class":555},[410,572,467],{"class":455},[410,574,575],{"class":438},"(\n",[410,577,579,582,584,587,590],{"class":412,"line":578},11,[410,580,581],{"class":427},"    operations",[410,583,399],{"class":438},[410,585,586],{"class":438}," [",[410,588,589],{"class":416},"\u002F* restrict to ROLE_SUPER_ADMIN *\u002F",[410,591,565],{"class":438},[410,593,595,598],{"class":412,"line":594},12,[410,596,597],{"class":438},")",[410,599,565],{"class":555},[410,601,603,607,610,613],{"class":412,"line":602},13,[410,604,606],{"class":605},"swB56","class",[410,608,609],{"class":427}," User",[410,611,612],{"class":605}," extends",[410,614,615],{"class":427}," AbstractUser\n",[410,617,619],{"class":412,"line":618},14,[410,620,621],{"class":438},"{\n",[410,623,625],{"class":412,"line":624},15,[410,626,627],{"class":416},"    \u002F\u002F Add custom fields here\n",[410,629,631],{"class":412,"line":630},16,[410,632,633],{"class":438},"}\n",[635,636,638],"h3",{"id":637},"what-abstractuser-provides","What AbstractUser Provides",[640,641,642,658],"table",{},[643,644,645],"thead",{},[646,647,648,652,655],"tr",{},[649,650,651],"th",{},"Field",[649,653,654],{},"Serialization group",[649,656,657],{},"Notes",[659,660,661,677,691,710,724,740,754],"tbody",{},[646,662,663,669,674],{},[664,665,666],"td",{},[355,667,668],{},"username",[664,670,671],{},[355,672,673],{},"User:output",[664,675,676],{},"Used as login identifier",[646,678,679,684,688],{},[664,680,681],{},[355,682,683],{},"emailAddress",[664,685,686],{},[355,687,673],{},[664,689,690],{},"Unique; separate from username",[646,692,693,698,703],{},[664,694,695],{},[355,696,697],{},"roles",[664,699,700],{},[355,701,702],{},"User:superAdmin",[664,704,705,706,709],{},"Array; ",[355,707,708],{},"ROLE_USER"," always included",[646,711,712,717,721],{},[664,713,714],{},[355,715,716],{},"enabled",[664,718,719],{},[355,720,702],{},[664,722,723],{},"Disabled users cannot log in",[646,725,726,731,737],{},[664,727,728],{},[355,729,730],{},"plainPassword",[664,732,733,736],{},[355,734,735],{},"User:input"," (write-only)",[664,738,739],{},"Hashed before persist",[646,741,742,747,751],{},[664,743,744],{},[355,745,746],{},"emailAddressVerified",[664,748,749],{},[355,750,673],{},[664,752,753],{},"Set by email verification flow",[646,755,756,761,765],{},[664,757,758],{},[355,759,760],{},"newEmailAddress",[664,762,763],{},[355,764,673],{},[664,766,767],{},"Pending email change",[351,769,770,774,775,778,779,782],{},[771,772,773],"strong",{},"Passwords"," are never serialized to output — ",[355,776,777],{},"readable: false"," is set on the hashed ",[355,780,781],{},"password"," field.",[360,784,786],{"id":785},"generating-jwt-keys","Generating JWT Keys",[351,788,789],{},"One-time setup per environment:",[401,791,795],{"className":792,"code":793,"language":794,"meta":406,"style":406},"language-bash shiki shiki-themes github-light github-dark material-theme-palenight","mkdir -p config\u002Fjwt\nopenssl genpkey -out config\u002Fjwt\u002Fprivate.pem -aes256 -algorithm rsa -pkeyopt rsa_keygen_bits:4096\nopenssl pkey -in config\u002Fjwt\u002Fprivate.pem -out config\u002Fjwt\u002Fpublic.pem -pubout\n","bash",[355,796,797,810,839],{"__ignoreMap":406},[410,798,799,802,806],{"class":412,"line":413},[410,800,801],{"class":427},"mkdir",[410,803,805],{"class":804},"szhYu"," -p",[410,807,809],{"class":808},"sLL54"," config\u002Fjwt\n",[410,811,812,815,818,821,824,827,830,833,836],{"class":412,"line":420},[410,813,814],{"class":427},"openssl",[410,816,817],{"class":808}," genpkey",[410,819,820],{"class":804}," -out",[410,822,823],{"class":808}," config\u002Fjwt\u002Fprivate.pem",[410,825,826],{"class":804}," -aes256",[410,828,829],{"class":804}," -algorithm",[410,831,832],{"class":808}," rsa",[410,834,835],{"class":804}," -pkeyopt",[410,837,838],{"class":808}," rsa_keygen_bits:4096\n",[410,840,841,843,846,849,851,853,856],{"class":412,"line":442},[410,842,814],{"class":427},[410,844,845],{"class":808}," pkey",[410,847,848],{"class":804}," -in",[410,850,823],{"class":808},[410,852,820],{"class":804},[410,854,855],{"class":808}," config\u002Fjwt\u002Fpublic.pem",[410,857,858],{"class":804}," -pubout\n",[351,860,861,862,865],{},"Add to ",[355,863,864],{},".env.local"," (never commit):",[401,867,871],{"className":868,"code":869,"language":870,"meta":406,"style":406},"language-ini shiki shiki-themes github-light github-dark material-theme-palenight","JWT_PASSPHRASE=your_secure_passphrase\n","ini",[355,872,873],{"__ignoreMap":406},[410,874,875],{"class":412,"line":413},[410,876,869],{},[351,878,861,879,399],{},[355,880,881],{},".env",[401,883,885],{"className":868,"code":884,"language":870,"meta":406,"style":406},"JWT_SECRET_KEY=%kernel.project_dir%\u002Fconfig\u002Fjwt\u002Fprivate.pem\nJWT_PUBLIC_KEY=%kernel.project_dir%\u002Fconfig\u002Fjwt\u002Fpublic.pem\n",[355,886,887,892],{"__ignoreMap":406},[410,888,889],{"class":412,"line":413},[410,890,891],{},"JWT_SECRET_KEY=%kernel.project_dir%\u002Fconfig\u002Fjwt\u002Fprivate.pem\n",[410,893,894],{"class":412,"line":420},[410,895,896],{},"JWT_PUBLIC_KEY=%kernel.project_dir%\u002Fconfig\u002Fjwt\u002Fpublic.pem\n",[360,898,900],{"id":899},"lexik_jwt_authentication-configuration","lexik_jwt_authentication Configuration",[351,902,903],{},"The JWT cookie name must match the refresh token cookie name in the bundle config:",[401,905,909],{"className":906,"code":907,"language":908,"meta":406,"style":406},"language-yaml shiki shiki-themes github-light github-dark material-theme-palenight","# config\u002Fpackages\u002Flexik_jwt_authentication.yaml\nlexik_jwt_authentication:\n    secret_key: '%env(resolve:JWT_SECRET_KEY)%'\n    public_key: '%env(resolve:JWT_PUBLIC_KEY)%'\n    pass_phrase: '%env(JWT_PASSPHRASE)%'\n    token_ttl: 3600\n    set_cookies:\n        api_components:\n            lifetime: 604800  # 1 week\n            samesite: '%env(JWT_COOKIE_SAMESITE)%'\n            secure: true\n            httpOnly: true\n","yaml",[355,910,911,916,925,942,956,970,981,988,995,1008,1022,1033],{"__ignoreMap":406},[410,912,913],{"class":412,"line":413},[410,914,915],{"class":416},"# config\u002Fpackages\u002Flexik_jwt_authentication.yaml\n",[410,917,918,922],{"class":412,"line":420},[410,919,921],{"class":920},"s-h7I","lexik_jwt_authentication",[410,923,924],{"class":438},":\n",[410,926,927,930,932,936,939],{"class":412,"line":442},[410,928,929],{"class":920},"    secret_key",[410,931,399],{"class":438},[410,933,935],{"class":934},"seSrl"," '",[410,937,938],{"class":808},"%env(resolve:JWT_SECRET_KEY)%",[410,940,941],{"class":934},"'\n",[410,943,944,947,949,951,954],{"class":412,"line":449},[410,945,946],{"class":920},"    public_key",[410,948,399],{"class":438},[410,950,935],{"class":934},[410,952,953],{"class":808},"%env(resolve:JWT_PUBLIC_KEY)%",[410,955,941],{"class":934},[410,957,958,961,963,965,968],{"class":412,"line":472},[410,959,960],{"class":920},"    pass_phrase",[410,962,399],{"class":438},[410,964,935],{"class":934},[410,966,967],{"class":808},"%env(JWT_PASSPHRASE)%",[410,969,941],{"class":934},[410,971,972,975,977],{"class":412,"line":498},[410,973,974],{"class":920},"    token_ttl",[410,976,399],{"class":438},[410,978,980],{"class":979},"scSvc"," 3600\n",[410,982,983,986],{"class":412,"line":522},[410,984,985],{"class":920},"    set_cookies",[410,987,924],{"class":438},[410,989,990,993],{"class":412,"line":547},[410,991,992],{"class":920},"        api_components",[410,994,924],{"class":438},[410,996,997,1000,1002,1005],{"class":412,"line":552},[410,998,999],{"class":920},"            lifetime",[410,1001,399],{"class":438},[410,1003,1004],{"class":979}," 604800",[410,1006,1007],{"class":416},"  # 1 week\n",[410,1009,1010,1013,1015,1017,1020],{"class":412,"line":568},[410,1011,1012],{"class":920},"            samesite",[410,1014,399],{"class":438},[410,1016,935],{"class":934},[410,1018,1019],{"class":808},"%env(JWT_COOKIE_SAMESITE)%",[410,1021,941],{"class":934},[410,1023,1024,1027,1029],{"class":412,"line":578},[410,1025,1026],{"class":920},"            secure",[410,1028,399],{"class":438},[410,1030,1032],{"class":1031},"swWMF"," true\n",[410,1034,1035,1038,1040],{"class":412,"line":594},[410,1036,1037],{"class":920},"            httpOnly",[410,1039,399],{"class":438},[410,1041,1032],{"class":1031},[360,1043,1045],{"id":1044},"refresh-token-configuration","Refresh Token Configuration",[401,1047,1049],{"className":906,"code":1048,"language":908,"meta":406,"style":406},"silverback_api_components:\n    refresh_token:\n        handler_id: silverback.api_components.refresh_token.storage.doctrine\n        options:\n            class: App\\Entity\\RefreshToken\n        cookie_name: api_components   # must match lexik_jwt cookie name\n        ttl: 604800                   # 1 week\n        database_user_provider: database\n",[355,1050,1051,1058,1065,1075,1082,1092,1105,1117],{"__ignoreMap":406},[410,1052,1053,1056],{"class":412,"line":413},[410,1054,1055],{"class":920},"silverback_api_components",[410,1057,924],{"class":438},[410,1059,1060,1063],{"class":412,"line":420},[410,1061,1062],{"class":920},"    refresh_token",[410,1064,924],{"class":438},[410,1066,1067,1070,1072],{"class":412,"line":442},[410,1068,1069],{"class":920},"        handler_id",[410,1071,399],{"class":438},[410,1073,1074],{"class":808}," silverback.api_components.refresh_token.storage.doctrine\n",[410,1076,1077,1080],{"class":412,"line":449},[410,1078,1079],{"class":920},"        options",[410,1081,924],{"class":438},[410,1083,1084,1087,1089],{"class":412,"line":472},[410,1085,1086],{"class":920},"            class",[410,1088,399],{"class":438},[410,1090,1091],{"class":808}," App\\Entity\\RefreshToken\n",[410,1093,1094,1097,1099,1102],{"class":412,"line":498},[410,1095,1096],{"class":920},"        cookie_name",[410,1098,399],{"class":438},[410,1100,1101],{"class":808}," api_components",[410,1103,1104],{"class":416},"   # must match lexik_jwt cookie name\n",[410,1106,1107,1110,1112,1114],{"class":412,"line":522},[410,1108,1109],{"class":920},"        ttl",[410,1111,399],{"class":438},[410,1113,1004],{"class":979},[410,1115,1116],{"class":416},"                   # 1 week\n",[410,1118,1119,1122,1124],{"class":412,"line":547},[410,1120,1121],{"class":920},"        database_user_provider",[410,1123,399],{"class":438},[410,1125,1126],{"class":808}," database\n",[360,1128,1130],{"id":1129},"security-configuration","Security Configuration",[351,1132,1133,1134,1137],{},"The Flex recipe provides a working ",[355,1135,1136],{},"security.yaml",". Key sections:",[401,1139,1141],{"className":906,"code":1140,"language":908,"meta":406,"style":406},"security:\n    role_hierarchy:\n        ROLE_ADMIN: ROLE_USER\n        ROLE_SUPER_ADMIN: ROLE_ADMIN\n\n    firewalls:\n        main:\n            stateless: true\n            provider: database\n            guard:\n                authenticators:\n                    - lexik_jwt_authentication.jwt_token_authenticator\n\n    access_control:\n        # Anonymous access for auth flows\n        - { path: '^\u002Flogin', roles: PUBLIC_ACCESS }\n        - { path: '^\u002Ftoken\u002Frefresh', roles: PUBLIC_ACCESS }\n        - { path: '^\u002Fpassword\u002Freset', roles: PUBLIC_ACCESS }\n        - { path: '^\u002Fpassword\u002Fupdate', roles: PUBLIC_ACCESS }\n\n        # Allow anonymous form submissions (contact forms etc.)\n        - { path: '^\u002Fcomponent\u002Fforms\u002F.*\u002Fsubmit', methods: ['POST', 'PATCH'], roles: PUBLIC_ACCESS }\n\n        # Public read access\n        - { path: '^\u002F', methods: ['GET'], roles: PUBLIC_ACCESS }\n\n        # Mutations require authentication\n        - { path: '^\u002F', roles: ROLE_USER }\n",[355,1142,1143,1150,1157,1167,1177,1181,1188,1195,1204,1213,1220,1227,1235,1239,1246,1251,1286,1314,1342,1370,1375,1381,1435,1440,1446,1489,1494,1500],{"__ignoreMap":406},[410,1144,1145,1148],{"class":412,"line":413},[410,1146,1147],{"class":920},"security",[410,1149,924],{"class":438},[410,1151,1152,1155],{"class":412,"line":420},[410,1153,1154],{"class":920},"    role_hierarchy",[410,1156,924],{"class":438},[410,1158,1159,1162,1164],{"class":412,"line":442},[410,1160,1161],{"class":920},"        ROLE_ADMIN",[410,1163,399],{"class":438},[410,1165,1166],{"class":808}," ROLE_USER\n",[410,1168,1169,1172,1174],{"class":412,"line":449},[410,1170,1171],{"class":920},"        ROLE_SUPER_ADMIN",[410,1173,399],{"class":438},[410,1175,1176],{"class":808}," ROLE_ADMIN\n",[410,1178,1179],{"class":412,"line":472},[410,1180,446],{"emptyLinePlaceholder":445},[410,1182,1183,1186],{"class":412,"line":498},[410,1184,1185],{"class":920},"    firewalls",[410,1187,924],{"class":438},[410,1189,1190,1193],{"class":412,"line":522},[410,1191,1192],{"class":920},"        main",[410,1194,924],{"class":438},[410,1196,1197,1200,1202],{"class":412,"line":547},[410,1198,1199],{"class":920},"            stateless",[410,1201,399],{"class":438},[410,1203,1032],{"class":1031},[410,1205,1206,1209,1211],{"class":412,"line":552},[410,1207,1208],{"class":920},"            provider",[410,1210,399],{"class":438},[410,1212,1126],{"class":808},[410,1214,1215,1218],{"class":412,"line":568},[410,1216,1217],{"class":920},"            guard",[410,1219,924],{"class":438},[410,1221,1222,1225],{"class":412,"line":578},[410,1223,1224],{"class":920},"                authenticators",[410,1226,924],{"class":438},[410,1228,1229,1232],{"class":412,"line":594},[410,1230,1231],{"class":438},"                    -",[410,1233,1234],{"class":808}," lexik_jwt_authentication.jwt_token_authenticator\n",[410,1236,1237],{"class":412,"line":602},[410,1238,446],{"emptyLinePlaceholder":445},[410,1240,1241,1244],{"class":412,"line":618},[410,1242,1243],{"class":920},"    access_control",[410,1245,924],{"class":438},[410,1247,1248],{"class":412,"line":624},[410,1249,1250],{"class":416},"        # Anonymous access for auth flows\n",[410,1252,1253,1256,1259,1262,1264,1266,1269,1272,1275,1278,1280,1283],{"class":412,"line":630},[410,1254,1255],{"class":438},"        -",[410,1257,1258],{"class":438}," {",[410,1260,1261],{"class":920}," path",[410,1263,399],{"class":438},[410,1265,935],{"class":934},[410,1267,1268],{"class":808},"^\u002Flogin",[410,1270,1271],{"class":934},"'",[410,1273,1274],{"class":438},",",[410,1276,1277],{"class":920}," roles",[410,1279,399],{"class":438},[410,1281,1282],{"class":808}," PUBLIC_ACCESS",[410,1284,1285],{"class":438}," }\n",[410,1287,1289,1291,1293,1295,1297,1299,1302,1304,1306,1308,1310,1312],{"class":412,"line":1288},17,[410,1290,1255],{"class":438},[410,1292,1258],{"class":438},[410,1294,1261],{"class":920},[410,1296,399],{"class":438},[410,1298,935],{"class":934},[410,1300,1301],{"class":808},"^\u002Ftoken\u002Frefresh",[410,1303,1271],{"class":934},[410,1305,1274],{"class":438},[410,1307,1277],{"class":920},[410,1309,399],{"class":438},[410,1311,1282],{"class":808},[410,1313,1285],{"class":438},[410,1315,1317,1319,1321,1323,1325,1327,1330,1332,1334,1336,1338,1340],{"class":412,"line":1316},18,[410,1318,1255],{"class":438},[410,1320,1258],{"class":438},[410,1322,1261],{"class":920},[410,1324,399],{"class":438},[410,1326,935],{"class":934},[410,1328,1329],{"class":808},"^\u002Fpassword\u002Freset",[410,1331,1271],{"class":934},[410,1333,1274],{"class":438},[410,1335,1277],{"class":920},[410,1337,399],{"class":438},[410,1339,1282],{"class":808},[410,1341,1285],{"class":438},[410,1343,1345,1347,1349,1351,1353,1355,1358,1360,1362,1364,1366,1368],{"class":412,"line":1344},19,[410,1346,1255],{"class":438},[410,1348,1258],{"class":438},[410,1350,1261],{"class":920},[410,1352,399],{"class":438},[410,1354,935],{"class":934},[410,1356,1357],{"class":808},"^\u002Fpassword\u002Fupdate",[410,1359,1271],{"class":934},[410,1361,1274],{"class":438},[410,1363,1277],{"class":920},[410,1365,399],{"class":438},[410,1367,1282],{"class":808},[410,1369,1285],{"class":438},[410,1371,1373],{"class":412,"line":1372},20,[410,1374,446],{"emptyLinePlaceholder":445},[410,1376,1378],{"class":412,"line":1377},21,[410,1379,1380],{"class":416},"        # Allow anonymous form submissions (contact forms etc.)\n",[410,1382,1384,1386,1388,1390,1392,1394,1397,1399,1401,1404,1406,1408,1410,1413,1415,1417,1419,1422,1424,1427,1429,1431,1433],{"class":412,"line":1383},22,[410,1385,1255],{"class":438},[410,1387,1258],{"class":438},[410,1389,1261],{"class":920},[410,1391,399],{"class":438},[410,1393,935],{"class":934},[410,1395,1396],{"class":808},"^\u002Fcomponent\u002Fforms\u002F.*\u002Fsubmit",[410,1398,1271],{"class":934},[410,1400,1274],{"class":438},[410,1402,1403],{"class":920}," methods",[410,1405,399],{"class":438},[410,1407,586],{"class":438},[410,1409,1271],{"class":934},[410,1411,1412],{"class":808},"POST",[410,1414,1271],{"class":934},[410,1416,1274],{"class":438},[410,1418,935],{"class":934},[410,1420,1421],{"class":808},"PATCH",[410,1423,1271],{"class":934},[410,1425,1426],{"class":438},"],",[410,1428,1277],{"class":920},[410,1430,399],{"class":438},[410,1432,1282],{"class":808},[410,1434,1285],{"class":438},[410,1436,1438],{"class":412,"line":1437},23,[410,1439,446],{"emptyLinePlaceholder":445},[410,1441,1443],{"class":412,"line":1442},24,[410,1444,1445],{"class":416},"        # Public read access\n",[410,1447,1449,1451,1453,1455,1457,1459,1462,1464,1466,1468,1470,1472,1474,1477,1479,1481,1483,1485,1487],{"class":412,"line":1448},25,[410,1450,1255],{"class":438},[410,1452,1258],{"class":438},[410,1454,1261],{"class":920},[410,1456,399],{"class":438},[410,1458,935],{"class":934},[410,1460,1461],{"class":808},"^\u002F",[410,1463,1271],{"class":934},[410,1465,1274],{"class":438},[410,1467,1403],{"class":920},[410,1469,399],{"class":438},[410,1471,586],{"class":438},[410,1473,1271],{"class":934},[410,1475,1476],{"class":808},"GET",[410,1478,1271],{"class":934},[410,1480,1426],{"class":438},[410,1482,1277],{"class":920},[410,1484,399],{"class":438},[410,1486,1282],{"class":808},[410,1488,1285],{"class":438},[410,1490,1492],{"class":412,"line":1491},26,[410,1493,446],{"emptyLinePlaceholder":445},[410,1495,1497],{"class":412,"line":1496},27,[410,1498,1499],{"class":416},"        # Mutations require authentication\n",[410,1501,1503,1505,1507,1509,1511,1513,1515,1517,1519,1521,1523,1526],{"class":412,"line":1502},28,[410,1504,1255],{"class":438},[410,1506,1258],{"class":438},[410,1508,1261],{"class":920},[410,1510,399],{"class":438},[410,1512,935],{"class":934},[410,1514,1461],{"class":808},[410,1516,1271],{"class":934},[410,1518,1274],{"class":438},[410,1520,1277],{"class":920},[410,1522,399],{"class":438},[410,1524,1525],{"class":808}," ROLE_USER",[410,1527,1285],{"class":438},[360,1529,1531],{"id":1530},"email-verification-flow","Email Verification Flow",[351,1533,1534,1535,399],{},"Configure verification behaviour in ",[355,1536,1537],{},"silverback_api_components.yaml",[401,1539,1541],{"className":906,"code":1540,"language":908,"meta":406,"style":406},"silverback_api_components:\n    user:\n        class_name: App\\Entity\\User\n        email_verification:\n            default_value: false          # new users start unverified\n            verify_on_register: true      # send verification email on POST \u002Fusers\n            verify_on_change: true        # re-verify when email changes\n            deny_unverified_login: true   # block unverified users from logging in\n            email:\n                redirect_path_query: null\n                default_redirect_path: \u002Fverify-email\u002F{{ username }}\u002F{{ token }}\n                subject: Please verify your email\n",[355,1542,1543,1549,1556,1566,1573,1586,1599,1611,1623,1630,1640,1650],{"__ignoreMap":406},[410,1544,1545,1547],{"class":412,"line":413},[410,1546,1055],{"class":920},[410,1548,924],{"class":438},[410,1550,1551,1554],{"class":412,"line":420},[410,1552,1553],{"class":920},"    user",[410,1555,924],{"class":438},[410,1557,1558,1561,1563],{"class":412,"line":442},[410,1559,1560],{"class":920},"        class_name",[410,1562,399],{"class":438},[410,1564,1565],{"class":808}," App\\Entity\\User\n",[410,1567,1568,1571],{"class":412,"line":449},[410,1569,1570],{"class":920},"        email_verification",[410,1572,924],{"class":438},[410,1574,1575,1578,1580,1583],{"class":412,"line":472},[410,1576,1577],{"class":920},"            default_value",[410,1579,399],{"class":438},[410,1581,1582],{"class":1031}," false",[410,1584,1585],{"class":416},"          # new users start unverified\n",[410,1587,1588,1591,1593,1596],{"class":412,"line":498},[410,1589,1590],{"class":920},"            verify_on_register",[410,1592,399],{"class":438},[410,1594,1595],{"class":1031}," true",[410,1597,1598],{"class":416},"      # send verification email on POST \u002Fusers\n",[410,1600,1601,1604,1606,1608],{"class":412,"line":522},[410,1602,1603],{"class":920},"            verify_on_change",[410,1605,399],{"class":438},[410,1607,1595],{"class":1031},[410,1609,1610],{"class":416},"        # re-verify when email changes\n",[410,1612,1613,1616,1618,1620],{"class":412,"line":547},[410,1614,1615],{"class":920},"            deny_unverified_login",[410,1617,399],{"class":438},[410,1619,1595],{"class":1031},[410,1621,1622],{"class":416},"   # block unverified users from logging in\n",[410,1624,1625,1628],{"class":412,"line":552},[410,1626,1627],{"class":920},"            email",[410,1629,924],{"class":438},[410,1631,1632,1635,1637],{"class":412,"line":568},[410,1633,1634],{"class":920},"                redirect_path_query",[410,1636,399],{"class":438},[410,1638,1639],{"class":459}," null\n",[410,1641,1642,1645,1647],{"class":412,"line":578},[410,1643,1644],{"class":920},"                default_redirect_path",[410,1646,399],{"class":438},[410,1648,1649],{"class":808}," \u002Fverify-email\u002F{{ username }}\u002F{{ token }}\n",[410,1651,1652,1655,1657],{"class":412,"line":594},[410,1653,1654],{"class":920},"                subject",[410,1656,399],{"class":438},[410,1658,1659],{"class":808}," Please verify your email\n",[351,1661,1662,1663,1666],{},"The Nuxt module provides the ",[355,1664,1665],{},"\u002Fverify-email\u002F[username]\u002F[token]"," page automatically.",[360,1668,1670],{"id":1669},"password-reset-flow","Password Reset Flow",[401,1672,1674],{"className":906,"code":1673,"language":908,"meta":406,"style":406},"silverback_api_components:\n    user:\n        password_reset:\n            email:\n                redirect_path_query: null\n                default_redirect_path: \u002Freset-password\u002F{{ username }}\u002F{{ token }}\n                subject: Your password reset request\n            repeat_ttl_seconds: 8600      # minimum time between reset requests\n            request_timeout_seconds: 3600 # token validity window\n",[355,1675,1676,1682,1688,1695,1701,1709,1718,1727,1740],{"__ignoreMap":406},[410,1677,1678,1680],{"class":412,"line":413},[410,1679,1055],{"class":920},[410,1681,924],{"class":438},[410,1683,1684,1686],{"class":412,"line":420},[410,1685,1553],{"class":920},[410,1687,924],{"class":438},[410,1689,1690,1693],{"class":412,"line":442},[410,1691,1692],{"class":920},"        password_reset",[410,1694,924],{"class":438},[410,1696,1697,1699],{"class":412,"line":449},[410,1698,1627],{"class":920},[410,1700,924],{"class":438},[410,1702,1703,1705,1707],{"class":412,"line":472},[410,1704,1634],{"class":920},[410,1706,399],{"class":438},[410,1708,1639],{"class":459},[410,1710,1711,1713,1715],{"class":412,"line":498},[410,1712,1644],{"class":920},[410,1714,399],{"class":438},[410,1716,1717],{"class":808}," \u002Freset-password\u002F{{ username }}\u002F{{ token }}\n",[410,1719,1720,1722,1724],{"class":412,"line":522},[410,1721,1654],{"class":920},[410,1723,399],{"class":438},[410,1725,1726],{"class":808}," Your password reset request\n",[410,1728,1729,1732,1734,1737],{"class":412,"line":547},[410,1730,1731],{"class":920},"            repeat_ttl_seconds",[410,1733,399],{"class":438},[410,1735,1736],{"class":979}," 8600",[410,1738,1739],{"class":416},"      # minimum time between reset requests\n",[410,1741,1742,1745,1747,1750],{"class":412,"line":552},[410,1743,1744],{"class":920},"            request_timeout_seconds",[410,1746,399],{"class":438},[410,1748,1749],{"class":979}," 3600",[410,1751,1752],{"class":416}," # token validity window\n",[351,1754,1755,1756,1759,1760,1763],{},"The Nuxt module provides ",[355,1757,1758],{},"\u002Fforgot-password"," and ",[355,1761,1762],{},"\u002Freset-password\u002F[username]\u002F[token]"," automatically.",[360,1765,1767],{"id":1766},"email-address-change-flow","Email Address Change Flow",[401,1769,1771],{"className":906,"code":1770,"language":908,"meta":406,"style":406},"silverback_api_components:\n    user:\n        new_email_confirmation:\n            email:\n                redirect_path_query: null\n                default_redirect_path: \u002Fconfirm-new-email\u002F{{ username }}\u002F{{ new_email }}\u002F{{ token }}\n                subject: Please confirm your new email address\n            request_timeout_seconds: 86400\n",[355,1772,1773,1779,1785,1792,1798,1806,1815,1824],{"__ignoreMap":406},[410,1774,1775,1777],{"class":412,"line":413},[410,1776,1055],{"class":920},[410,1778,924],{"class":438},[410,1780,1781,1783],{"class":412,"line":420},[410,1782,1553],{"class":920},[410,1784,924],{"class":438},[410,1786,1787,1790],{"class":412,"line":442},[410,1788,1789],{"class":920},"        new_email_confirmation",[410,1791,924],{"class":438},[410,1793,1794,1796],{"class":412,"line":449},[410,1795,1627],{"class":920},[410,1797,924],{"class":438},[410,1799,1800,1802,1804],{"class":412,"line":472},[410,1801,1634],{"class":920},[410,1803,399],{"class":438},[410,1805,1639],{"class":459},[410,1807,1808,1810,1812],{"class":412,"line":498},[410,1809,1644],{"class":920},[410,1811,399],{"class":438},[410,1813,1814],{"class":808}," \u002Fconfirm-new-email\u002F{{ username }}\u002F{{ new_email }}\u002F{{ token }}\n",[410,1816,1817,1819,1821],{"class":412,"line":522},[410,1818,1654],{"class":920},[410,1820,399],{"class":438},[410,1822,1823],{"class":808}," Please confirm your new email address\n",[410,1825,1826,1828,1830],{"class":412,"line":547},[410,1827,1744],{"class":920},[410,1829,399],{"class":438},[410,1831,1832],{"class":979}," 86400\n",[360,1834,1836],{"id":1835},"notification-emails","Notification Emails",[351,1838,1839],{},"Configure which system emails are sent and their subjects:",[401,1841,1843],{"className":906,"code":1842,"language":908,"meta":406,"style":406},"silverback_api_components:\n    user:\n        emails:\n            welcome:\n                enabled: true\n                subject: 'Welcome to {{ website_name }}'\n            user_enabled:\n                enabled: true\n                subject: 'Your account has been enabled'\n            username_changed:\n                enabled: true\n                subject: 'Your username has been updated'\n            password_changed:\n                enabled: true\n                subject: 'Your password has been changed'\n",[355,1844,1845,1851,1857,1864,1871,1880,1893,1900,1908,1921,1928,1936,1949,1956,1964],{"__ignoreMap":406},[410,1846,1847,1849],{"class":412,"line":413},[410,1848,1055],{"class":920},[410,1850,924],{"class":438},[410,1852,1853,1855],{"class":412,"line":420},[410,1854,1553],{"class":920},[410,1856,924],{"class":438},[410,1858,1859,1862],{"class":412,"line":442},[410,1860,1861],{"class":920},"        emails",[410,1863,924],{"class":438},[410,1865,1866,1869],{"class":412,"line":449},[410,1867,1868],{"class":920},"            welcome",[410,1870,924],{"class":438},[410,1872,1873,1876,1878],{"class":412,"line":472},[410,1874,1875],{"class":920},"                enabled",[410,1877,399],{"class":438},[410,1879,1032],{"class":1031},[410,1881,1882,1884,1886,1888,1891],{"class":412,"line":498},[410,1883,1654],{"class":920},[410,1885,399],{"class":438},[410,1887,935],{"class":934},[410,1889,1890],{"class":808},"Welcome to {{ website_name }}",[410,1892,941],{"class":934},[410,1894,1895,1898],{"class":412,"line":522},[410,1896,1897],{"class":920},"            user_enabled",[410,1899,924],{"class":438},[410,1901,1902,1904,1906],{"class":412,"line":547},[410,1903,1875],{"class":920},[410,1905,399],{"class":438},[410,1907,1032],{"class":1031},[410,1909,1910,1912,1914,1916,1919],{"class":412,"line":552},[410,1911,1654],{"class":920},[410,1913,399],{"class":438},[410,1915,935],{"class":934},[410,1917,1918],{"class":808},"Your account has been enabled",[410,1920,941],{"class":934},[410,1922,1923,1926],{"class":412,"line":568},[410,1924,1925],{"class":920},"            username_changed",[410,1927,924],{"class":438},[410,1929,1930,1932,1934],{"class":412,"line":578},[410,1931,1875],{"class":920},[410,1933,399],{"class":438},[410,1935,1032],{"class":1031},[410,1937,1938,1940,1942,1944,1947],{"class":412,"line":594},[410,1939,1654],{"class":920},[410,1941,399],{"class":438},[410,1943,935],{"class":934},[410,1945,1946],{"class":808},"Your username has been updated",[410,1948,941],{"class":934},[410,1950,1951,1954],{"class":412,"line":602},[410,1952,1953],{"class":920},"            password_changed",[410,1955,924],{"class":438},[410,1957,1958,1960,1962],{"class":412,"line":618},[410,1959,1875],{"class":920},[410,1961,399],{"class":438},[410,1963,1032],{"class":1031},[410,1965,1966,1968,1970,1972,1975],{"class":412,"line":624},[410,1967,1654],{"class":920},[410,1969,399],{"class":438},[410,1971,935],{"class":934},[410,1973,1974],{"class":808},"Your password has been changed",[410,1976,941],{"class":934},[351,1978,1979,1980,1983],{},"Set ",[355,1981,1982],{},"MAILER_DSN"," in your environment:",[401,1985,1987],{"className":868,"code":1986,"language":870,"meta":406,"style":406},"MAILER_DSN=smtp:\u002F\u002Fuser:pass@smtp.example.com:587\n",[355,1988,1989],{"__ignoreMap":406},[410,1990,1991],{"class":412,"line":413},[410,1992,1986],{},[360,1994,1996],{"id":1995},"route-security","Route Security",[351,1998,1999],{},"Restrict which routes are visible in the API based on the current user's role:",[401,2001,2003],{"className":906,"code":2002,"language":908,"meta":406,"style":406},"silverback_api_components:\n    route_security:\n        - { route: '\u002Fuser-area*', security: \"is_granted('ROLE_USER')\" }\n        - { route: '\u002Fadmin*', security: \"is_granted('ROLE_ADMIN')\" }\n",[355,2004,2005,2011,2018,2054],{"__ignoreMap":406},[410,2006,2007,2009],{"class":412,"line":413},[410,2008,1055],{"class":920},[410,2010,924],{"class":438},[410,2012,2013,2016],{"class":412,"line":420},[410,2014,2015],{"class":920},"    route_security",[410,2017,924],{"class":438},[410,2019,2020,2022,2024,2027,2029,2031,2034,2036,2038,2041,2043,2046,2049,2052],{"class":412,"line":442},[410,2021,1255],{"class":438},[410,2023,1258],{"class":438},[410,2025,2026],{"class":920}," route",[410,2028,399],{"class":438},[410,2030,935],{"class":934},[410,2032,2033],{"class":808},"\u002Fuser-area*",[410,2035,1271],{"class":934},[410,2037,1274],{"class":438},[410,2039,2040],{"class":920}," security",[410,2042,399],{"class":438},[410,2044,2045],{"class":934}," \"",[410,2047,2048],{"class":808},"is_granted('ROLE_USER')",[410,2050,2051],{"class":934},"\"",[410,2053,1285],{"class":438},[410,2055,2056,2058,2060,2062,2064,2066,2069,2071,2073,2075,2077,2079,2082,2084],{"class":412,"line":449},[410,2057,1255],{"class":438},[410,2059,1258],{"class":438},[410,2061,2026],{"class":920},[410,2063,399],{"class":438},[410,2065,935],{"class":934},[410,2067,2068],{"class":808},"\u002Fadmin*",[410,2070,1271],{"class":934},[410,2072,1274],{"class":438},[410,2074,2040],{"class":920},[410,2076,399],{"class":438},[410,2078,2045],{"class":934},[410,2080,2081],{"class":808},"is_granted('ROLE_ADMIN')",[410,2083,2051],{"class":934},[410,2085,1285],{"class":438},[351,2087,2088,2091,2092,2095,2096,2099,2100,2102,2103,2106,2107,2109],{},[355,2089,2090],{},"route_security"," accepts any number of patterns. Each ",[355,2093,2094],{},"route"," value supports a ",[355,2097,2098],{},"*"," wildcard that matches any sequence of characters (internally converted to a regex — ",[355,2101,2098],{}," does not need to be a ",[355,2104,2105],{},"%","-style SQL wildcard). The ",[355,2108,1147],{}," value is any Symfony expression-language security expression.",[351,2111,2112],{},"Two things happen for each rule:",[2114,2115,2116,2134],"ul",{},[368,2117,2118,2121,2122,2125,2126,2129,2130,2133],{},[771,2119,2120],{},"Collection filtering"," — the ",[355,2123,2124],{},"Route"," collection endpoint (",[355,2127,2128],{},"GET \u002F_\u002Froutes",") omits routes matching the pattern when the expression is not satisfied. Anonymous users won't see ",[355,2131,2132],{},"\u002Fadmin\u002F*"," routes at all.",[368,2135,2136,2139,2140,2142],{},[771,2137,2138],{},"Item access"," — fetching a specific ",[355,2141,2124],{}," by IRI is denied if any matching rule's expression fails.",[360,2144,2146],{"id":2145},"routable_security",[355,2147,2145],{},[351,2149,2150,2151,2154,2155,2158],{},"Controls who can ",[771,2152,2153],{},"read"," un-routed pages and page data, and who can ",[771,2156,2157],{},"create"," new pages and page data:",[401,2160,2162],{"className":906,"code":2161,"language":908,"meta":406,"style":406},"silverback_api_components:\n    routable_security: \"is_granted('ROLE_ADMIN')\"\n",[355,2163,2164,2170],{"__ignoreMap":406},[410,2165,2166,2168],{"class":412,"line":413},[410,2167,1055],{"class":920},[410,2169,924],{"class":438},[410,2171,2172,2175,2177,2179,2181],{"class":412,"line":420},[410,2173,2174],{"class":920},"    routable_security",[410,2176,399],{"class":438},[410,2178,2045],{"class":934},[410,2180,2081],{"class":808},[410,2182,2183],{"class":934},"\"\n",[351,2185,2186,2187,1759,2190,2193,2194,2197],{},"Without this, every ",[355,2188,2189],{},"Page",[355,2191,2192],{},"PageData"," record is visible in API collections regardless of whether it has a public route. This matters for template pages (",[355,2195,2196],{},"isTemplate: true",") and draft pages — they exist in the database but have no URL.",[351,2199,2200,2201,2203],{},"When ",[355,2202,2145],{}," is set:",[351,2205,2206],{},[771,2207,2208],{},"GET (read access)",[2114,2210,2211,2218],{},[368,2212,2213,2214,2217],{},"Users who ",[771,2215,2216],{},"pass"," the expression see all records (including un-routed ones).",[368,2219,2213,2220,2223,2224,2226],{},[771,2221,2222],{},"fail"," the expression only see records that have a ",[355,2225,2094],{}," assigned — i.e., publicly accessible pages.",[351,2228,2229],{},"This prevents anonymous users from discovering admin-only templates or draft content through the collection endpoints.",[351,2231,2232,2235,2236,2238,2239,2241,2242,2244],{},[771,2233,2234],{},"POST (create access)","\nCreating a new ",[355,2237,2189],{}," or ",[355,2240,2192],{}," resource requires the ",[355,2243,2145],{}," expression to pass. This matches the existing restriction on edit operations — both creating and modifying CMS structure require admin access.",[360,2246,2248],{"id":2247},"component-security","Component Security",[351,2250,2251,2252,2255],{},"Components are automatically secured based on the routes they are reachable through. You do not need to configure this — it is built into the bundle via ",[355,2253,2254],{},"ComponentVoter",".",[351,2257,2258,2259,2261],{},"When a ",[355,2260,1476],{}," request is made for a specific component IRI, the bundle checks whether that component is accessible to the current user by:",[365,2263,2264,2270,2279,2285],{},[368,2265,2266,2269],{},[771,2267,2268],{},"Route check"," — is the component part of a page that has a publicly accessible route? If yes, access is granted.",[368,2271,2272,2275,2276,2278],{},[771,2273,2274],{},"PageData check"," — is the component referenced as a property on a ",[355,2277,2192],{}," resource with a reachable route? If yes, access is granted.",[368,2280,2281,2284],{},[771,2282,2283],{},"Template check"," — is the component placed in a page template used by reachable page data? If yes, access is granted.",[368,2286,2287],{},"If none of the above resolve (the component is genuinely unreachable for this user), access is denied.",[351,2289,2290],{},"This means components placed exclusively on admin pages are automatically hidden from anonymous API clients without any extra configuration.",[360,2292,2294],{"id":2293},"creating-the-first-admin-user","Creating the First Admin User",[401,2296,2298],{"className":792,"code":2297,"language":794,"meta":406,"style":406},"bin\u002Fconsole silverback:api-components:user:create\n",[355,2299,2300],{"__ignoreMap":406},[410,2301,2302,2305],{"class":412,"line":413},[410,2303,2304],{"class":427},"bin\u002Fconsole",[410,2306,2307],{"class":808}," silverback:api-components:user:create\n",[351,2309,2310,2311,2313],{},"You'll be prompted for username, email, and password. Without flags, the user is created with ",[355,2312,708],{}," only.",[640,2315,2316,2326],{},[643,2317,2318],{},[646,2319,2320,2323],{},[649,2321,2322],{},"Flag",[649,2324,2325],{},"Role granted",[659,2327,2328,2340,2352],{},[646,2329,2330,2336],{},[664,2331,2332],{},[2333,2334,2335],"em",{},"(none)",[664,2337,2338],{},[355,2339,708],{},[646,2341,2342,2347],{},[664,2343,2344],{},[355,2345,2346],{},"--admin",[664,2348,2349],{},[355,2350,2351],{},"ROLE_ADMIN",[646,2353,2354,2359],{},[664,2355,2356],{},[355,2357,2358],{},"--super-admin",[664,2360,2361],{},[355,2362,2363],{},"ROLE_SUPER_ADMIN",[351,2365,2366],{},"To create an admin non-interactively:",[401,2368,2370],{"className":792,"code":2369,"language":794,"meta":406,"style":406},"bin\u002Fconsole silverback:api-components:user:create alice alice@example.com s3cr3t --admin\n",[355,2371,2372],{"__ignoreMap":406},[410,2373,2374,2376,2379,2382,2385,2388],{"class":412,"line":413},[410,2375,2304],{"class":427},[410,2377,2378],{"class":808}," silverback:api-components:user:create",[410,2380,2381],{"class":808}," alice",[410,2383,2384],{"class":808}," alice@example.com",[410,2386,2387],{"class":808}," s3cr3t",[410,2389,2390],{"class":804}," --admin\n",[2392,2393,2394],"style",{},"html pre.shiki code .sTBSN, html code.shiki .sTBSN{--shiki-light:#6A737D;--shiki-light-font-style:inherit;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .stmX-, html code.shiki .stmX-{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F78C6C}html pre.shiki code .sRCss, html code.shiki .sRCss{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#FFCB6B}html pre.shiki code .sn4go, html code.shiki .sn4go{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#89DDFF}html pre.shiki code .sOvfz, html code.shiki .sOvfz{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#89DDFF}html pre.shiki code .sc2zw, html code.shiki .sc2zw{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#BABED8}html pre.shiki code .sBtbT, html code.shiki .sBtbT{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#89DDFF}html pre.shiki code .sPB8G, html code.shiki .sPB8G{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#BABED8}html pre.shiki code .swB56, html code.shiki .swB56{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#C792EA}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 .szhYu, html code.shiki .szhYu{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#C3E88D}html pre.shiki code .sLL54, html code.shiki .sLL54{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#C3E88D}html pre.shiki code .s-h7I, html code.shiki .s-h7I{--shiki-light:#22863A;--shiki-default:#85E89D;--shiki-dark:#F07178}html pre.shiki code .seSrl, html code.shiki .seSrl{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#89DDFF}html pre.shiki code .scSvc, html code.shiki .scSvc{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#F78C6C}html pre.shiki code .swWMF, html code.shiki .swWMF{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#FF9CAC}",{"title":406,"searchDepth":420,"depth":420,"links":2396},[2397,2398,2401,2402,2403,2404,2405,2406,2407,2408,2409,2410,2411,2412],{"id":362,"depth":420,"text":363},{"id":388,"depth":420,"text":389,"children":2399},[2400],{"id":637,"depth":442,"text":638},{"id":785,"depth":420,"text":786},{"id":899,"depth":420,"text":900},{"id":1044,"depth":420,"text":1045},{"id":1129,"depth":420,"text":1130},{"id":1530,"depth":420,"text":1531},{"id":1669,"depth":420,"text":1670},{"id":1766,"depth":420,"text":1767},{"id":1835,"depth":420,"text":1836},{"id":1995,"depth":420,"text":1996},{"id":2145,"depth":420,"text":2145},{"id":2247,"depth":420,"text":2248},{"id":2293,"depth":420,"text":2294},"JWT cookie authentication, the AbstractUser entity, email verification, password reset, and Symfony security configuration.","md",null,{},{"title":121,"description":2413},"8snx8yt_sWsm1hA4UaKI1jdsRVbMyNDcduHs33k6rag",[2420,2422],{"title":117,"path":118,"stem":119,"description":2421,"children":-1},"Build blogs, event listings, and multi-level page hierarchies using AbstractPageData and nested Page relationships.",{"title":125,"path":126,"stem":127,"description":2423,"children":-1},"Use AbstractCwaScaffold and CwaFixtureBuilder to seed your database with layouts, pages, routes, components, and page data in a fluent API.",1782241280811]