[{"data":1,"prerenderedAt":2840},["ShallowReactive",2],{"navigation_docs":3,"-modules-identity-authorization-roles-and-requirements":587,"-modules-identity-authorization-roles-and-requirements-surround":2835},[4,50,155,441,504],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":49},"Get Started","i-lucide-rocket","\u002Fget-started","1.get-started",[10,15,20,25,30,35,40,45],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fget-started\u002Fintroduction","1.get-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fget-started\u002Finstallation","1.get-started\u002F2.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":24},"Project structure","\u002Fget-started\u002Fproject-structure","1.get-started\u002F3.project-structure","i-lucide-folder-tree",{"title":26,"path":27,"stem":28,"icon":29},"Configuration","\u002Fget-started\u002Fconfiguration","1.get-started\u002F4.configuration","i-lucide-settings",{"title":31,"path":32,"stem":33,"icon":34},"Authentication","\u002Fget-started\u002Fauthentication","1.get-started\u002F5.authentication","i-lucide-lock",{"title":36,"path":37,"stem":38,"icon":39},"Adding modules","\u002Fget-started\u002Fadding-modules","1.get-started\u002F6.adding-modules","i-lucide-puzzle",{"title":41,"path":42,"stem":43,"icon":44},"Database","\u002Fget-started\u002Fdatabase","1.get-started\u002F7.database","i-lucide-database",{"title":46,"path":47,"stem":48,"icon":6},"Deployment","\u002Fget-started\u002Fdeployment","1.get-started\u002F8.deployment",false,{"title":51,"icon":52,"path":53,"stem":54,"children":55,"page":49},"Guide","i-lucide-book-open","\u002Fguide","2.guide",[56,90,115,125],{"title":57,"icon":49,"path":58,"stem":59,"children":60,"page":49},"Concepts","\u002Fguide\u002Fconcepts","2.guide\u002F1.concepts",[61,66,71,76,80,85],{"title":62,"path":63,"stem":64,"icon":65},"Architecture","\u002Fguide\u002Fconcepts\u002Farchitecture","2.guide\u002F1.concepts\u002F1.architecture","i-lucide-blocks",{"title":67,"path":68,"stem":69,"icon":70},"Access control","\u002Fguide\u002Fconcepts\u002Fauth-and-scopes","2.guide\u002F1.concepts\u002F2.auth-and-scopes","i-lucide-shield-check",{"title":72,"path":73,"stem":74,"icon":75},"Extension points","\u002Fguide\u002Fconcepts\u002Fextension-points","2.guide\u002F1.concepts\u002F3.extension-points","i-lucide-plug",{"title":77,"path":78,"stem":79,"icon":44},"Database extensions","\u002Fguide\u002Fconcepts\u002Fdatabase-extensions","2.guide\u002F1.concepts\u002F4.database-extensions",{"title":81,"path":82,"stem":83,"icon":84},"Identity","\u002Fguide\u002Fconcepts\u002Fidentity","2.guide\u002F1.concepts\u002F5.identity","i-lucide-fingerprint",{"title":86,"path":87,"stem":88,"icon":89},"Glossary","\u002Fguide\u002Fconcepts\u002Fglossary","2.guide\u002F1.concepts\u002F6.glossary","i-lucide-book-a",{"title":91,"icon":49,"path":92,"stem":93,"children":94,"page":49},"UX patterns","\u002Fguide\u002Fux-patterns","2.guide\u002F2.ux-patterns",[95,100,105,110],{"title":96,"path":97,"stem":98,"icon":99},"Layouts and navigation","\u002Fguide\u002Fux-patterns\u002Flayouts-and-navigation","2.guide\u002F2.ux-patterns\u002F1.layouts-and-navigation","i-lucide-layout-template",{"title":101,"path":102,"stem":103,"icon":104},"Pages","\u002Fguide\u002Fux-patterns\u002Fpages","2.guide\u002F2.ux-patterns\u002F2.pages","i-lucide-table",{"title":106,"path":107,"stem":108,"icon":109},"Forms and actions","\u002Fguide\u002Fux-patterns\u002Fforms-and-actions","2.guide\u002F2.ux-patterns\u002F3.forms-and-actions","i-lucide-square-pen",{"title":111,"path":112,"stem":113,"icon":114},"Text and formatting","\u002Fguide\u002Fux-patterns\u002Ftext-and-formatting","2.guide\u002F2.ux-patterns\u002F4.text-and-formatting","i-lucide-type",{"title":116,"icon":49,"path":117,"stem":118,"children":119,"page":49},"Best practices","\u002Fguide\u002Fbest-practices","2.guide\u002F3.best-practices",[120],{"title":121,"path":122,"stem":123,"icon":124},"HTTP routes","\u002Fguide\u002Fbest-practices\u002Fhttp-routes","2.guide\u002F3.best-practices\u002F1.http-routes","i-lucide-route",{"title":126,"icon":49,"path":127,"stem":128,"children":129,"page":49},"Going further","\u002Fguide\u002Fgoing-further","2.guide\u002F4.going-further",[130,135,140,145,150],{"title":131,"path":132,"stem":133,"icon":134},"Use your own OAuth server","\u002Fguide\u002Fgoing-further\u002Fown-oauth-server","2.guide\u002F4.going-further\u002F1.own-oauth-server","i-lucide-key-round",{"title":136,"path":137,"stem":138,"icon":139},"Create an OAuth application","\u002Fguide\u002Fgoing-further\u002Foauth-application","2.guide\u002F4.going-further\u002F2.oauth-application","i-lucide-app-window",{"title":141,"path":142,"stem":143,"icon":144},"Signing keys","\u002Fguide\u002Fgoing-further\u002Fsigning-keys","2.guide\u002F4.going-further\u002F3.signing-keys","i-lucide-key-square",{"title":146,"path":147,"stem":148,"icon":149},"Stripe setup","\u002Fguide\u002Fgoing-further\u002Fstripe-setup","2.guide\u002F4.going-further\u002F4.stripe-setup","i-lucide-credit-card",{"title":151,"path":152,"stem":153,"icon":154},"Migrate to the permission model","\u002Fguide\u002Fgoing-further\u002Fmigrate-access-control","2.guide\u002F4.going-further\u002F5.migrate-access-control","i-lucide-arrow-right-left",{"title":156,"icon":157,"path":158,"stem":159,"children":160},"Modules","i-lucide-boxes","\u002Fmodules","3.modules",[161,163,244,273,320,375],{"title":156,"path":158,"stem":162},"3.modules\u002Findex",{"title":81,"icon":49,"path":164,"stem":165,"children":166,"page":49},"\u002Fmodules\u002Fidentity","3.modules\u002F1.identity",[167,190,194,198,220,224,240],{"title":168,"path":169,"stem":170,"children":171},"Auth","\u002Fmodules\u002Fidentity\u002Fauth","3.modules\u002F1.identity\u002F1.auth\u002Findex",[172,174,178,182,186],{"title":173,"path":169,"stem":170},"Overview",{"title":175,"path":176,"stem":177},"Server API","\u002Fmodules\u002Fidentity\u002Fauth\u002Fserver","3.modules\u002F1.identity\u002F1.auth\u002F2.server",{"title":179,"path":180,"stem":181},"Reference","\u002Fmodules\u002Fidentity\u002Fauth\u002Freference","3.modules\u002F1.identity\u002F1.auth\u002F3.reference",{"title":183,"path":184,"stem":185},"Client mode","\u002Fmodules\u002Fidentity\u002Fauth\u002Fclient-mode","3.modules\u002F1.identity\u002F1.auth\u002F4.client-mode",{"title":187,"path":188,"stem":189},"OAuth providers","\u002Fmodules\u002Fidentity\u002Fauth\u002Foauth-providers","3.modules\u002F1.identity\u002F1.auth\u002F5.oauth-providers",{"title":191,"path":192,"stem":193},"Users","\u002Fmodules\u002Fidentity\u002Fusers","3.modules\u002F1.identity\u002F2.users",{"title":195,"path":196,"stem":197},"Account","\u002Fmodules\u002Fidentity\u002Faccount","3.modules\u002F1.identity\u002F3.account",{"title":199,"path":200,"stem":201,"children":202},"Authorization","\u002Fmodules\u002Fidentity\u002Fauthorization","3.modules\u002F1.identity\u002F4.authorization\u002Findex",[203,204,208,212,216],{"title":173,"path":200,"stem":201},{"title":205,"path":206,"stem":207},"Roles and requirements","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Froles-and-requirements","3.modules\u002F1.identity\u002F4.authorization\u002F2.roles-and-requirements",{"title":209,"path":210,"stem":211},"Policies","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Fpolicies","3.modules\u002F1.identity\u002F4.authorization\u002F3.policies",{"title":213,"path":214,"stem":215},"Client","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Fclient","3.modules\u002F1.identity\u002F4.authorization\u002F4.client",{"title":217,"path":218,"stem":219},"Admin","\u002Fmodules\u002Fidentity\u002Fauthorization\u002Fadmin","3.modules\u002F1.identity\u002F4.authorization\u002F5.admin",{"title":221,"path":222,"stem":223},"Preferences","\u002Fmodules\u002Fidentity\u002Fpreferences","3.modules\u002F1.identity\u002F5.preferences",{"title":225,"path":226,"stem":227,"children":228},"OAuth Server","\u002Fmodules\u002Fidentity\u002Foauth-server","3.modules\u002F1.identity\u002F6.oauth-server\u002Findex",[229,230,233,237],{"title":173,"path":226,"stem":227},{"title":175,"path":231,"stem":232},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Fserver","3.modules\u002F1.identity\u002F6.oauth-server\u002F2.server",{"title":234,"path":235,"stem":236},"Hooks","\u002Fmodules\u002Fidentity\u002Foauth-server\u002Fhooks","3.modules\u002F1.identity\u002F6.oauth-server\u002F3.hooks",{"title":179,"path":238,"stem":239},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Froutes-and-clients","3.modules\u002F1.identity\u002F6.oauth-server\u002F4.routes-and-clients",{"title":241,"path":242,"stem":243},"OAuth Resource","\u002Fmodules\u002Fidentity\u002Foauth-resource","3.modules\u002F1.identity\u002F8.oauth-resource",{"title":245,"icon":49,"path":246,"stem":247,"children":248,"page":49},"Commerce","\u002Fmodules\u002Fcommerce","3.modules\u002F2.commerce",[249,253,257],{"title":250,"path":251,"stem":252},"Stripe","\u002Fmodules\u002Fcommerce\u002Fstripe","3.modules\u002F2.commerce\u002F1.stripe",{"title":254,"path":255,"stem":256},"Payments","\u002Fmodules\u002Fcommerce\u002Fpayments","3.modules\u002F2.commerce\u002F2.payments",{"title":258,"path":259,"stem":260,"children":261},"Subscriptions","\u002Fmodules\u002Fcommerce\u002Fsubscriptions","3.modules\u002F2.commerce\u002F3.subscriptions\u002Findex",[262,263,266,270],{"title":173,"path":259,"stem":260},{"title":175,"path":264,"stem":265},"\u002Fmodules\u002Fcommerce\u002Fsubscriptions\u002Fserver","3.modules\u002F2.commerce\u002F3.subscriptions\u002F2.server",{"title":267,"path":268,"stem":269},"App","\u002Fmodules\u002Fcommerce\u002Fsubscriptions\u002Fapp","3.modules\u002F2.commerce\u002F3.subscriptions\u002F3.app",{"title":179,"path":271,"stem":272},"\u002Fmodules\u002Fcommerce\u002Fsubscriptions\u002Freference","3.modules\u002F2.commerce\u002F3.subscriptions\u002F4.reference",{"title":274,"icon":49,"path":275,"stem":276,"children":277,"page":49},"Features","\u002Fmodules\u002Ffeatures","3.modules\u002F3.features",[278,293,312,316],{"title":279,"path":280,"stem":281,"children":282},"Events","\u002Fmodules\u002Ffeatures\u002Fevents","3.modules\u002F3.features\u002F1.events\u002Findex",[283,284,287,290],{"title":173,"path":280,"stem":281},{"title":175,"path":285,"stem":286},"\u002Fmodules\u002Ffeatures\u002Fevents\u002Fserver","3.modules\u002F3.features\u002F1.events\u002F2.server",{"title":267,"path":288,"stem":289},"\u002Fmodules\u002Ffeatures\u002Fevents\u002Fapp","3.modules\u002F3.features\u002F1.events\u002F3.app",{"title":179,"path":291,"stem":292},"\u002Fmodules\u002Ffeatures\u002Fevents\u002Freference","3.modules\u002F3.features\u002F1.events\u002F4.reference",{"title":294,"path":295,"stem":296,"children":297},"Forms","\u002Fmodules\u002Ffeatures\u002Fforms","3.modules\u002F3.features\u002F2.forms\u002Findex",[298,299,303,306,309],{"title":173,"path":295,"stem":296},{"title":300,"path":301,"stem":302},"Definition","\u002Fmodules\u002Ffeatures\u002Fforms\u002Fdefinition","3.modules\u002F3.features\u002F2.forms\u002F2.definition",{"title":175,"path":304,"stem":305},"\u002Fmodules\u002Ffeatures\u002Fforms\u002Fserver","3.modules\u002F3.features\u002F2.forms\u002F3.server",{"title":267,"path":307,"stem":308},"\u002Fmodules\u002Ffeatures\u002Fforms\u002Fapp","3.modules\u002F3.features\u002F2.forms\u002F4.app",{"title":179,"path":310,"stem":311},"\u002Fmodules\u002Ffeatures\u002Fforms\u002Freference","3.modules\u002F3.features\u002F2.forms\u002F5.reference",{"title":313,"path":314,"stem":315},"Cookie Consent","\u002Fmodules\u002Ffeatures\u002Fcookie-consent","3.modules\u002F3.features\u002F3.cookie-consent",{"title":317,"path":318,"stem":319},"MCP","\u002Fmodules\u002Ffeatures\u002Fmcp","3.modules\u002F3.features\u002F4.mcp",{"title":321,"icon":49,"path":322,"stem":323,"children":324,"page":49},"Interface","\u002Fmodules\u002Finterface","3.modules\u002F4.interface",[325,350,353,357,361],{"title":326,"path":327,"stem":328,"children":329},"UI","\u002Fmodules\u002Finterface\u002Fui","3.modules\u002F4.interface\u002F1.ui\u002Findex",[330,331,335,339,343,347],{"title":173,"path":327,"stem":328},{"title":332,"path":333,"stem":334},"Page components","\u002Fmodules\u002Finterface\u002Fui\u002Fpage-components","3.modules\u002F4.interface\u002F1.ui\u002F2.page-components",{"title":336,"path":337,"stem":338},"App shell","\u002Fmodules\u002Finterface\u002Fui\u002Fapp-shell","3.modules\u002F4.interface\u002F1.ui\u002F3.app-shell",{"title":340,"path":341,"stem":342},"Form inputs","\u002Fmodules\u002Finterface\u002Fui\u002Fform-inputs","3.modules\u002F4.interface\u002F1.ui\u002F4.form-inputs",{"title":344,"path":345,"stem":346},"Composables and helpers","\u002Fmodules\u002Finterface\u002Fui\u002Fcomposables","3.modules\u002F4.interface\u002F1.ui\u002F5.composables",{"title":179,"path":348,"stem":349},"\u002Fmodules\u002Finterface\u002Fui\u002Freference","3.modules\u002F4.interface\u002F1.ui\u002F6.reference",{"title":217,"path":351,"stem":352},"\u002Fmodules\u002Finterface\u002Fadmin","3.modules\u002F4.interface\u002F2.admin",{"title":354,"path":355,"stem":356},"Menu","\u002Fmodules\u002Finterface\u002Fmenu","3.modules\u002F4.interface\u002F3.menu",{"title":358,"path":359,"stem":360},"Widget","\u002Fmodules\u002Finterface\u002Fwidget","3.modules\u002F4.interface\u002F4.widget",{"title":362,"path":363,"stem":364,"children":365},"Mobile","\u002Fmodules\u002Finterface\u002Fmobile","3.modules\u002F4.interface\u002F5.mobile\u002Findex",[366,367,371],{"title":173,"path":363,"stem":364},{"title":368,"path":369,"stem":370},"CLI and devices","\u002Fmodules\u002Finterface\u002Fmobile\u002Fcli-and-devices","3.modules\u002F4.interface\u002F5.mobile\u002F2.cli-and-devices",{"title":372,"path":373,"stem":374},"Splash screen","\u002Fmodules\u002Finterface\u002Fmobile\u002Fsplash-screen","3.modules\u002F4.interface\u002F5.mobile\u002F3.splash-screen",{"title":376,"icon":49,"path":377,"stem":378,"children":379,"page":49},"Platform","\u002Fmodules\u002Fplatform","3.modules\u002F5.platform",[380,402,406,423],{"title":381,"path":382,"stem":383,"children":384},"Module Kit","\u002Fmodules\u002Fplatform\u002Fmodule-kit","3.modules\u002F5.platform\u002F1.module-kit\u002Findex",[385,386,390,394,398],{"title":173,"path":382,"stem":383},{"title":387,"path":388,"stem":389},"Server toolkit","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fserver-toolkit","3.modules\u002F5.platform\u002F1.module-kit\u002F2.server-toolkit",{"title":391,"path":392,"stem":393},"Registries and menus","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fregistries-and-menus","3.modules\u002F5.platform\u002F1.module-kit\u002F3.registries-and-menus",{"title":395,"path":396,"stem":397},"Translations","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fi18n","3.modules\u002F5.platform\u002F1.module-kit\u002F4.i18n",{"title":399,"path":400,"stem":401},"Database helpers","\u002Fmodules\u002Fplatform\u002Fmodule-kit\u002Fdatabase","3.modules\u002F5.platform\u002F1.module-kit\u002F5.database",{"title":403,"path":404,"stem":405},"Notify","\u002Fmodules\u002Fplatform\u002Fnotify","3.modules\u002F5.platform\u002F2.notify",{"title":407,"path":408,"stem":409,"children":410},"Email Templates","\u002Fmodules\u002Fplatform\u002Femail-templates","3.modules\u002F5.platform\u002F3.email-templates\u002Findex",[411,412,416,419],{"title":173,"path":408,"stem":409},{"title":413,"path":414,"stem":415},"Email components","\u002Fmodules\u002Fplatform\u002Femail-templates\u002Fcomponents","3.modules\u002F5.platform\u002F3.email-templates\u002F2.components",{"title":175,"path":417,"stem":418},"\u002Fmodules\u002Fplatform\u002Femail-templates\u002Fserver","3.modules\u002F5.platform\u002F3.email-templates\u002F3.server",{"title":420,"path":421,"stem":422},"Module emails","\u002Fmodules\u002Fplatform\u002Femail-templates\u002Fmodule-emails","3.modules\u002F5.platform\u002F3.email-templates\u002F4.module-emails",{"title":424,"path":425,"stem":426,"children":427},"Base Layer","\u002Fmodules\u002Fplatform\u002Fbase-layer","3.modules\u002F5.platform\u002F4.base-layer\u002Findex",[428,429,433,437],{"title":173,"path":425,"stem":426},{"title":430,"path":431,"stem":432},"Content collections","\u002Fmodules\u002Fplatform\u002Fbase-layer\u002Fcontent-collections","3.modules\u002F5.platform\u002F4.base-layer\u002F2.content-collections",{"title":434,"path":435,"stem":436},"Layouts and routing","\u002Fmodules\u002Fplatform\u002Fbase-layer\u002Flayouts-and-routing","3.modules\u002F5.platform\u002F4.base-layer\u002F3.layouts-and-routing",{"title":438,"path":439,"stem":440},"Composables and utils","\u002Fmodules\u002Fplatform\u002Fbase-layer\u002Fcomposables-and-utils","3.modules\u002F5.platform\u002F4.base-layer\u002F4.composables-and-utils",{"title":442,"icon":443,"path":444,"stem":445,"children":446,"page":49},"Examples","i-lucide-code-xml","\u002Fexamples","4.examples",[447,466,476],{"title":448,"icon":49,"path":449,"stem":450,"children":451,"page":49},"Starters","\u002Fexamples\u002Fstarters","4.examples\u002F1.starters",[452,456,461],{"title":453,"path":454,"stem":455,"icon":6},"Workspace starter","\u002Fexamples\u002Fstarters\u002Fworkspace","4.examples\u002F1.starters\u002F1.workspace",{"title":457,"path":458,"stem":459,"icon":460},"Mobile starter","\u002Fexamples\u002Fstarters\u002Fmobile","4.examples\u002F1.starters\u002F2.mobile","i-lucide-smartphone",{"title":462,"path":463,"stem":464,"icon":465},"Standalone mobile starter","\u002Fexamples\u002Fstarters\u002Fmobile-standalone","4.examples\u002F1.starters\u002F3.mobile-standalone","i-lucide-tablet-smartphone",{"title":467,"icon":49,"path":468,"stem":469,"children":470,"page":49},"Apps","\u002Fexamples\u002Fapps","4.examples\u002F2.apps",[471],{"title":472,"path":473,"stem":474,"icon":475},"Frigear website app","\u002Fexamples\u002Fapps\u002Ffrigear-nu-website","4.examples\u002F2.apps\u002F1.frigear-nu-website","i-lucide-layout-dashboard",{"title":477,"icon":49,"path":478,"stem":479,"children":480,"page":49},"Tasks","\u002Fexamples\u002Ftasks","4.examples\u002F3.tasks",[481,485,489,494,499],{"title":482,"path":483,"stem":484,"icon":70},"Protect a route","\u002Fexamples\u002Ftasks\u002Fprotect-a-route","4.examples\u002F3.tasks\u002F1.protect-a-route",{"title":486,"path":487,"stem":488,"icon":475},"Add an admin page","\u002Fexamples\u002Ftasks\u002Fadd-an-admin-page","4.examples\u002F3.tasks\u002F2.add-an-admin-page",{"title":490,"path":491,"stem":492,"icon":493},"Sell event tickets","\u002Fexamples\u002Ftasks\u002Fsell-event-tickets","4.examples\u002F3.tasks\u002F3.sell-event-tickets","i-lucide-ticket",{"title":495,"path":496,"stem":497,"icon":498},"Build a form","\u002Fexamples\u002Ftasks\u002Fbuild-a-form","4.examples\u002F3.tasks\u002F4.build-a-form","i-lucide-clipboard-list",{"title":500,"path":501,"stem":502,"icon":503},"Send an email","\u002Fexamples\u002Ftasks\u002Fsend-an-email","4.examples\u002F3.tasks\u002F5.send-an-email","i-lucide-mail",{"title":505,"icon":506,"path":507,"stem":508,"children":509,"page":49},"Contribute","i-lucide-git-pull-request","\u002Fcontribute","5.contribute",[510,513,518,544,549,552,556,571],{"title":173,"path":511,"stem":512,"icon":506},"\u002Fcontribute\u002Foverview","5.contribute\u002F1.overview",{"title":514,"path":515,"stem":516,"icon":517},"Local development","\u002Fcontribute\u002Flocal-development","5.contribute\u002F2.local-development","i-lucide-terminal",{"title":519,"icon":49,"path":520,"stem":521,"children":522,"page":49},"Writing a module","\u002Fcontribute\u002Fwriting-a-module","5.contribute\u002F3.writing-a-module",[523,527,532,536,541],{"title":524,"path":525,"stem":526,"icon":39},"Scaffold a module","\u002Fcontribute\u002Fwriting-a-module\u002Fscaffold","5.contribute\u002F3.writing-a-module\u002F1.scaffold",{"title":528,"path":529,"stem":530,"icon":531},"Setup checklist","\u002Fcontribute\u002Fwriting-a-module\u002Fsetup-checklist","5.contribute\u002F3.writing-a-module\u002F2.setup-checklist","i-lucide-list-checks",{"title":533,"path":534,"stem":535,"icon":44},"Database tables","\u002Fcontribute\u002Fwriting-a-module\u002Fdatabase-tables","5.contribute\u002F3.writing-a-module\u002F3.database-tables",{"title":537,"path":538,"stem":539,"icon":540},"Testing","\u002Fcontribute\u002Fwriting-a-module\u002Ftesting","5.contribute\u002F3.writing-a-module\u002F4.testing","i-lucide-flask-conical",{"title":67,"path":542,"stem":543,"icon":70},"\u002Fcontribute\u002Fwriting-a-module\u002Faccess-control","5.contribute\u002F3.writing-a-module\u002F5.access-control",{"title":545,"path":546,"stem":547,"icon":548},"Publishing","\u002Fcontribute\u002Fpublishing","5.contribute\u002F4.publishing","i-lucide-package-check",{"title":448,"path":550,"stem":551,"icon":6},"\u002Fcontribute\u002Fstarters","5.contribute\u002F5.starters",{"title":553,"path":554,"stem":555,"icon":52},"Documentation","\u002Fcontribute\u002Fdocumentation","5.contribute\u002F6.documentation",{"title":557,"icon":49,"path":558,"stem":559,"children":560,"page":49},"Tooling","\u002Fcontribute\u002Ftooling","5.contribute\u002F7.tooling",[561,566],{"title":562,"path":563,"stem":564,"icon":565},"CLI","\u002Fcontribute\u002Ftooling\u002Fcli","5.contribute\u002F7.tooling\u002F1.cli","i-lucide-square-terminal",{"title":567,"path":568,"stem":569,"icon":570},"ESLint config","\u002Fcontribute\u002Ftooling\u002Feslint-config","5.contribute\u002F7.tooling\u002F2.eslint-config","i-lucide-spell-check",{"title":572,"icon":49,"path":573,"stem":574,"children":575},"Decisions","\u002Fcontribute\u002Fdecisions","5.contribute\u002F8.decisions\u002Findex",[576,578,583],{"title":572,"path":573,"stem":574,"icon":577},"i-lucide-scale",{"title":579,"path":580,"stem":581,"icon":582},"Session lifetimes per OAuth client","\u002Fcontribute\u002Fdecisions\u002Foauth-token-lifetimes","5.contribute\u002F8.decisions\u002F1.oauth-token-lifetimes","i-lucide-timer",{"title":584,"path":585,"stem":586,"icon":70},"One permission model","\u002Fcontribute\u002Fdecisions\u002Fpermission-model","5.contribute\u002F8.decisions\u002F2.permission-model",{"id":588,"title":205,"body":589,"description":2828,"extension":2829,"links":2830,"meta":2831,"navigation":2832,"path":206,"seo":2833,"stem":207,"__hash__":2834},"docs\u002F3.modules\u002F1.identity\u002F4.authorization\u002F2.roles-and-requirements.md",{"type":590,"value":591,"toc":2809},"minimark",[592,605,610,961,1113,1265,1270,1287,1435,1511,1514,1561,1588,1596,1599,1626,1630,1636,1710,1825,1829,1850,1853,1856,1973,1976,1982,2080,2091,2151,2278,2308,2312,2315,2352,2364,2367,2512,2519,2523,2550,2618,2627,2637,2703,2707,2717,2724,2730,2766,2784,2788,2805],[593,594,595,596,600,601,604],"p",{},"A ",[597,598,599],"strong",{},"role"," is a named bundle of permissions. A user holds several roles, and what they may do is the union of what the\nroles grant. This page explains how a role is defined, how modules and your app merge their definitions, where a user's\nroles come from, and how roles are assigned. Set up the module first: ",[602,603,173],"a",{"href":200},".",[606,607,609],"h2",{"id":608},"define-a-role","Define a role",[611,612,618],"pre",{"className":613,"code":614,"filename":615,"language":616,"meta":617,"style":617},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { defineRoles } from '@frigear-nu\u002Fauth\u002Faccess'\n\nexport default defineNuxtConfig({\n  authorization: {\n    defaultRoles: ['user'],\n    roles: defineRoles({\n      coordinator: {\n        label: 'Coordinator',\n        grant: ['forms:*', 'users:read', 'users:list'],\n        inherit: ['eventmanager'],\n      },\n      member: {\n        label: 'Member',\n        grant: ['member-area:view'],\n        requirements: { subscription: '*' },\n        auto: true,\n        inherit: ['user'],\n      },\n    }),\n  },\n})\n","nuxt.config.ts","ts","",[619,620,621,654,661,680,693,718,732,742,759,799,820,826,836,852,872,897,911,930,935,946,952],"code",{"__ignoreMap":617},[622,623,626,630,634,638,641,644,647,651],"span",{"class":624,"line":625},"line",1,[622,627,629],{"class":628},"s7zQu","import",[622,631,633],{"class":632},"sMK4o"," {",[622,635,637],{"class":636},"sTEyZ"," defineRoles",[622,639,640],{"class":632}," }",[622,642,643],{"class":628}," from",[622,645,646],{"class":632}," '",[622,648,650],{"class":649},"sfazB","@frigear-nu\u002Fauth\u002Faccess",[622,652,653],{"class":632},"'\n",[622,655,657],{"class":624,"line":656},2,[622,658,660],{"emptyLinePlaceholder":659},true,"\n",[622,662,664,667,670,674,677],{"class":624,"line":663},3,[622,665,666],{"class":628},"export",[622,668,669],{"class":628}," default",[622,671,673],{"class":672},"s2Zo4"," defineNuxtConfig",[622,675,676],{"class":636},"(",[622,678,679],{"class":632},"{\n",[622,681,683,687,690],{"class":624,"line":682},4,[622,684,686],{"class":685},"swJcz","  authorization",[622,688,689],{"class":632},":",[622,691,692],{"class":632}," {\n",[622,694,696,699,701,704,707,710,712,715],{"class":624,"line":695},5,[622,697,698],{"class":685},"    defaultRoles",[622,700,689],{"class":632},[622,702,703],{"class":636}," [",[622,705,706],{"class":632},"'",[622,708,709],{"class":649},"user",[622,711,706],{"class":632},[622,713,714],{"class":636},"]",[622,716,717],{"class":632},",\n",[622,719,721,724,726,728,730],{"class":624,"line":720},6,[622,722,723],{"class":685},"    roles",[622,725,689],{"class":632},[622,727,637],{"class":672},[622,729,676],{"class":636},[622,731,679],{"class":632},[622,733,735,738,740],{"class":624,"line":734},7,[622,736,737],{"class":685},"      coordinator",[622,739,689],{"class":632},[622,741,692],{"class":632},[622,743,745,748,750,752,755,757],{"class":624,"line":744},8,[622,746,747],{"class":685},"        label",[622,749,689],{"class":632},[622,751,646],{"class":632},[622,753,754],{"class":649},"Coordinator",[622,756,706],{"class":632},[622,758,717],{"class":632},[622,760,762,765,767,769,771,774,776,779,781,784,786,788,790,793,795,797],{"class":624,"line":761},9,[622,763,764],{"class":685},"        grant",[622,766,689],{"class":632},[622,768,703],{"class":636},[622,770,706],{"class":632},[622,772,773],{"class":649},"forms:*",[622,775,706],{"class":632},[622,777,778],{"class":632},",",[622,780,646],{"class":632},[622,782,783],{"class":649},"users:read",[622,785,706],{"class":632},[622,787,778],{"class":632},[622,789,646],{"class":632},[622,791,792],{"class":649},"users:list",[622,794,706],{"class":632},[622,796,714],{"class":636},[622,798,717],{"class":632},[622,800,802,805,807,809,811,814,816,818],{"class":624,"line":801},10,[622,803,804],{"class":685},"        inherit",[622,806,689],{"class":632},[622,808,703],{"class":636},[622,810,706],{"class":632},[622,812,813],{"class":649},"eventmanager",[622,815,706],{"class":632},[622,817,714],{"class":636},[622,819,717],{"class":632},[622,821,823],{"class":624,"line":822},11,[622,824,825],{"class":632},"      },\n",[622,827,829,832,834],{"class":624,"line":828},12,[622,830,831],{"class":685},"      member",[622,833,689],{"class":632},[622,835,692],{"class":632},[622,837,839,841,843,845,848,850],{"class":624,"line":838},13,[622,840,747],{"class":685},[622,842,689],{"class":632},[622,844,646],{"class":632},[622,846,847],{"class":649},"Member",[622,849,706],{"class":632},[622,851,717],{"class":632},[622,853,855,857,859,861,863,866,868,870],{"class":624,"line":854},14,[622,856,764],{"class":685},[622,858,689],{"class":632},[622,860,703],{"class":636},[622,862,706],{"class":632},[622,864,865],{"class":649},"member-area:view",[622,867,706],{"class":632},[622,869,714],{"class":636},[622,871,717],{"class":632},[622,873,875,878,880,882,885,887,889,892,894],{"class":624,"line":874},15,[622,876,877],{"class":685},"        requirements",[622,879,689],{"class":632},[622,881,633],{"class":632},[622,883,884],{"class":685}," subscription",[622,886,689],{"class":632},[622,888,646],{"class":632},[622,890,891],{"class":649},"*",[622,893,706],{"class":632},[622,895,896],{"class":632}," },\n",[622,898,900,903,905,909],{"class":624,"line":899},16,[622,901,902],{"class":685},"        auto",[622,904,689],{"class":632},[622,906,908],{"class":907},"sfNiH"," true",[622,910,717],{"class":632},[622,912,914,916,918,920,922,924,926,928],{"class":624,"line":913},17,[622,915,804],{"class":685},[622,917,689],{"class":632},[622,919,703],{"class":636},[622,921,706],{"class":632},[622,923,709],{"class":649},[622,925,706],{"class":632},[622,927,714],{"class":636},[622,929,717],{"class":632},[622,931,933],{"class":624,"line":932},18,[622,934,825],{"class":632},[622,936,938,941,944],{"class":624,"line":937},19,[622,939,940],{"class":632},"    }",[622,942,943],{"class":636},")",[622,945,717],{"class":632},[622,947,949],{"class":624,"line":948},20,[622,950,951],{"class":632},"  },\n",[622,953,955,958],{"class":624,"line":954},21,[622,956,957],{"class":632},"}",[622,959,960],{"class":636},")\n",[611,962,964],{"className":613,"code":963,"language":616,"meta":617,"style":617},"interface RoleDefinition {\n  label?: string\n  labelKey?: string \u002F\u002F an i18n key for the label\n  description?: string\n  descriptionKey?: string\n  grant?: PermissionGrant[] \u002F\u002F permission names or wildcards (`string` before the app's types are generated)\n  inherit?: RoleName[] \u002F\u002F roles whose permissions this role also holds\n  requirements?: Record\u003Cstring, unknown>\n  auto?: boolean\n  assignable?: boolean\n  replace?: boolean \u002F\u002F host only: see below\n}\n",[619,965,966,978,989,1003,1012,1021,1037,1052,1076,1086,1095,1108],{"__ignoreMap":617},[622,967,968,972,976],{"class":624,"line":625},[622,969,971],{"class":970},"spNyl","interface",[622,973,975],{"class":974},"sBMFI"," RoleDefinition",[622,977,692],{"class":632},[622,979,980,983,986],{"class":624,"line":656},[622,981,982],{"class":685},"  label",[622,984,985],{"class":632},"?:",[622,987,988],{"class":974}," string\n",[622,990,991,994,996,999],{"class":624,"line":663},[622,992,993],{"class":685},"  labelKey",[622,995,985],{"class":632},[622,997,998],{"class":974}," string",[622,1000,1002],{"class":1001},"sHwdD"," \u002F\u002F an i18n key for the label\n",[622,1004,1005,1008,1010],{"class":624,"line":682},[622,1006,1007],{"class":685},"  description",[622,1009,985],{"class":632},[622,1011,988],{"class":974},[622,1013,1014,1017,1019],{"class":624,"line":695},[622,1015,1016],{"class":685},"  descriptionKey",[622,1018,985],{"class":632},[622,1020,988],{"class":974},[622,1022,1023,1026,1028,1031,1034],{"class":624,"line":720},[622,1024,1025],{"class":685},"  grant",[622,1027,985],{"class":632},[622,1029,1030],{"class":974}," PermissionGrant",[622,1032,1033],{"class":636},"[] ",[622,1035,1036],{"class":1001},"\u002F\u002F permission names or wildcards (`string` before the app's types are generated)\n",[622,1038,1039,1042,1044,1047,1049],{"class":624,"line":734},[622,1040,1041],{"class":685},"  inherit",[622,1043,985],{"class":632},[622,1045,1046],{"class":974}," RoleName",[622,1048,1033],{"class":636},[622,1050,1051],{"class":1001},"\u002F\u002F roles whose permissions this role also holds\n",[622,1053,1054,1057,1059,1062,1065,1068,1070,1073],{"class":624,"line":744},[622,1055,1056],{"class":685},"  requirements",[622,1058,985],{"class":632},[622,1060,1061],{"class":974}," Record",[622,1063,1064],{"class":632},"\u003C",[622,1066,1067],{"class":974},"string",[622,1069,778],{"class":632},[622,1071,1072],{"class":974}," unknown",[622,1074,1075],{"class":632},">\n",[622,1077,1078,1081,1083],{"class":624,"line":761},[622,1079,1080],{"class":685},"  auto",[622,1082,985],{"class":632},[622,1084,1085],{"class":974}," boolean\n",[622,1087,1088,1091,1093],{"class":624,"line":801},[622,1089,1090],{"class":685},"  assignable",[622,1092,985],{"class":632},[622,1094,1085],{"class":974},[622,1096,1097,1100,1102,1105],{"class":624,"line":822},[622,1098,1099],{"class":685},"  replace",[622,1101,985],{"class":632},[622,1103,1104],{"class":974}," boolean",[622,1106,1107],{"class":1001}," \u002F\u002F host only: see below\n",[622,1109,1110],{"class":624,"line":828},[622,1111,1112],{"class":632},"}\n",[1114,1115,1116,1129],"table",{},[1117,1118,1119],"thead",{},[1120,1121,1122,1126],"tr",{},[1123,1124,1125],"th",{},"Key",[1123,1127,1128],{},"Meaning",[1130,1131,1132,1178,1199,1217,1234,1255],"tbody",{},[1120,1133,1134,1140],{},[1135,1136,1137],"td",{},[619,1138,1139],{},"grant",[1135,1141,1142,1143,1146,1147,1150,1151,1153,1154,1157,1158,1161,1162,1165,1166,1169,1170,1173,1174,1177],{},"Permissions the role holds. A name (",[619,1144,1145],{},"events:update","), a resource wildcard (",[619,1148,1149],{},"events:*",") or ",[619,1152,891],{},". ",[597,1155,1156],{},"A wildcard never covers a sensitive permission"," (",[619,1159,1160],{},":pii"," by default): grant those by name. The built-in ones (",[619,1163,1164],{},"events:pii",", ",[619,1167,1168],{},"forms:pii",") gate MCP tool output only; the admin HTTP API is gated by ",[619,1171,1172],{},"events:manage"," \u002F ",[619,1175,1176],{},"forms:manage",". Every grant has to match a registered permission.",[1120,1179,1180,1185],{},[1135,1181,1182],{},[619,1183,1184],{},"inherit",[1135,1186,1187,1188,1191,1192,1195,1196,1198],{},"Roles whose permissions this role also holds, transitively. There are no ranks: ",[619,1189,1190],{},"manager"," inheriting ",[619,1193,1194],{},"crew"," simply holds everything ",[619,1197,1194],{}," grants. A cycle fails the build.",[1120,1200,1201,1206],{},[1135,1202,1203],{},[619,1204,1205],{},"requirements",[1135,1207,1208,1209,1213,1214,1216],{},"Conditions that must all hold for the role to count. Each key is a registered ",[602,1210,1212],{"href":1211},"#requirements","requirement",". The role is dropped, and so are roles that only reach it through ",[619,1215,1184],{},", while one fails.",[1120,1218,1219,1224],{},[1135,1220,1221],{},[619,1222,1223],{},"auto",[1135,1225,1226,1227,1229,1230,1233],{},"Held by everyone who meets the ",[619,1228,1205],{},". Not assignable, never in ",[619,1231,1232],{},"defaultRoles",", and it needs at least one requirement.",[1120,1235,1236,1241],{},[1135,1237,1238],{},[619,1239,1240],{},"assignable",[1135,1242,1243,1244,1247,1248,1251,1252,1254],{},"Whether admins may assign it. Defaults to ",[619,1245,1246],{},"true","; always ",[619,1249,1250],{},"false"," for ",[619,1253,1223],{}," and default roles.",[1120,1256,1257,1262],{},[1135,1258,1259],{},[619,1260,1261],{},"replace",[1135,1263,1264],{},"Host only: discard the module's definition of this role instead of merging into it.",[1266,1267,1269],"h3",{"id":1268},"type-your-roles","Type your roles",[593,1271,1272,1273,1276,1277,1279,1280,1282,1283,1286],{},"Wrap the roles in ",[619,1274,1275],{},"defineRoles"," from ",[619,1278,650],{},", in ",[619,1281,615],{}," or in a ",[619,1284,1285],{},"roles.ts"," it imports:",[611,1288,1290],{"className":613,"code":1289,"filename":1285,"language":616,"meta":617,"style":617},"import { defineRoles } from '@frigear-nu\u002Fauth\u002Faccess'\n\nexport const roles = defineRoles({\n  coordinator: { label: 'Coordinator', grant: ['forms:*', 'users:read', 'users:list'], inherit: ['eventmanager'] },\n  user: { label: 'User' },\n})\n",[619,1291,1292,1310,1314,1333,1407,1429],{"__ignoreMap":617},[622,1293,1294,1296,1298,1300,1302,1304,1306,1308],{"class":624,"line":625},[622,1295,629],{"class":628},[622,1297,633],{"class":632},[622,1299,637],{"class":636},[622,1301,640],{"class":632},[622,1303,643],{"class":628},[622,1305,646],{"class":632},[622,1307,650],{"class":649},[622,1309,653],{"class":632},[622,1311,1312],{"class":624,"line":656},[622,1313,660],{"emptyLinePlaceholder":659},[622,1315,1316,1318,1321,1324,1327,1329,1331],{"class":624,"line":663},[622,1317,666],{"class":628},[622,1319,1320],{"class":970}," const",[622,1322,1323],{"class":636}," roles ",[622,1325,1326],{"class":632},"=",[622,1328,637],{"class":672},[622,1330,676],{"class":636},[622,1332,679],{"class":632},[622,1334,1335,1338,1340,1342,1345,1347,1349,1351,1353,1355,1358,1360,1362,1364,1366,1368,1370,1372,1374,1376,1378,1380,1382,1384,1386,1388,1391,1393,1395,1397,1399,1401,1404],{"class":624,"line":682},[622,1336,1337],{"class":685},"  coordinator",[622,1339,689],{"class":632},[622,1341,633],{"class":632},[622,1343,1344],{"class":685}," label",[622,1346,689],{"class":632},[622,1348,646],{"class":632},[622,1350,754],{"class":649},[622,1352,706],{"class":632},[622,1354,778],{"class":632},[622,1356,1357],{"class":685}," grant",[622,1359,689],{"class":632},[622,1361,703],{"class":636},[622,1363,706],{"class":632},[622,1365,773],{"class":649},[622,1367,706],{"class":632},[622,1369,778],{"class":632},[622,1371,646],{"class":632},[622,1373,783],{"class":649},[622,1375,706],{"class":632},[622,1377,778],{"class":632},[622,1379,646],{"class":632},[622,1381,792],{"class":649},[622,1383,706],{"class":632},[622,1385,714],{"class":636},[622,1387,778],{"class":632},[622,1389,1390],{"class":685}," inherit",[622,1392,689],{"class":632},[622,1394,703],{"class":636},[622,1396,706],{"class":632},[622,1398,813],{"class":649},[622,1400,706],{"class":632},[622,1402,1403],{"class":636},"] ",[622,1405,1406],{"class":632},"},\n",[622,1408,1409,1412,1414,1416,1418,1420,1422,1425,1427],{"class":624,"line":695},[622,1410,1411],{"class":685},"  user",[622,1413,689],{"class":632},[622,1415,633],{"class":632},[622,1417,1344],{"class":685},[622,1419,689],{"class":632},[622,1421,646],{"class":632},[622,1423,1424],{"class":649},"User",[622,1426,706],{"class":632},[622,1428,896],{"class":632},[622,1430,1431,1433],{"class":624,"line":720},[622,1432,957],{"class":632},[622,1434,960],{"class":636},[611,1436,1438],{"className":613,"code":1437,"filename":615,"language":616,"meta":617,"style":617},"import { roles } from '.\u002Froles'\n\nexport default defineNuxtConfig({\n  authorization: { defaultRoles: ['user'], roles },\n})\n",[619,1439,1440,1460,1464,1476,1505],{"__ignoreMap":617},[622,1441,1442,1444,1446,1449,1451,1453,1455,1458],{"class":624,"line":625},[622,1443,629],{"class":628},[622,1445,633],{"class":632},[622,1447,1448],{"class":636}," roles",[622,1450,640],{"class":632},[622,1452,643],{"class":628},[622,1454,646],{"class":632},[622,1456,1457],{"class":649},".\u002Froles",[622,1459,653],{"class":632},[622,1461,1462],{"class":624,"line":656},[622,1463,660],{"emptyLinePlaceholder":659},[622,1465,1466,1468,1470,1472,1474],{"class":624,"line":663},[622,1467,666],{"class":628},[622,1469,669],{"class":628},[622,1471,673],{"class":672},[622,1473,676],{"class":636},[622,1475,679],{"class":632},[622,1477,1478,1480,1482,1484,1487,1489,1491,1493,1495,1497,1499,1501,1503],{"class":624,"line":682},[622,1479,686],{"class":685},[622,1481,689],{"class":632},[622,1483,633],{"class":632},[622,1485,1486],{"class":685}," defaultRoles",[622,1488,689],{"class":632},[622,1490,703],{"class":636},[622,1492,706],{"class":632},[622,1494,709],{"class":649},[622,1496,706],{"class":632},[622,1498,714],{"class":636},[622,1500,778],{"class":632},[622,1502,1323],{"class":636},[622,1504,1406],{"class":632},[622,1506,1507,1509],{"class":624,"line":695},[622,1508,957],{"class":632},[622,1510,960],{"class":636},[593,1512,1513],{},"It returns the roles unchanged. Its value is in the types:",[1515,1516,1517,1543,1555],"ul",{},[1518,1519,1520,1522,1523,1165,1526,1528,1529,1157,1532,1535,1536,1539,1540,1542],"li",{},[619,1521,1139],{}," takes a ",[619,1524,1525],{},"Permission",[619,1527,891],{}," or ",[619,1530,1531],{},"resource:*",[619,1533,1534],{},"PermissionGrant","), so ",[619,1537,1538],{},"'users:lst'"," fails typecheck with a\n\"did you mean ",[619,1541,792],{},"\" hint.",[1518,1544,1545,1547,1548,1551,1552,1554],{},[619,1546,1184],{}," takes the roles of the same object, and once the types are generated every compiled role (",[619,1549,1550],{},"RoleName","),\nmodules' roles included (",[619,1553,813],{},").",[1518,1556,1557,1522,1559,604],{},[619,1558,1232],{},[619,1560,1550],{},[593,1562,1563,1564,1567,1568,1571,1572,1574,1575,1577,1578,1580,1581,1583,1584,1554],{},"The types come from ",[619,1565,1566],{},".nuxt\u002Ftypes\u002Fauth-access.d.ts",", which auth writes at ",[619,1569,1570],{},"nuxi prepare"," (and every build) from the\nregistered permissions and roles, and which ",[619,1573,615],{}," sees too. Before the first prepare, and in a package\nwithout a generated app, ",[619,1576,1525],{}," and ",[619,1579,1550],{}," are plain ",[619,1582,1067],{},": nothing fails, nothing is checked. The build\nchecks the same rules at runtime regardless (see ",[602,1585,1587],{"href":1586},"#build-errors","Build errors",[1266,1589,1591,1577,1593],{"id":1590},"defaultroles-and-implicit",[619,1592,1232],{},[619,1594,1595],{},"implicit",[593,1597,1598],{},"Two things give every signed-in user a permission, and they are not the same:",[1515,1600,1601,1612],{},[1518,1602,1603,1607,1608,1611],{},[597,1604,1605],{},[619,1606,1232],{}," is your baseline bundle (",[619,1609,1610],{},"['user']","). It is host config, shows up on the roles pages and can hold\nanything.",[1518,1613,1614,1618,1619,1528,1622,1625],{},[597,1615,1616],{},[619,1617,1595],{}," is a flag on a permission that a module registers for self-service every user needs, such as\n",[619,1620,1621],{},"tickets:read",[619,1623,1624],{},"profile:write",". It applies even when Authorization is not installed.",[606,1627,1629],{"id":1628},"how-roles-merge","How roles merge",[593,1631,1632,1633,689],{},"A role can come from several places. The build merges them at ",[619,1634,1635],{},"modules:done",[1637,1638,1639,1662,1678,1699],"ol",{},[1518,1640,1641,1643,1644,1647,1648,1650,1651,1654,1655,1657,1658,1661],{},[597,1642,156],{}," ship roles with ",[619,1645,1646],{},"addRole"," (Events offers ",[619,1649,813],{},") and put permissions into roles by name with\n",[619,1652,1653],{},"grantTo"," on the permission (Forms gives ",[619,1656,1168],{}," to ",[619,1659,1660],{},"admin","). Roles that inherit that role get the permission\ntoo. When the role does not exist, the grant is skipped with an info log.",[1518,1663,1664,1667,1668,1577,1670,1672,1673,1528,1675,1677],{},[597,1665,1666],{},"Two modules defining one role"," union their ",[619,1669,1139],{},[619,1671,1184],{},". Differing ",[619,1674,1205],{},[619,1676,1223],{}," fail the\nbuild.",[1518,1679,1680,1686,1687,1577,1689,1691,1692,1165,1694,1577,1696,1698],{},[597,1681,1682,1683],{},"Your app's ",[619,1684,1685],{},"authorization.roles[name]"," merges into a module's role of the same name by default: your label and\ndescription win, ",[619,1688,1139],{},[619,1690,1184],{}," are unions, and your ",[619,1693,1205],{},[619,1695,1223],{},[619,1697,1240],{}," win.",[1518,1700,1701,1706,1707,1709],{},[597,1702,1703],{},[619,1704,1705],{},"replace: true"," discards the module's definition, including the ",[619,1708,1653],{}," grants into that role, so you own it\ncompletely.",[611,1711,1713],{"className":613,"code":1712,"filename":615,"language":616,"meta":617,"style":617},"authorization: {\n  roles: {\n    \u002F\u002F Events ships `eventmanager` (grant: events:*). Add forms to it, keep the rest.\n    eventmanager: { grant: ['forms:read'] },\n    \u002F\u002F Take over a module role entirely.\n    crew: { replace: true, label: 'Crew', grant: ['events:read'] },\n  },\n}\n",[619,1714,1715,1724,1733,1738,1764,1769,1817,1821],{"__ignoreMap":617},[622,1716,1717,1720,1722],{"class":624,"line":625},[622,1718,1719],{"class":974},"authorization",[622,1721,689],{"class":632},[622,1723,692],{"class":632},[622,1725,1726,1729,1731],{"class":624,"line":656},[622,1727,1728],{"class":974},"  roles",[622,1730,689],{"class":632},[622,1732,692],{"class":632},[622,1734,1735],{"class":624,"line":663},[622,1736,1737],{"class":1001},"    \u002F\u002F Events ships `eventmanager` (grant: events:*). Add forms to it, keep the rest.\n",[622,1739,1740,1743,1745,1747,1749,1751,1753,1755,1758,1760,1762],{"class":624,"line":682},[622,1741,1742],{"class":974},"    eventmanager",[622,1744,689],{"class":632},[622,1746,633],{"class":632},[622,1748,1357],{"class":974},[622,1750,689],{"class":632},[622,1752,703],{"class":685},[622,1754,706],{"class":632},[622,1756,1757],{"class":649},"forms:read",[622,1759,706],{"class":632},[622,1761,1403],{"class":685},[622,1763,1406],{"class":632},[622,1765,1766],{"class":624,"line":695},[622,1767,1768],{"class":1001},"    \u002F\u002F Take over a module role entirely.\n",[622,1770,1771,1774,1776,1778,1781,1783,1785,1787,1789,1791,1793,1796,1798,1800,1802,1804,1806,1808,1811,1813,1815],{"class":624,"line":720},[622,1772,1773],{"class":974},"    crew",[622,1775,689],{"class":632},[622,1777,633],{"class":632},[622,1779,1780],{"class":974}," replace",[622,1782,689],{"class":632},[622,1784,908],{"class":907},[622,1786,778],{"class":632},[622,1788,1344],{"class":974},[622,1790,689],{"class":632},[622,1792,646],{"class":632},[622,1794,1795],{"class":649},"Crew",[622,1797,706],{"class":632},[622,1799,778],{"class":632},[622,1801,1357],{"class":974},[622,1803,689],{"class":632},[622,1805,703],{"class":685},[622,1807,706],{"class":632},[622,1809,1810],{"class":649},"events:read",[622,1812,706],{"class":632},[622,1814,1403],{"class":685},[622,1816,1406],{"class":632},[622,1818,1819],{"class":624,"line":734},[622,1820,951],{"class":632},[622,1822,1823],{"class":624,"line":744},[622,1824,1112],{"class":632},[1266,1826,1828],{"id":1827},"provenance","Provenance",[593,1830,1831,1832,1165,1835,1165,1838,1841,1842,1845,1846,1849],{},"The compiled role remembers where each grant came from: ",[619,1833,1834],{},"host",[619,1836,1837],{},"module:\u003Cname>",[619,1839,1840],{},"grantTo:\u003Cmodule>"," or\n",[619,1843,1844],{},"inherit:\u003Crole>",". The ",[602,1847,1848],{"href":218},"roles admin page"," shows it, so it is always clear why a\nrole holds a permission.",[1266,1851,1587],{"id":1852},"build-errors",[593,1854,1855],{},"The build stops when the role configuration would do nothing, or something surprising. Each message names the role or\npermission.",[1114,1857,1858,1868],{},[1117,1859,1860],{},[1120,1861,1862,1865],{},[1123,1863,1864],{},"Error",[1123,1866,1867],{},"Fix",[1130,1869,1870,1882,1892,1900,1908,1921,1931,1946,1962],{},[1120,1871,1872,1875],{},[1135,1873,1874],{},"A grant that names no registered permission, or a wildcard that matches none",[1135,1876,1877,1878,1881],{},"Register the permission with ",[619,1879,1880],{},"addPermission",", or fix the name.",[1120,1883,1884,1889],{},[1135,1885,1886,1888],{},[619,1887,1184],{}," names a role that is not defined",[1135,1890,1891],{},"Define the role or fix the name.",[1120,1893,1894,1897],{},[1135,1895,1896],{},"Roles inherit in a cycle",[1135,1898,1899],{},"Remove the loop.",[1120,1901,1902,1905],{},[1135,1903,1904],{},"An unknown requirement",[1135,1906,1907],{},"Install the module that registers it, or fix the name.",[1120,1909,1910,1918],{},[1135,1911,1912,1913,1915,1916],{},"An ",[619,1914,1223],{}," role without requirements, or in ",[619,1917,1232],{},[1135,1919,1920],{},"Add a requirement, or make it a plain default role.",[1120,1922,1923,1926],{},[1135,1924,1925],{},"A default role that is not defined",[1135,1927,1928,1929,604],{},"Define it, or remove it from ",[619,1930,1232],{},[1120,1932,1933,1941],{},[1135,1934,1935,1936,1528,1938,1940],{},"Two modules disagree on ",[619,1937,1205],{},[619,1939,1223],{}," for one role",[1135,1942,1943,1944,604],{},"Rename one role, or define it in your app with ",[619,1945,1705],{},[1120,1947,1948,1959],{},[1135,1949,1950,1951,1165,1954,1528,1957],{},"A permission registered twice with a different ",[619,1952,1953],{},"sensitive",[619,1955,1956],{},"sessionOnly",[619,1958,1595],{},[1135,1960,1961],{},"Make the registrations agree.",[1120,1963,1964,1970],{},[1135,1965,1966,1967],{},"An unknown permission in a route rule or ",[619,1968,1969],{},"definePageMeta({ authorize })",[1135,1971,1972],{},"Register it, or fix the name.",[606,1974,1975],{"id":1205},"Requirements",[593,1977,1978,1979,1981],{},"A requirement ties a role to a condition. The role only counts while every requirement holds. The most common pairing is\nan ",[619,1980,1223],{}," role, so everyone who meets the condition holds it:",[611,1983,1985],{"className":613,"code":1984,"filename":615,"language":616,"meta":617,"style":617},"authorization: {\n  roles: {\n    member: {\n      grant: ['member-area:view'],\n      requirements: { subscription: '*' }, \u002F\u002F any plan; or 'gold'; or ['gold', 'silver']\n      auto: true,\n    },\n  },\n}\n",[619,1986,1987,1995,2003,2012,2031,2056,2067,2072,2076],{"__ignoreMap":617},[622,1988,1989,1991,1993],{"class":624,"line":625},[622,1990,1719],{"class":974},[622,1992,689],{"class":632},[622,1994,692],{"class":632},[622,1996,1997,1999,2001],{"class":624,"line":656},[622,1998,1728],{"class":974},[622,2000,689],{"class":632},[622,2002,692],{"class":632},[622,2004,2005,2008,2010],{"class":624,"line":663},[622,2006,2007],{"class":974},"    member",[622,2009,689],{"class":632},[622,2011,692],{"class":632},[622,2013,2014,2017,2019,2021,2023,2025,2027,2029],{"class":624,"line":682},[622,2015,2016],{"class":974},"      grant",[622,2018,689],{"class":632},[622,2020,703],{"class":685},[622,2022,706],{"class":632},[622,2024,865],{"class":649},[622,2026,706],{"class":632},[622,2028,714],{"class":685},[622,2030,717],{"class":632},[622,2032,2033,2036,2038,2040,2042,2044,2046,2048,2050,2053],{"class":624,"line":695},[622,2034,2035],{"class":974},"      requirements",[622,2037,689],{"class":632},[622,2039,633],{"class":632},[622,2041,884],{"class":974},[622,2043,689],{"class":632},[622,2045,646],{"class":632},[622,2047,891],{"class":649},[622,2049,706],{"class":632},[622,2051,2052],{"class":632}," },",[622,2054,2055],{"class":1001}," \u002F\u002F any plan; or 'gold'; or ['gold', 'silver']\n",[622,2057,2058,2061,2063,2065],{"class":624,"line":720},[622,2059,2060],{"class":974},"      auto",[622,2062,689],{"class":632},[622,2064,908],{"class":907},[622,2066,717],{"class":632},[622,2068,2069],{"class":624,"line":734},[622,2070,2071],{"class":632},"    },\n",[622,2073,2074],{"class":624,"line":744},[622,2075,951],{"class":632},[622,2077,2078],{"class":624,"line":761},[622,2079,1112],{"class":632},[593,2081,2082,2083,2086,2087,2090],{},"A module registers a requirement with ",[619,2084,2085],{},"addRoleRequirement"," in ",[619,2088,2089],{},"setup()",". The file's default export decides it per user:",[611,2092,2095],{"className":613,"code":2093,"filename":2094,"language":616,"meta":617,"style":617},"addRoleRequirement(nuxt, { name: 'subscription', path: resolver.resolve('.\u002Fruntime\u002Fserver\u002Frequirements\u002Fsubscription') })\n","src\u002Fmodule.ts",[619,2096,2097],{"__ignoreMap":617},[622,2098,2099,2101,2104,2106,2108,2111,2113,2115,2118,2120,2122,2125,2127,2130,2132,2135,2137,2139,2142,2144,2147,2149],{"class":624,"line":625},[622,2100,2085],{"class":672},[622,2102,2103],{"class":636},"(nuxt",[622,2105,778],{"class":632},[622,2107,633],{"class":632},[622,2109,2110],{"class":685}," name",[622,2112,689],{"class":632},[622,2114,646],{"class":632},[622,2116,2117],{"class":649},"subscription",[622,2119,706],{"class":632},[622,2121,778],{"class":632},[622,2123,2124],{"class":685}," path",[622,2126,689],{"class":632},[622,2128,2129],{"class":636}," resolver",[622,2131,604],{"class":632},[622,2133,2134],{"class":672},"resolve",[622,2136,676],{"class":636},[622,2138,706],{"class":632},[622,2140,2141],{"class":649},".\u002Fruntime\u002Fserver\u002Frequirements\u002Fsubscription",[622,2143,706],{"class":632},[622,2145,2146],{"class":636},") ",[622,2148,957],{"class":632},[622,2150,960],{"class":636},[611,2152,2155],{"className":613,"code":2153,"filename":2154,"language":616,"meta":617,"style":617},"export default async function ({ user, value }: AuthRoleRequirementContext): Promise\u003Cboolean> {\n  return hasActiveSubscription(Number(user.id), { plans: value === '*' ? [] : [].concat(value) })\n}\n","src\u002Fruntime\u002Fserver\u002Frequirements\u002Fsubscription.ts",[619,2156,2157,2203,2274],{"__ignoreMap":617},[622,2158,2159,2161,2163,2166,2169,2172,2176,2178,2181,2184,2187,2190,2193,2195,2198,2201],{"class":624,"line":625},[622,2160,666],{"class":628},[622,2162,669],{"class":628},[622,2164,2165],{"class":970}," async",[622,2167,2168],{"class":970}," function",[622,2170,2171],{"class":632}," ({",[622,2173,2175],{"class":2174},"sHdIc"," user",[622,2177,778],{"class":632},[622,2179,2180],{"class":2174}," value",[622,2182,2183],{"class":632}," }:",[622,2185,2186],{"class":974}," AuthRoleRequirementContext",[622,2188,2189],{"class":632},"):",[622,2191,2192],{"class":974}," Promise",[622,2194,1064],{"class":632},[622,2196,2197],{"class":974},"boolean",[622,2199,2200],{"class":632},">",[622,2202,692],{"class":632},[622,2204,2205,2208,2211,2213,2216,2218,2220,2222,2225,2227,2229,2231,2234,2236,2238,2241,2243,2245,2247,2250,2253,2255,2258,2260,2263,2265,2268,2270,2272],{"class":624,"line":656},[622,2206,2207],{"class":628},"  return",[622,2209,2210],{"class":672}," hasActiveSubscription",[622,2212,676],{"class":685},[622,2214,2215],{"class":672},"Number",[622,2217,676],{"class":685},[622,2219,709],{"class":636},[622,2221,604],{"class":632},[622,2223,2224],{"class":636},"id",[622,2226,943],{"class":685},[622,2228,778],{"class":632},[622,2230,633],{"class":632},[622,2232,2233],{"class":685}," plans",[622,2235,689],{"class":632},[622,2237,2180],{"class":636},[622,2239,2240],{"class":632}," ===",[622,2242,646],{"class":632},[622,2244,891],{"class":649},[622,2246,706],{"class":632},[622,2248,2249],{"class":632}," ?",[622,2251,2252],{"class":685}," [] ",[622,2254,689],{"class":632},[622,2256,2257],{"class":685}," []",[622,2259,604],{"class":632},[622,2261,2262],{"class":672},"concat",[622,2264,676],{"class":685},[622,2266,2267],{"class":636},"value",[622,2269,2146],{"class":685},[622,2271,957],{"class":632},[622,2273,960],{"class":685},[622,2275,2276],{"class":624,"line":663},[622,2277,1112],{"class":632},[1515,2279,2280,2290,2297,2300],{},[1518,2281,2282,2283,2286,2287,2289],{},"The context is ",[619,2284,2285],{},"{ event, user, value }",", where ",[619,2288,2267],{}," is what the role wrote after the name.",[1518,2291,2292,2293,2296],{},"A requirement that ",[597,2294,2295],{},"throws"," counts as not met, and an unknown requirement name is not met either: it fails closed.",[1518,2298,2299],{},"Results are cached per request and user.",[1518,2301,2302,2304,2305,2307],{},[602,2303,258],{"href":259}," registers ",[619,2306,2117],{},". It is the only built-in requirement.",[606,2309,2311],{"id":2310},"where-a-users-roles-come-from","Where a user's roles come from",[593,2313,2314],{},"A user's effective roles are, in order:",[1637,2316,2317,2329,2334,2340,2347],{},[1518,2318,2319,2320,2323,2324,2328],{},"the roles ",[597,2321,2322],{},"assigned"," to them (stored, see ",[602,2325,2327],{"href":2326},"#assignment-and-its-rules","Assignment","),",[1518,2330,2331,2332,778],{},"plus the ",[619,2333,1232],{},[1518,2335,2336,2337,2339],{},"plus every ",[619,2338,1223],{}," role,",[1518,2341,2342,2343,2346],{},"then the ",[619,2344,2345],{},"authorization:roles"," hook, which may add or remove roles,",[1518,2348,2349,2350,604],{},"then the roles whose requirements fail are dropped, and the rest is closed over ",[619,2351,1184],{},[593,2353,2354,2355,2357,2358,2360,2361,2363],{},"Role permissions are ",[619,2356,1139],{},"s of all of these, plus the ",[619,2359,1595],{}," permissions. An assigned role that is not configured\nany more is kept in the database, ignored at runtime and listed in a startup warning. A role provider or a hook that\nthrows leaves the user with no roles at all (only ",[619,2362,1595],{}," permissions), never with extra ones.",[593,2365,2366],{},"The hook is how an environment allowlist becomes a role:",[611,2368,2371],{"className":613,"code":2369,"filename":2370,"language":616,"meta":617,"style":617},"export default defineNitroPlugin((nitro) => {\n  nitro.hooks.hook('authorization:roles', (ctx) => {\n    if (ctx.user.emailVerifiedAt && admins.includes(ctx.user.email)) ctx.roles.push('admin')\n  })\n})\n","server\u002Fplugins\u002Fauthorization-roles.ts",[619,2372,2373,2396,2432,2499,2506],{"__ignoreMap":617},[622,2374,2375,2377,2379,2382,2384,2386,2389,2391,2394],{"class":624,"line":625},[622,2376,666],{"class":628},[622,2378,669],{"class":628},[622,2380,2381],{"class":672}," defineNitroPlugin",[622,2383,676],{"class":636},[622,2385,676],{"class":632},[622,2387,2388],{"class":2174},"nitro",[622,2390,943],{"class":632},[622,2392,2393],{"class":970}," =>",[622,2395,692],{"class":632},[622,2397,2398,2401,2403,2406,2408,2411,2413,2415,2417,2419,2421,2423,2426,2428,2430],{"class":624,"line":656},[622,2399,2400],{"class":636},"  nitro",[622,2402,604],{"class":632},[622,2404,2405],{"class":636},"hooks",[622,2407,604],{"class":632},[622,2409,2410],{"class":672},"hook",[622,2412,676],{"class":685},[622,2414,706],{"class":632},[622,2416,2345],{"class":649},[622,2418,706],{"class":632},[622,2420,778],{"class":632},[622,2422,1157],{"class":632},[622,2424,2425],{"class":2174},"ctx",[622,2427,943],{"class":632},[622,2429,2393],{"class":970},[622,2431,692],{"class":632},[622,2433,2434,2437,2439,2441,2443,2445,2447,2450,2453,2456,2458,2461,2463,2465,2467,2469,2471,2474,2477,2479,2481,2484,2486,2489,2491,2493,2495,2497],{"class":624,"line":663},[622,2435,2436],{"class":628},"    if",[622,2438,1157],{"class":685},[622,2440,2425],{"class":636},[622,2442,604],{"class":632},[622,2444,709],{"class":636},[622,2446,604],{"class":632},[622,2448,2449],{"class":636},"emailVerifiedAt",[622,2451,2452],{"class":632}," &&",[622,2454,2455],{"class":636}," admins",[622,2457,604],{"class":632},[622,2459,2460],{"class":672},"includes",[622,2462,676],{"class":685},[622,2464,2425],{"class":636},[622,2466,604],{"class":632},[622,2468,709],{"class":636},[622,2470,604],{"class":632},[622,2472,2473],{"class":636},"email",[622,2475,2476],{"class":685},")) ",[622,2478,2425],{"class":636},[622,2480,604],{"class":632},[622,2482,2483],{"class":636},"roles",[622,2485,604],{"class":632},[622,2487,2488],{"class":672},"push",[622,2490,676],{"class":685},[622,2492,706],{"class":632},[622,2494,1660],{"class":649},[622,2496,706],{"class":632},[622,2498,960],{"class":685},[622,2500,2501,2504],{"class":624,"line":682},[622,2502,2503],{"class":632},"  }",[622,2505,960],{"class":685},[622,2507,2508,2510],{"class":624,"line":695},[622,2509,957],{"class":632},[622,2511,960],{"class":636},[593,2513,2514,2515,604],{},"Roles from the hook are not stored and cannot be changed in the admin. They still count for\n",[602,2516,2518],{"href":2517},"#target-protection","target protection",[606,2520,2522],{"id":2521},"assignment-and-its-rules","Assignment and its rules",[593,2524,2525,2526,2530,2531,2534,2535,2538,2539,1577,2542,2545,2546,2549],{},"Roles are assigned in ",[602,2527,2529],{"href":2528},"\u002Fmodules\u002Fidentity\u002Fauthorization\u002Fadmin#the-user-roles-tab","the users admin"," or through\n",[619,2532,2533],{},"PUT \u002Fapi\u002Fadmin\u002Fauthorization\u002Fusers\u002F:id\u002Froles"," with ",[619,2536,2537],{},"{ roles: string[] }",". The call replaces the roles staff assigned\n(",[619,2540,2541],{},"manual",[619,2543,2544],{},"migrated"," rows). It needs ",[619,2547,2548],{},"roles:assign",", which is session only, and three hard-coded rules a host\ncannot override:",[1515,2551,2552,2572,2598],{},[1518,2553,2554,2557,2558,2561,2562,2564,2565,2568,2569,604],{},[597,2555,2556],{},"No escalation."," To add or remove a role the actor must hold ",[597,2559,2560],{},"every"," permission that role expands to, sensitive\nones by name. An admin without ",[619,2563,1168],{}," cannot hand out a role that holds it. Missing permissions are\n",[619,2566,2567],{},"403 forbidden"," with the list in ",[619,2570,2571],{},"data.missing",[1518,2573,2574,2577,2578,2580,2581,2583,2584,2587,2588,2591,2592,2534,2594,2597],{},[597,2575,2576],{},"Strictly below."," The role must also sit below the actor: the actor holds at least one permission the role does\nnot (the ",[619,2579,1595],{}," permissions everyone holds do not count). So a manager can assign and remove lower roles, but not\n",[619,2582,1190],{}," itself, and peers cannot promote or demote each other; that answers ",[619,2585,2586],{},"403 role_not_below"," with the role in\n",[619,2589,2590],{},"data.role",". The one exception is an actor who holds every registered permission, sensitive ones included: such an\nadmin may assign and remove their own role (",[619,2593,1660],{},[619,2595,2596],{},"grant: ['*']"," alone does not qualify when sensitive\npermissions exist; grant those by name).",[1518,2599,2600,2603,2604,2606,2607,2610,2611,2614,2615,604],{},[597,2601,2602],{},"Not assignable."," ",[619,2605,1223],{}," roles, default roles and roles with ",[619,2608,2609],{},"assignable: false"," answer ",[619,2612,2613],{},"409 role_not_assignable",".\nAn unknown role is ",[619,2616,2617],{},"400 unknown_role",[593,2619,2620,2621,2623,2624,2626],{},"The actor's own roles are resolved strictly for this check: when the role provider, an ",[619,2622,2345],{}," listener or\na requirement fails, nothing is assigned (",[619,2625,2567],{},") and the user tab offers no roles.",[593,2628,2629,2630,2633,2634,689],{},"Each row in ",[619,2631,2632],{},"authorization_user_roles"," records its ",[619,2635,2636],{},"source",[1114,2638,2639,2652],{},[1117,2640,2641],{},[1120,2642,2643,2646,2649],{},[1123,2644,2645],{},"Source",[1123,2647,2648],{},"Written by",[1123,2650,2651],{},"Replaced by",[1130,2653,2654,2666,2689],{},[1120,2655,2656,2660,2663],{},[1135,2657,2658],{},[619,2659,2541],{},[1135,2661,2662],{},"An admin, through the API or the user tab",[1135,2664,2665],{},"The next assignment",[1120,2667,2668,2673,2683],{},[1135,2669,2670],{},[619,2671,2672],{},"sso",[1135,2674,2675,2676,2679,2680],{},"Single sign-on (",[602,2677,2678],{"href":188},"frigear.nu sign-in","), through the role provider's ",[619,2681,2682],{},"setRoles",[1135,2684,2685,2686,2688],{},"The next sign-in. It replaces only ",[619,2687,2672],{}," rows, never manual ones.",[1120,2690,2691,2695,2701],{},[1135,2692,2693],{},[619,2694,2544],{},[1135,2696,2697,2698],{},"The one-off migration of ",[619,2699,2700],{},"users.role",[1135,2702,2665],{},[1266,2704,2706],{"id":2705},"target-protection","Target protection",[593,2708,2709,2710,2713,2714,2716],{},"Assigning roles is not the only way to edit another user. ",[602,2711,191],{"href":2712},"\u002Fmodules\u002Fidentity\u002Fusers#target-protection"," refuses any\nwrite on a user whose permissions the actor does not fully hold, roles from ",[619,2715,2345],{}," included. So a\ncoordinator cannot edit an administrator.",[606,2718,2720,2721,2723],{"id":2719},"the-usersrole-migration","The ",[619,2722,2700],{}," migration",[593,2725,2726,2727,2729],{},"Earlier releases stored one role in ",[619,2728,2700],{},". This release keeps the column but never reads it as a role.",[1637,2731,2732,2750,2760],{},[1518,2733,2734,2735,2737,2738,2741,2742,2744,2745,2534,2747,604],{},"On the first request, an idempotent task copies ",[619,2736,2700],{}," (where it is not ",[619,2739,2740],{},"'user'",", a default or an ",[619,2743,1223],{},"\nrole) into ",[619,2746,2632],{},[619,2748,2749],{},"source = 'migrated'",[1518,2751,2752,2753,1157,2756,2759],{},"It records completion in ",[619,2754,2755],{},"authorization_meta",[619,2757,2758],{},"users-role-migrated","), so it never runs again. Removing a migrated\nrole therefore cannot bring it back.",[1518,2761,2762,2763,2765],{},"Single sign-on stops writing ",[619,2764,2700],{},". A later release drops the column.",[593,2767,2768,2769,2772,2773,2776,2777,2780,2781,604],{},"To check it, list the users of a role on ",[619,2770,2771],{},"\u002Fadmin\u002Froles\u002F:name",", or call ",[619,2774,2775],{},"GET \u002Fapi\u002Fadmin\u002Fauthorization\u002Froles\u002F:name\u002Fusers",",\nand compare with what you expect. Roles found in the data but absent from config are kept, ignored and listed in a\nstartup warning: add them to ",[619,2778,2779],{},"authorization.roles",", or remove the rows. The mapping of every removed option is in\n",[602,2782,2783],{"href":152},"Migrate access control",[606,2785,2787],{"id":2786},"next-steps","Next steps",[1515,2789,2790,2795,2800],{},[1518,2791,2792,2794],{},[602,2793,209],{"href":210}," – refine a permission for one record.",[1518,2796,2797,2799],{},[602,2798,217],{"href":218}," – the pages that show roles and provenance.",[1518,2801,2802,2804],{},[602,2803,67],{"href":68}," – the order in which a check is decided.",[2806,2807,2808],"style",{},"html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .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}",{"title":617,"searchDepth":656,"depth":656,"links":2810},[2811,2816,2820,2821,2822,2825,2827],{"id":608,"depth":656,"text":609,"children":2812},[2813,2814],{"id":1268,"depth":663,"text":1269},{"id":1590,"depth":663,"text":2815},"defaultRoles and implicit",{"id":1628,"depth":656,"text":1629,"children":2817},[2818,2819],{"id":1827,"depth":663,"text":1828},{"id":1852,"depth":663,"text":1587},{"id":1205,"depth":656,"text":1975},{"id":2310,"depth":656,"text":2311},{"id":2521,"depth":656,"text":2522,"children":2823},[2824],{"id":2705,"depth":663,"text":2706},{"id":2719,"depth":656,"text":2826},"The users.role migration",{"id":2786,"depth":656,"text":2787},"How roles are built from host config and module defaults, how users get them, and how to keep a role tied to a condition such as a subscription.","md",null,{},{"title":205},{"title":205,"description":2828},"iIw-YrBM0ujhpEvA0Y-joe579NrAQvtG8FNpP6v63cg",[2836,2838],{"title":173,"path":200,"stem":201,"description":2837,"children":-1},"Roles, permissions and policies that decide what a signed-in user may do on pages, server routes and in the interface.",{"title":209,"path":210,"stem":211,"description":2839,"children":-1},"Refine one permission against a record, such as \"only the author may edit\", on the server and in the interface.",1794503154862]