[{"data":1,"prerenderedAt":2218},["ShallowReactive",2],{"navigation_docs":3,"-modules-identity-oauth-server":587,"-modules-identity-oauth-server-surround":2213},[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":225,"body":589,"description":2206,"extension":2207,"links":2208,"meta":2209,"navigation":2210,"path":226,"seo":2211,"stem":227,"__hash__":2212},"docs\u002F3.modules\u002F1.identity\u002F6.oauth-server\u002Findex.md",{"type":590,"value":591,"toc":2189},"minimark",[592,604,629,634,756,760,808,812,1203,1224,1230,1234,1241,1713,1720,1727,1734,1747,1762,1805,1816,1830,1845,1855,1865,1869,1872,2030,2037,2047,2057,2060,2070,2091,2095,2149,2153,2185],[593,594,595,596,600,601,603],"p",{},"You have one app where people already have an account, and other apps that should use that same account: a mobile\napp, a partner site or a separate service. OAuth Server makes your app the ",[597,598,599],"a",{"href":87},"issuer"," for them.\nThe other apps send people here to sign in and get tokens back, and your app decides who may sign in where. If you only\nneed people to sign in to this app itself, use ",[597,602,168],{"href":169}," instead.",[593,605,606,607,611,612,618,619,622,623,625,626,628],{},"The module is ",[608,609,610],"code",{},"@frigear-nu\u002Foauth-server",", a ",[597,613,617],{"href":614,"rel":615},"https:\u002F\u002Fnuxt.com\u002Fdocs\u002F4.x\u002Fguide\u002Fmodules",[616],"nofollow","Nuxt module"," that speaks OAuth 2.0\nand OpenID Connect (OIDC). It has no role model of its own. It follows the ",[597,620,621],{"href":68},"permissions and roles","\nof ",[597,624,168],{"href":169}," and ",[597,627,199],{"href":200},": who may manage applications,\nwhich roles may sign in where and which scopes a user may hand to an application are all decided there.",[630,631,633],"h2",{"id":632},"what-you-get","What you get",[635,636,637,660,694,741,750],"ul",{},[638,639,640,644],"li",{},[641,642,643],"strong",{},"Pages.",[635,645,646,653],{},[638,647,648,649,652],{},"The consent screen at ",[608,650,651],{},"\u002Fauthorize",", where a person allows an app to sign them in. On by default.",[638,654,655,656,659],{},"The signed-in user's applications at ",[608,657,658],{},"\u002Faccount\u002Fapplications",". Opt-in.",[638,661,662,665],{},[641,663,664],{},"Admin area.",[635,666,667,688],{},[638,668,669,670,673,674,677,678,673,681,684,685,687],{},"An ",[641,671,672],{},"OAuth applications"," screen at ",[608,675,676],{},"\u002Fadmin\u002Foauth"," to create, edit and disable applications, and an ",[641,679,680],{},"OAuth\nscopes",[608,682,683],{},"\u002Fadmin\u002Foauth\u002Fscopes"," to define scopes. Opt-in, and only with ",[597,686,217],{"href":351},".",[638,689,690,691,693],{},"Menu items in the account menu and the admin sidebar, with ",[597,692,354],{"href":355},". On when Menu is\ninstalled.",[638,695,696,699],{},[641,697,698],{},"Server routes.",[635,700,701,704,711,725,732],{},[638,702,703],{},"The standard OAuth and OIDC endpoints: discovery, signing keys, authorize, token, revoke and userinfo. On by\ndefault.",[638,705,706,707,710],{},"Your own API accepts the ",[597,708,709],{"href":87},"access tokens"," these endpoints issue. On by default.",[638,712,713,714,717,720,721,724],{},"A staff API to manage applications and scopes. On by default. It needs the session-only ",[608,715,716],{},"oauth:manage",[597,718,719],{"href":200},"permission",", which the ",[608,722,723],{},"admin"," role gets by default.",[638,726,727,728,731],{},"Token introspection at ",[608,729,730],{},"POST \u002Foauth\u002Fintrospect"," (RFC 7662), for services that must ask the issuer what a token may\ndo now. On by default.",[638,733,734,735,738,739,659],{},"A ",[608,736,737],{},"my-oauth-applications"," tool for ",[597,740,317],{"href":318},[638,742,743,746,747,687],{},[641,744,745],{},"Composables and helpers."," Composables for the admin screen and the user's applications, and server helpers to\ncreate applications from code. See ",[597,748,749],{"href":231},"Helpers",[638,751,752,755],{},[641,753,754],{},"Emails."," None.",[757,758],"module-runtime",{":client":759,":server":759},"true",[761,762,763,766,767,769,770,769,772,774,775,777,778,766,781,784,785,788,789,766,792,794,795,797,798,800,801,803,804,807],"note",{},[641,764,765],{},"Installed for you:"," ",[597,768,168],{"href":169},", ",[597,771,191],{"href":192},[597,773,317],{"href":318},",\n",[597,776,326],{"href":327}," and Module Kit.\n",[641,779,780],{},"You add:",[608,782,783],{},"@nuxthub\u002Fcore",", and ",[608,786,787],{},"@nuxt\u002Fui"," for the consent, admin and applications pages.\n",[641,790,791],{},"Optional:",[597,793,217],{"href":351}," for the admin screens (it brings ",[597,796,354],{"href":355}," for the\nmenu items), and ",[597,799,199],{"href":200}," for roles. Without roles nobody holds ",[608,802,716],{},"\nand every ",[608,805,806],{},"allowedRoles"," list locks everybody out. Quick setup uses both.",[630,809,811],{"id":810},"quick-setup","Quick setup",[813,814,815,820,854,861,870,1115,1119,1129,1133,1137,1141,1167,1171,1190],"steps",{},[816,817,819],"h3",{"id":818},"install-the-module","Install the module",[821,822,827],"pre",{"className":823,"code":824,"language":825,"meta":826,"style":826},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm add @frigear-nu\u002Foauth-server @frigear-nu\u002Fadmin @frigear-nu\u002Fauthorization @nuxthub\u002Fcore\n","bash","",[608,828,829],{"__ignoreMap":826},[830,831,834,838,842,845,848,851],"span",{"class":832,"line":833},"line",1,[830,835,837],{"class":836},"sBMFI","pnpm",[830,839,841],{"class":840},"sfazB"," add",[830,843,844],{"class":840}," @frigear-nu\u002Foauth-server",[830,846,847],{"class":840}," @frigear-nu\u002Fadmin",[830,849,850],{"class":840}," @frigear-nu\u002Fauthorization",[830,852,853],{"class":840}," @nuxthub\u002Fcore\n",[816,855,857,858],{"id":856},"configure-it-in-nuxtconfigts","Configure it in ",[608,859,860],{},"nuxt.config.ts",[593,862,863,864,866,867,869],{},"This setup adds Admin for the admin screens and Authorization for roles. The ",[608,865,723],{}," role holds everything, including\n",[608,868,716],{},", which lets its users manage applications and scopes.",[821,871,875],{"className":872,"code":873,"filename":860,"language":874,"meta":826,"style":826},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","export default defineNuxtConfig({\n  modules: ['@nuxthub\u002Fcore', '@frigear-nu\u002Fadmin', '@frigear-nu\u002Fauthorization', '@frigear-nu\u002Foauth-server'],\n  authorization: {\n    roles: {\n      admin: { label: 'Admin', grant: ['*'] },\n    },\n  },\n  oauthServer: {\n    issuer: 'https:\u002F\u002Fid.example.com',\n    settings: {\n      pages: { admin: true, applications: true },\n    },\n  },\n})\n","ts",[608,876,877,898,951,962,972,1016,1022,1028,1038,1055,1065,1096,1101,1106],{"__ignoreMap":826},[830,878,879,883,886,890,894],{"class":832,"line":833},[830,880,882],{"class":881},"s7zQu","export",[830,884,885],{"class":881}," default",[830,887,889],{"class":888},"s2Zo4"," defineNuxtConfig",[830,891,893],{"class":892},"sTEyZ","(",[830,895,897],{"class":896},"sMK4o","{\n",[830,899,901,905,908,911,914,916,918,921,924,927,929,931,933,936,938,940,942,944,946,949],{"class":832,"line":900},2,[830,902,904],{"class":903},"swJcz","  modules",[830,906,907],{"class":896},":",[830,909,910],{"class":892}," [",[830,912,913],{"class":896},"'",[830,915,783],{"class":840},[830,917,913],{"class":896},[830,919,920],{"class":896},",",[830,922,923],{"class":896}," '",[830,925,926],{"class":840},"@frigear-nu\u002Fadmin",[830,928,913],{"class":896},[830,930,920],{"class":896},[830,932,923],{"class":896},[830,934,935],{"class":840},"@frigear-nu\u002Fauthorization",[830,937,913],{"class":896},[830,939,920],{"class":896},[830,941,923],{"class":896},[830,943,610],{"class":840},[830,945,913],{"class":896},[830,947,948],{"class":892},"]",[830,950,774],{"class":896},[830,952,954,957,959],{"class":832,"line":953},3,[830,955,956],{"class":903},"  authorization",[830,958,907],{"class":896},[830,960,961],{"class":896}," {\n",[830,963,965,968,970],{"class":832,"line":964},4,[830,966,967],{"class":903},"    roles",[830,969,907],{"class":896},[830,971,961],{"class":896},[830,973,975,978,980,983,986,988,990,992,994,996,999,1001,1003,1005,1008,1010,1013],{"class":832,"line":974},5,[830,976,977],{"class":903},"      admin",[830,979,907],{"class":896},[830,981,982],{"class":896}," {",[830,984,985],{"class":903}," label",[830,987,907],{"class":896},[830,989,923],{"class":896},[830,991,217],{"class":840},[830,993,913],{"class":896},[830,995,920],{"class":896},[830,997,998],{"class":903}," grant",[830,1000,907],{"class":896},[830,1002,910],{"class":892},[830,1004,913],{"class":896},[830,1006,1007],{"class":840},"*",[830,1009,913],{"class":896},[830,1011,1012],{"class":892},"] ",[830,1014,1015],{"class":896},"},\n",[830,1017,1019],{"class":832,"line":1018},6,[830,1020,1021],{"class":896},"    },\n",[830,1023,1025],{"class":832,"line":1024},7,[830,1026,1027],{"class":896},"  },\n",[830,1029,1031,1034,1036],{"class":832,"line":1030},8,[830,1032,1033],{"class":903},"  oauthServer",[830,1035,907],{"class":896},[830,1037,961],{"class":896},[830,1039,1041,1044,1046,1048,1051,1053],{"class":832,"line":1040},9,[830,1042,1043],{"class":903},"    issuer",[830,1045,907],{"class":896},[830,1047,923],{"class":896},[830,1049,1050],{"class":840},"https:\u002F\u002Fid.example.com",[830,1052,913],{"class":896},[830,1054,774],{"class":896},[830,1056,1058,1061,1063],{"class":832,"line":1057},10,[830,1059,1060],{"class":903},"    settings",[830,1062,907],{"class":896},[830,1064,961],{"class":896},[830,1066,1068,1071,1073,1075,1078,1080,1084,1086,1089,1091,1093],{"class":832,"line":1067},11,[830,1069,1070],{"class":903},"      pages",[830,1072,907],{"class":896},[830,1074,982],{"class":896},[830,1076,1077],{"class":903}," admin",[830,1079,907],{"class":896},[830,1081,1083],{"class":1082},"sfNiH"," true",[830,1085,920],{"class":896},[830,1087,1088],{"class":903}," applications",[830,1090,907],{"class":896},[830,1092,1083],{"class":1082},[830,1094,1095],{"class":896}," },\n",[830,1097,1099],{"class":832,"line":1098},12,[830,1100,1021],{"class":896},[830,1102,1104],{"class":832,"line":1103},13,[830,1105,1027],{"class":896},[830,1107,1109,1112],{"class":832,"line":1108},14,[830,1110,1111],{"class":896},"}",[830,1113,1114],{"class":892},")\n",[816,1116,1118],{"id":1117},"set-a-signing-key","Set a signing key",[593,1120,1121,1122,1125,1126,1128],{},"Generate a key and set it as ",[608,1123,1124],{},"NUXT_OAUTH_SERVER_PRIVATE_KEY",", as ",[597,1127,141],{"href":142},"\nshows.",[1130,1131,1132],"caution",{},"Use a different signing key in each environment, and store it as a secret. Anyone who has the key can sign tokens that\nyour apps and services accept.",[1134,1135,1136],"warning",{},"Without a migration the module's tables do not exist, and every OAuth request fails.",[816,1138,1140],{"id":1139},"generate-a-migration","Generate a migration",[593,1142,1143,1144,769,1147,769,1150,1153,1154,1157,1158,1161,1162,1166],{},"The module adds four tables: ",[608,1145,1146],{},"oauth_applications",[608,1148,1149],{},"oauth_scopes",[608,1151,1152],{},"oauth_authorization_codes"," and\n",[608,1155,1156],{},"oauth_refresh_tokens",". It does not change ",[608,1159,1160],{},"users",". Generate and commit a ",[597,1163,1165],{"href":1164},"\u002Fget-started\u002Fdatabase#migrations","migration","\nfor them.",[816,1168,1170],{"id":1169},"give-someone-the-admin-role","Give someone the admin role",[1134,1172,1173,1174,1176,1177,1179,1180,1183,1184,1187,1188,687],{},"Nobody can manage OAuth applications until a user holds a role with ",[608,1175,716],{},". Assign the ",[608,1178,723],{}," role to your\nfirst user in the ",[597,1181,1182],{"href":218},"Authorization admin",", or from ",[608,1185,1186],{},"authorization:roles",". See\n",[597,1189,205],{"href":206},[593,1191,1192,1193,1195,1196,1199,1200,1202],{},"Which roles may sign in to an application is set per application, in ",[608,1194,806],{},". The module reads the user's\n",[597,1197,1198],{"href":206},"effective roles"," from Authorization, so you need no code for\nit. ",[597,1201,234],{"href":235}," has the hooks that are left.",[1204,1205,1208,766,1211,1214,1215,1217,1218,1220,1221,1223],"callout",{"color":1206,"icon":1207},"success","i-lucide-check",[641,1209,1210],{},"What you should see:",[608,1212,1213],{},"\u002F.well-known\u002Fopenid-configuration"," answers with your ",[608,1216,599],{}," and the endpoint URLs. Signed\nin as an admin, ",[608,1219,676],{}," lists your OAuth applications and ",[608,1222,683],{}," your scopes.",[1225,1226,1227,1228,687],"tip",{},"To register your first application and choose between public and confidential, follow\n",[597,1229,136],{"href":137},[630,1231,1233],{"id":1232},"options","Options",[593,1235,1236,1237,1240],{},"Options go under the ",[608,1238,1239],{},"oauthServer"," key.",[1242,1243,1244,1263],"table",{},[1245,1246,1247],"thead",{},[1248,1249,1250,1254,1257,1260],"tr",{},[1251,1252,1253],"th",{},"Option",[1251,1255,1256],{},"Type",[1251,1258,1259],{},"Default",[1251,1261,1262],{},"Purpose",[1264,1265,1266,1288,1310,1330,1357,1374,1397,1416,1435,1454,1473,1500,1519,1537,1561,1590,1612,1632,1649,1671,1689],"tbody",{},[1248,1267,1268,1273,1278,1281],{},[1269,1270,1271],"td",{},[608,1272,599],{},[1269,1274,1275],{},[608,1276,1277],{},"string",[1269,1279,1280],{},"request origin",[1269,1282,1283,1284,1287],{},"The ",[608,1285,1286],{},"iss"," claim and the issuer in discovery.",[1248,1289,1290,1295,1299,1304],{},[1269,1291,1292],{},[608,1293,1294],{},"keyId",[1269,1296,1297],{},[608,1298,1277],{},[1269,1300,1301],{},[608,1302,1303],{},"'key-1'",[1269,1305,1283,1306,1309],{},[608,1307,1308],{},"kid"," of the signing key in the JWKS.",[1248,1311,1312,1317,1322,1327],{},[1269,1313,1314],{},[608,1315,1316],{},"accessTokenTtl",[1269,1318,1319],{},[608,1320,1321],{},"number",[1269,1323,1324],{},[608,1325,1326],{},"900",[1269,1328,1329],{},"Lifetime of access tokens and ID tokens, in seconds.",[1248,1331,1332,1337,1342,1348],{},[1269,1333,1334],{},[608,1335,1336],{},"accessTokenAudience",[1269,1338,1339],{},[608,1340,1341],{},"string | string[]",[1269,1343,1344,1345],{},"the ",[608,1346,1347],{},"client_id",[1269,1349,1283,1350,1353,1354,687],{},[608,1351,1352],{},"aud"," of every access token, such as ",[608,1355,1356],{},"frigear-services",[1248,1358,1359,1364,1368,1371],{},[1269,1360,1361],{},[608,1362,1363],{},"refreshToken.idleTtl",[1269,1365,1366],{},[608,1367,1321],{},[1269,1369,1370],{},"30 days",[1269,1372,1373],{},"How long a refresh token lives unused, in seconds. At most two years.",[1248,1375,1376,1381,1386,1391],{},[1269,1377,1378],{},[608,1379,1380],{},"refreshToken.maxAge",[1269,1382,1383],{},[608,1384,1385],{},"number | null",[1269,1387,1388],{},[608,1389,1390],{},"null",[1269,1392,1393,1394,1396],{},"How long a sign-in lives in total, in seconds. ",[608,1395,1390],{}," means no cap.",[1248,1398,1399,1404,1408,1410],{},[1269,1400,1401],{},[608,1402,1403],{},"refreshTokenTtl",[1269,1405,1406],{},[608,1407,1321],{},[1269,1409,1370],{},[1269,1411,1412,1413,1415],{},"Deprecated alias of ",[608,1414,1363],{},"; warns at build time.",[1248,1417,1418,1423,1428,1432],{},[1269,1419,1420],{},[608,1421,1422],{},"revokeOnCredentialChange",[1269,1424,1425],{},[608,1426,1427],{},"boolean",[1269,1429,1430],{},[608,1431,759],{},[1269,1433,1434],{},"Ends a user's sign-ins when their password or email changes.",[1248,1436,1437,1442,1446,1451],{},[1269,1438,1439],{},[608,1440,1441],{},"codeTtl",[1269,1443,1444],{},[608,1445,1321],{},[1269,1447,1448],{},[608,1449,1450],{},"600",[1269,1452,1453],{},"Lifetime of authorization codes, in seconds.",[1248,1455,1456,1461,1465,1470],{},[1269,1457,1458],{},[608,1459,1460],{},"callbackPath",[1269,1462,1463],{},[608,1464,1277],{},[1269,1466,1467],{},[608,1468,1469],{},"'\u002Fauth\u002Ffrigear'",[1269,1471,1472],{},"Added to an application's website URL to form its redirect URI.",[1248,1474,1475,1480,1485,1490],{},[1269,1476,1477],{},[608,1478,1479],{},"scopes",[1269,1481,1482],{},[608,1483,1484],{},"Array\u003Cstring | OAuthScopeDefinition>",[1269,1486,1487],{},[608,1488,1489],{},"[]",[1269,1491,1492,1493,1495,1496,1499],{},"Named ",[597,1494,1479],{"href":87}," next to ",[608,1497,1498],{},"openid profile email",", and how permission scopes read on the consent screen.",[1248,1501,1502,1507,1512,1516],{},[1269,1503,1504],{},[608,1505,1506],{},"cors.origins",[1269,1508,1509],{},[608,1510,1511],{},"string[]",[1269,1513,1514],{},[608,1515,1489],{},[1269,1517,1518],{},"Exact browser origins that may call the token, revoke, userinfo and discovery endpoints.",[1248,1520,1521,1526,1530,1534],{},[1269,1522,1523],{},[608,1524,1525],{},"cors.paths",[1269,1527,1528],{},[608,1529,1511],{},[1269,1531,1532],{},[608,1533,1489],{},[1269,1535,1536],{},"Path prefixes of your own API that the same origins may call with an access token.",[1248,1538,1539,1544,1549,1553],{},[1269,1540,1541],{},[608,1542,1543],{},"clients",[1269,1545,1546],{},[608,1547,1548],{},"OAuthConfiguredClient[]",[1269,1550,1551],{},[608,1552,1489],{},[1269,1554,1555,1558,1559,687],{},[597,1556,1557],{"href":87},"Configured clients",": public OAuth applications with a fixed ",[608,1560,1347],{},[1248,1562,1563,1568,1573,1581],{},[1269,1564,1565],{},[608,1566,1567],{},"settings.pages.authorize",[1269,1569,1570],{},[608,1571,1572],{},"string | boolean",[1269,1574,1575,1577,1578,1580],{},[608,1576,759],{}," (",[608,1579,651],{},")",[1269,1582,1583,1584,1587,1588,687],{},"The consent screen. ",[608,1585,1586],{},"false"," lets you put your own page at ",[608,1589,651],{},[1248,1591,1592,1597,1601,1604],{},[1269,1593,1594],{},[608,1595,1596],{},"settings.pages.admin",[1269,1598,1599],{},[608,1600,1572],{},[1269,1602,1603],{},"off",[1269,1605,1606,1607,1609,1610,687],{},"The admin screen for OAuth applications. ",[608,1608,759],{}," is ",[608,1611,676],{},[1248,1613,1614,1619,1623,1625],{},[1269,1615,1616],{},[608,1617,1618],{},"settings.pages.applications",[1269,1620,1621],{},[608,1622,1572],{},[1269,1624,1603],{},[1269,1626,1627,1628,1609,1630,687],{},"The signed-in user's applications. ",[608,1629,759],{},[608,1631,658],{},[1248,1633,1634,1639,1643,1646],{},[1269,1635,1636],{},[608,1637,1638],{},"settings.signInPath",[1269,1640,1641],{},[608,1642,1277],{},[1269,1644,1645],{},"the Auth login page",[1269,1647,1648],{},"Where signed-out people are sent to sign in.",[1248,1650,1651,1656,1660,1665],{},[1269,1652,1653],{},[608,1654,1655],{},"settings.pages.scopes",[1269,1657,1658],{},[608,1659,1572],{},[1269,1661,1662],{},[608,1663,1664],{},"\u003Cadmin>\u002Fscopes",[1269,1666,1667,1668,1670],{},"The admin screen for scopes. On when the applications screen is. ",[608,1669,1586],{}," turns it off.",[1248,1672,1673,1678,1683,1686],{},[1269,1674,1675],{},[608,1676,1677],{},"settings.roleScopes",[1269,1679,1680],{},[608,1681,1682],{},"Record\u003Cstring, string[]>",[1269,1684,1685],{},"unset",[1269,1687,1688],{},"The most each role may grant to an application. Unset means no cap.",[1248,1690,1691,1696,1700,1704],{},[1269,1692,1693],{},[608,1694,1695],{},"settings.mcp",[1269,1697,1698],{},[608,1699,1427],{},[1269,1701,1702],{},[608,1703,1586],{},[1269,1705,1706,1707,1709,1710,687],{},"Adds the ",[608,1708,737],{}," MCP tool, with the permission ",[608,1711,1712],{},"oauth:read",[593,1714,1715,1719],{},[641,1716,1717],{},[608,1718,599],{}," must be set explicitly behind a proxy.",[593,1721,1722,1726],{},[641,1723,1724],{},[608,1725,1294],{}," changes when you rotate the signing key.",[593,1728,1729,1733],{},[641,1730,1731],{},[608,1732,1316],{}," should stay at 5 to 15 minutes when other services accept the tokens. Those services cannot revoke\na token. They can only stop a refresh. The module warns at startup when an audience is set and the lifetime is over\n900 seconds.",[593,1735,1736,1741,1742,1746],{},[641,1737,1738],{},[608,1739,1740],{},"refreshToken"," is the default for applications without their own session length. Each application can set\nits own in the admin area (",[597,1743,1745],{"href":1744},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Froutes-and-clients#session-lifetimes","Session lifetimes",").",[593,1748,1749,1753,1754,1758,1759,1761],{},[641,1750,1751],{},[608,1752,1336],{}," is for tokens that\n",[597,1755,1757],{"href":1756},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Fserver#one-app-for-every-service","other services"," accept. ID tokens keep the\n",[608,1760,1347],{}," as their audience.",[593,1763,1764,1768,1769,1772,1773,1776,1777,1780,1781,1784,1785,1788,1789,1792,1793,1796,1797,1800,1801,687],{},[641,1765,1766],{},[608,1767,1479],{}," is where you name scopes. Pass a string, or an object\n",[608,1770,1771],{},"{ name, label?, description?, icon?, service?, permissions? }",". A single word such as ",[608,1774,1775],{},"tickets"," is a named scope that\nstands for its ",[608,1778,1779],{},"permissions",". A permission such as ",[608,1782,1783],{},"vouchers:read"," only describes that permission on the consent screen\nand groups it under its ",[608,1786,1787],{},"service",". Modules add named scopes with ",[608,1790,1791],{},"addScope"," from ",[608,1794,1795],{},"@frigear-nu\u002Fauth\u002Futils",", and staff\nadd more in the admin area. Add claims for a scope with the ",[608,1798,1799],{},"oauth:claims"," hook. See\n",[597,1802,1804],{"href":1803},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Fserver#scopes","Scopes",[593,1806,1807,1811,1812,687],{},[641,1808,1809],{},[608,1810,1677],{}," caps what each role may hand to an application, as scopes, permissions or wildcards. A user's\ncap is the union over all their effective roles. A role that is not listed adds nothing. Role names are checked at build\ntime. See ",[597,1813,1815],{"href":1814},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Fserver#capping-scopes-by-role","Capping scopes by role",[593,1817,1818,1822,1823,1825,1826,687],{},[641,1819,1820],{},[608,1821,1506],{}," never takes ",[608,1824,1007],{},". The origins of configured clients are added for you. See\n",[597,1827,1829],{"href":1828},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Froutes-and-clients#public-applications","Public applications",[593,1831,1832,1836,1837,1840,1841,687],{},[641,1833,1834],{},[608,1835,1525],{}," takes prefixes such as ",[608,1838,1839],{},"['\u002Fapi\u002F']",". See ",[597,1842,1844],{"href":1843},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Froutes-and-clients#calling-from-a-browser-on-another-origin","Calling from a browser on another\norigin",[593,1846,1847,1851,1852,687],{},[641,1848,1849],{},[608,1850,1543],{}," defines applications in config instead of in the admin area. See\n",[597,1853,1557],{"href":1854},"\u002Fmodules\u002Fidentity\u002Foauth-server\u002Froutes-and-clients#configured-clients",[593,1856,1857,1861,1862,1864],{},[641,1858,1859],{},[608,1860,1596],{}," is registered only when ",[597,1863,217],{"href":351}," is installed.",[816,1866,1868],{"id":1867},"runtime-config","Runtime config",[593,1870,1871],{},"Keys are secrets, so they are set through runtime config, not module options.",[1242,1873,1874,1885],{},[1245,1875,1876],{},[1248,1877,1878,1880,1883],{},[1251,1879,1868],{},[1251,1881,1882],{},"Env var",[1251,1884,1262],{},[1264,1886,1887,1901,1916,1931,1946,1963,1980,1997,2015],{},[1248,1888,1889,1894,1898],{},[1269,1890,1891],{},[608,1892,1893],{},"oauthServer.privateKey",[1269,1895,1896],{},[608,1897,1124],{},[1269,1899,1900],{},"The RSA private key, as PKCS#8 PEM. Required.",[1248,1902,1903,1908,1913],{},[1269,1904,1905],{},[608,1906,1907],{},"oauthServer.publicKey",[1269,1909,1910],{},[608,1911,1912],{},"NUXT_OAUTH_SERVER_PUBLIC_KEY",[1269,1914,1915],{},"Overrides the public key that is derived from the private key.",[1248,1917,1918,1923,1928],{},[1269,1919,1920],{},[608,1921,1922],{},"oauthServer.accessTokenAudience",[1269,1924,1925],{},[608,1926,1927],{},"NUXT_OAUTH_SERVER_ACCESS_TOKEN_AUDIENCE",[1269,1929,1930],{},"The shared audience of access tokens, comma separated.",[1248,1932,1933,1938,1943],{},[1269,1934,1935],{},[608,1936,1937],{},"oauthServer.corsOrigins",[1269,1939,1940],{},[608,1941,1942],{},"NUXT_OAUTH_SERVER_CORS_ORIGINS",[1269,1944,1945],{},"The CORS origins, comma separated.",[1248,1947,1948,1953,1958],{},[1269,1949,1950],{},[608,1951,1952],{},"oauthServer.corsPaths",[1269,1954,1955],{},[608,1956,1957],{},"NUXT_OAUTH_SERVER_CORS_PATHS",[1269,1959,1960,1962],{},[608,1961,1525],{},", comma separated.",[1248,1964,1965,1970,1975],{},[1269,1966,1967],{},[608,1968,1969],{},"oauthServer.refreshToken.idleTtl",[1269,1971,1972],{},[608,1973,1974],{},"NUXT_OAUTH_SERVER_REFRESH_TOKEN_IDLE_TTL",[1269,1976,1977,1979],{},[608,1978,1363],{}," per environment, in seconds.",[1248,1981,1982,1987,1992],{},[1269,1983,1984],{},[608,1985,1986],{},"oauthServer.refreshToken.maxAge",[1269,1988,1989],{},[608,1990,1991],{},"NUXT_OAUTH_SERVER_REFRESH_TOKEN_MAX_AGE",[1269,1993,1994,1996],{},[608,1995,1380],{}," per environment, in seconds. Empty means no cap.",[1248,1998,1999,2004,2009],{},[1269,2000,2001],{},[608,2002,2003],{},"oauthServer.clients",[1269,2005,2006],{},[608,2007,2008],{},"NUXT_OAUTH_SERVER_CLIENTS",[1269,2010,2011,2012,2014],{},"Replaces ",[608,2013,1543],{}," with a JSON array of the same shape.",[1248,2016,2017,2022,2027],{},[1269,2018,2019],{},[608,2020,2021],{},"oauthServer.previousPublicKeys",[1269,2023,2024],{},[608,2025,2026],{},"NUXT_OAUTH_SERVER_PREVIOUS_PUBLIC_KEYS",[1269,2028,2029],{},"Public keys of retired keys during a rotation.",[593,2031,2032,2036],{},[641,2033,2034],{},[608,2035,1937],{}," helps when the origins differ per environment, such as the dev server of a mobile app.",[593,2038,2039,2043,2044,687],{},[641,2040,2041],{},[608,2042,2003],{}," is validated when the first OAuth request needs it. An invalid list answers\n",[608,2045,2046],{},"500 not_configured",[593,2048,2049,1609,2053,2056],{},[641,2050,2051],{},[608,2052,2021],{},[608,2054,2055],{},"{ \"\u003Ckid>\": \"\u003CSPKI PEM>\" }",", or the same object as a JSON string.",[816,2058,141],{"id":2059},"signing-keys",[593,2061,2062,2063,2066,2067,2069],{},"A missing or malformed signing key answers ",[608,2064,2065],{},"500"," with \"The OAuth server signing keys are not configured.\"\n",[597,2068,141],{"href":142}," covers generating, storing and rotating the key.",[761,2071,2072,2073,2076,2077,2080,2081,2084,2085,2088,2089,687],{},"Under ",[608,2074,2075],{},"nuxt dev"," with no key, the module generates one into ",[608,2078,2079],{},".data\u002Foauth-server\u002Fdev-key.pem"," (mode ",[608,2082,2083],{},"0600","). It reuses\nthat key on every restart and logs a warning. ",[608,2086,2087],{},"nuxt build"," never does this, so a production server without a key keeps\nanswering ",[608,2090,2046],{},[630,2092,2094],{"id":2093},"module-pages","Module pages",[1242,2096,2097,2110],{},[1245,2098,2099],{},[1248,2100,2101,2104,2107],{},[1251,2102,2103],{},"Page",[1251,2105,2106],{},"What it covers",[1251,2108,2109],{},"For",[1264,2111,2112,2124,2136],{},[1248,2113,2114,2118,2121],{},[1269,2115,2116],{},[597,2117,749],{"href":231},[1269,2119,2120],{},"Server helpers, scopes, calling your API with an access token, one app for every service, and the composables.",[1269,2122,2123],{},"App developers and module authors",[1248,2125,2126,2130,2133],{},[1269,2127,2128],{},[597,2129,234],{"href":235},[1269,2131,2132],{},"Who may manage applications, how roles decide who signs in, what goes into tokens, vetoes, and the removed hooks.",[1269,2134,2135],{},"App developers",[1248,2137,2138,2143,2146],{},[1269,2139,2140],{},[597,2141,2142],{"href":238},"Routes and clients",[1269,2144,2145],{},"Endpoints, introspection, how a sign-in works, public and configured applications, database and translations.",[1269,2147,2148],{},"App developers and anyone connecting an app",[630,2150,2152],{"id":2151},"next-steps","Next steps",[635,2154,2155,2160,2165,2170,2175,2180],{},[638,2156,2157,2159],{},[597,2158,136],{"href":137}," – register the first app that signs in here.",[638,2161,2162,2164],{},[597,2163,1804],{"href":1803}," – decide what applications may ask users for.",[638,2166,2167,2169],{},[597,2168,234],{"href":235}," – add claims, veto access and audit tokens.",[638,2171,2172,2174],{},[597,2173,199],{"href":200}," – roles and permissions, which decide who manages applications and what\nusers may grant.",[638,2176,2177,2179],{},[597,2178,81],{"href":82}," – see where OAuth Server sits next to Auth, Mobile and OAuth Resource.",[638,2181,2182,2184],{},[597,2183,241],{"href":242}," – let a separate service accept this issuer's access tokens.",[2186,2187,2188],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":826,"searchDepth":900,"depth":900,"links":2190},[2191,2192,2200,2204,2205],{"id":632,"depth":900,"text":633},{"id":810,"depth":900,"text":811,"children":2193},[2194,2195,2197,2198,2199],{"id":818,"depth":953,"text":819},{"id":856,"depth":953,"text":2196},"Configure it in nuxt.config.ts",{"id":1117,"depth":953,"text":1118},{"id":1139,"depth":953,"text":1140},{"id":1169,"depth":953,"text":1170},{"id":1232,"depth":900,"text":1233,"children":2201},[2202,2203],{"id":1867,"depth":953,"text":1868},{"id":2059,"depth":953,"text":141},{"id":2093,"depth":900,"text":2094},{"id":2151,"depth":900,"text":2152},"Let people sign in to your other apps and services with the account they already have in this app.","md",null,{},{"title":173},{"title":225,"description":2206},"LWcCICen0huP-8xjru-GlW4VWEgGm-tS0iitEWjL6QY",[2214,2216],{"title":221,"path":222,"stem":223,"description":2215,"children":-1},"Stores each user's settings, such as colour mode or table density, with types, validation and an optional hand-off to other apps.",{"title":175,"path":231,"stem":232,"description":2217,"children":-1},"Create OAuth applications from code, define scopes, let applications call your API and sign one app in to every service.",1794503146482]