[{"data":1,"prerenderedAt":2519},["ShallowReactive",2],{"navigation_docs":3,"-modules-authorization":153,"-modules-authorization-surround":2514},[4,35,50,59,144],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":6},"Getting started",false,"\u002Fgetting-started","1.getting-started",[10,15,20,25,30],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F2.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Local Development","\u002Fgetting-started\u002Flocal-development","1.getting-started\u002F3.local-development","i-lucide-terminal",{"title":21,"path":22,"stem":23,"icon":24},"Publishing Packages","\u002Fgetting-started\u002Fpublishing","1.getting-started\u002F4.publishing","i-lucide-package-check",{"title":26,"path":27,"stem":28,"icon":29},"Writing a Module","\u002Fgetting-started\u002Fwriting-a-module","1.getting-started\u002F5.writing-a-module","i-lucide-puzzle",{"title":31,"path":32,"stem":33,"icon":34},"UX Patterns","\u002Fgetting-started\u002Fux-patterns","1.getting-started\u002F6.ux-patterns","i-lucide-layout-template",{"title":36,"path":37,"stem":38,"children":39},"Applications","\u002Fapplications","2.applications",[40,45],{"title":41,"path":42,"stem":43,"icon":44},"Website","\u002Fapplications\u002Fwebsite","2.applications\u002F1.website","i-lucide-layout-dashboard",{"title":46,"path":47,"stem":48,"icon":49},"Docs","\u002Fapplications\u002Fdocs","2.applications\u002F2.docs","i-lucide-book-open",{"title":51,"path":52,"stem":53,"children":54},"Layers","\u002Flayers","3.layers",[55],{"title":56,"path":57,"stem":58},"Base Layer","\u002Flayers\u002Fbase","3.layers\u002F1.base",{"title":60,"path":61,"stem":62,"children":63},"Modules","\u002Fmodules","4.modules",[64,68,72,76,80,84,88,92,96,100,104,108,112,116,120,124,128,132,136,140],{"title":65,"path":66,"stem":67},"Account","\u002Fmodules\u002Faccount","4.modules\u002F01.account",{"title":69,"path":70,"stem":71},"Admin","\u002Fmodules\u002Fadmin","4.modules\u002F02.admin",{"title":73,"path":74,"stem":75},"Auth","\u002Fmodules\u002Fauth","4.modules\u002F03.auth",{"title":77,"path":78,"stem":79},"Authorization","\u002Fmodules\u002Fauthorization","4.modules\u002F04.authorization",{"title":81,"path":82,"stem":83},"Cookie Consent","\u002Fmodules\u002Fcookie-consent","4.modules\u002F05.cookie-consent",{"title":85,"path":86,"stem":87},"Events","\u002Fmodules\u002Fevents","4.modules\u002F06.events",{"title":89,"path":90,"stem":91},"Forms","\u002Fmodules\u002Fforms","4.modules\u002F07.forms",{"title":93,"path":94,"stem":95},"MCP","\u002Fmodules\u002Fmcp","4.modules\u002F08.mcp",{"title":97,"path":98,"stem":99},"Menu","\u002Fmodules\u002Fmenu","4.modules\u002F09.menu",{"title":101,"path":102,"stem":103},"Module Kit","\u002Fmodules\u002Fmodule-kit","4.modules\u002F10.module-kit",{"title":105,"path":106,"stem":107},"Notify","\u002Fmodules\u002Fnotify","4.modules\u002F11.notify",{"title":109,"path":110,"stem":111},"OAuth Server","\u002Fmodules\u002Foauth-server","4.modules\u002F12.oauth-server",{"title":113,"path":114,"stem":115},"Payments","\u002Fmodules\u002Fpayments","4.modules\u002F13.payments",{"title":117,"path":118,"stem":119},"Preferences","\u002Fmodules\u002Fpreferences","4.modules\u002F14.preferences",{"title":121,"path":122,"stem":123},"Stripe","\u002Fmodules\u002Fstripe","4.modules\u002F15.stripe",{"title":125,"path":126,"stem":127},"Subscriptions","\u002Fmodules\u002Fsubscriptions","4.modules\u002F16.subscriptions",{"title":129,"path":130,"stem":131},"UI","\u002Fmodules\u002Fui","4.modules\u002F17.ui",{"title":133,"path":134,"stem":135},"Users","\u002Fmodules\u002Fusers","4.modules\u002F18.users",{"title":137,"path":138,"stem":139},"Widget","\u002Fmodules\u002Fwidget","4.modules\u002F19.widget",{"title":141,"path":142,"stem":143},"Email Templates","\u002Fmodules\u002Femail-templates","4.modules\u002F20.email-templates",{"title":145,"path":146,"stem":147,"children":148},"Packages","\u002Fpackages","5.packages",[149],{"title":150,"path":151,"stem":152},"CLI","\u002Fpackages\u002Fcli","5.packages\u002F4.cli",{"id":154,"title":77,"body":155,"description":2508,"extension":2509,"links":2510,"meta":2511,"navigation":867,"path":78,"seo":2512,"stem":79,"__hash__":2513},"docs\u002F4.modules\u002F04.authorization.md",{"type":156,"value":157,"toc":2495},"minimark",[158,179,207,212,237,408,498,604,666,685,689,801,805,818,1040,1047,1311,1315,1321,1418,1423,1440,1464,1468,1474,1636,1643,1830,1834,1919,1927,1985,1992,1996,2018,2218,2285,2302,2359,2457,2466,2469,2491],[159,160,161,162,169,170,172,173,178],"p",{},"Policy-based authorization as a ",[163,164,168],"a",{"href":165,"rel":166},"https:\u002F\u002Fnuxt.com\u002Fdocs\u002F4.x\u002Fguide\u002Fmodules",[167],"nofollow","Nuxt module",": what an already-identified user\nmay do. Authentication stays in ",[163,171,73],{"href":74},". The design follows\n",[163,174,177],{"href":175,"rel":176},"https:\u002F\u002Fgithub.com\u002Fbarbapapazes\u002Fnuxt-authorization",[167],"nuxt-authorization",": the app defines policies as functions and the\ncurrent user is injected into them by a resolver (one for the app, one for the server).",[180,181,182,186,187,191,192,191,195,200,201,206],"note",{},[183,184,185],"strong",{},"Requires"," ",[188,189,190],"code",{},"@nuxthub\u002Fcore",", ",[188,193,194],{},"@frigear-nu\u002Fmodule-kit",[163,196,197],{"href":74},[188,198,199],{},"@frigear-nu\u002Fauth"," and\n",[163,202,203],{"href":134},[188,204,205],{},"@frigear-nu\u002Fusers","; all are installed automatically.",[208,209,211],"h2",{"id":210},"quick-setup","Quick setup",[213,214,219],"pre",{"className":215,"code":216,"language":217,"meta":218,"style":218},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","pnpm add @frigear-nu\u002Fauthorization\n","bash","",[188,220,221],{"__ignoreMap":218},[222,223,226,230,234],"span",{"class":224,"line":225},"line",1,[222,227,229],{"class":228},"sBMFI","pnpm",[222,231,233],{"class":232},"sfazB"," add",[222,235,236],{"class":232}," @frigear-nu\u002Fauthorization\n",[213,238,242],{"className":239,"code":240,"language":241,"meta":218,"style":218},"language-ts shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","export default defineNuxtConfig({\n  modules: ['@nuxthub\u002Fcore', '@frigear-nu\u002Fusers', '@frigear-nu\u002Fauthorization'],\n  routeRules: {\n    '\u002Fadmin\u002F**': { roles: ['admin'] },\n  },\n  authorization: {\n    redirectTo: '\u002Flogin', \u002F\u002F unauthenticated page visits; omit to show a 401 error\n  },\n})\n","ts",[188,243,244,265,310,321,357,363,373,394,399],{"__ignoreMap":218},[222,245,246,250,253,257,261],{"class":224,"line":225},[222,247,249],{"class":248},"s7zQu","export",[222,251,252],{"class":248}," default",[222,254,256],{"class":255},"s2Zo4"," defineNuxtConfig",[222,258,260],{"class":259},"sTEyZ","(",[222,262,264],{"class":263},"sMK4o","{\n",[222,266,268,272,275,278,281,283,285,288,291,293,295,297,299,302,304,307],{"class":224,"line":267},2,[222,269,271],{"class":270},"swJcz","  modules",[222,273,274],{"class":263},":",[222,276,277],{"class":259}," [",[222,279,280],{"class":263},"'",[222,282,190],{"class":232},[222,284,280],{"class":263},[222,286,287],{"class":263},",",[222,289,290],{"class":263}," '",[222,292,205],{"class":232},[222,294,280],{"class":263},[222,296,287],{"class":263},[222,298,290],{"class":263},[222,300,301],{"class":232},"@frigear-nu\u002Fauthorization",[222,303,280],{"class":263},[222,305,306],{"class":259},"]",[222,308,309],{"class":263},",\n",[222,311,313,316,318],{"class":224,"line":312},3,[222,314,315],{"class":270},"  routeRules",[222,317,274],{"class":263},[222,319,320],{"class":263}," {\n",[222,322,324,327,330,332,334,337,340,342,344,346,349,351,354],{"class":224,"line":323},4,[222,325,326],{"class":263},"    '",[222,328,329],{"class":270},"\u002Fadmin\u002F**",[222,331,280],{"class":263},[222,333,274],{"class":263},[222,335,336],{"class":263}," {",[222,338,339],{"class":270}," roles",[222,341,274],{"class":263},[222,343,277],{"class":259},[222,345,280],{"class":263},[222,347,348],{"class":232},"admin",[222,350,280],{"class":263},[222,352,353],{"class":259},"] ",[222,355,356],{"class":263},"},\n",[222,358,360],{"class":224,"line":359},5,[222,361,362],{"class":263},"  },\n",[222,364,366,369,371],{"class":224,"line":365},6,[222,367,368],{"class":270},"  authorization",[222,370,274],{"class":263},[222,372,320],{"class":263},[222,374,376,379,381,383,386,388,390],{"class":224,"line":375},7,[222,377,378],{"class":270},"    redirectTo",[222,380,274],{"class":263},[222,382,290],{"class":263},[222,384,385],{"class":232},"\u002Flogin",[222,387,280],{"class":263},[222,389,287],{"class":263},[222,391,393],{"class":392},"sHwdD"," \u002F\u002F unauthenticated page visits; omit to show a 401 error\n",[222,395,397],{"class":224,"line":396},8,[222,398,362],{"class":263},[222,400,402,405],{"class":224,"line":401},9,[222,403,404],{"class":263},"}",[222,406,407],{"class":259},")\n",[213,409,411],{"className":239,"code":410,"language":241,"meta":218,"style":218},"\u002F\u002F shared\u002Futils\u002Fabilities.ts - auto-imported in the app and the server\nexport const editPost = defineAbility((user, post: Post) => user.id === post.userId || user.role === 'admin')\n",[188,412,413,418],{"__ignoreMap":218},[222,414,415],{"class":224,"line":225},[222,416,417],{"class":392},"\u002F\u002F shared\u002Futils\u002Fabilities.ts - auto-imported in the app and the server\n",[222,419,420,422,426,429,432,435,437,439,443,445,448,450,453,456,459,462,465,468,471,473,475,478,481,483,485,488,490,492,494,496],{"class":224,"line":267},[222,421,249],{"class":248},[222,423,425],{"class":424},"spNyl"," const",[222,427,428],{"class":259}," editPost ",[222,430,431],{"class":263},"=",[222,433,434],{"class":255}," defineAbility",[222,436,260],{"class":259},[222,438,260],{"class":263},[222,440,442],{"class":441},"sHdIc","user",[222,444,287],{"class":263},[222,446,447],{"class":441}," post",[222,449,274],{"class":263},[222,451,452],{"class":228}," Post",[222,454,455],{"class":263},")",[222,457,458],{"class":424}," =>",[222,460,461],{"class":259}," user",[222,463,464],{"class":263},".",[222,466,467],{"class":259},"id ",[222,469,470],{"class":263},"===",[222,472,447],{"class":259},[222,474,464],{"class":263},[222,476,477],{"class":259},"userId ",[222,479,480],{"class":263},"||",[222,482,461],{"class":259},[222,484,464],{"class":263},[222,486,487],{"class":259},"role ",[222,489,470],{"class":263},[222,491,290],{"class":263},[222,493,348],{"class":232},[222,495,280],{"class":263},[222,497,407],{"class":259},[213,499,501],{"className":239,"code":500,"language":241,"meta":218,"style":218},"\u002F\u002F server\u002Fapi\u002Fposts\u002F[id].put.ts\nexport default defineEventHandler(async (event) => {\n  const post = await findPost(getRouterParam(event, 'id'))\n  await authorize(event, editPost, post) \u002F\u002F throws 403 when denied\n})\n",[188,502,503,508,534,571,598],{"__ignoreMap":218},[222,504,505],{"class":224,"line":225},[222,506,507],{"class":392},"\u002F\u002F server\u002Fapi\u002Fposts\u002F[id].put.ts\n",[222,509,510,512,514,517,519,522,525,528,530,532],{"class":224,"line":267},[222,511,249],{"class":248},[222,513,252],{"class":248},[222,515,516],{"class":255}," defineEventHandler",[222,518,260],{"class":259},[222,520,521],{"class":424},"async",[222,523,524],{"class":263}," (",[222,526,527],{"class":441},"event",[222,529,455],{"class":263},[222,531,458],{"class":424},[222,533,320],{"class":263},[222,535,536,539,541,544,547,550,552,555,557,559,561,563,566,568],{"class":224,"line":312},[222,537,538],{"class":424},"  const",[222,540,447],{"class":259},[222,542,543],{"class":263}," =",[222,545,546],{"class":248}," await",[222,548,549],{"class":255}," findPost",[222,551,260],{"class":270},[222,553,554],{"class":255},"getRouterParam",[222,556,260],{"class":270},[222,558,527],{"class":259},[222,560,287],{"class":263},[222,562,290],{"class":263},[222,564,565],{"class":232},"id",[222,567,280],{"class":263},[222,569,570],{"class":270},"))\n",[222,572,573,576,579,581,583,585,588,590,592,595],{"class":224,"line":323},[222,574,575],{"class":248},"  await",[222,577,578],{"class":255}," authorize",[222,580,260],{"class":270},[222,582,527],{"class":259},[222,584,287],{"class":263},[222,586,587],{"class":259}," editPost",[222,589,287],{"class":263},[222,591,447],{"class":259},[222,593,594],{"class":270},") ",[222,596,597],{"class":392},"\u002F\u002F throws 403 when denied\n",[222,599,600,602],{"class":224,"line":359},[222,601,404],{"class":263},[222,603,407],{"class":259},[213,605,609],{"className":606,"code":607,"language":608,"meta":218,"style":218},"language-vue shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u003CCan :ability=\"editPost\" :args=\"[post]\">\n  \u003Cbutton>Edit\u003C\u002Fbutton>\n\u003C\u002FCan>\n","vue",[188,610,611,652,657],{"__ignoreMap":218},[222,612,613,616,619,622,625,627,630,633,635,637,640,642,644,647,649],{"class":224,"line":225},[222,614,615],{"class":263},"\u003C",[222,617,618],{"class":270},"Can",[222,620,621],{"class":263}," :",[222,623,624],{"class":424},"ability",[222,626,431],{"class":263},[222,628,629],{"class":263},"\"",[222,631,632],{"class":259},"editPost",[222,634,629],{"class":263},[222,636,621],{"class":263},[222,638,639],{"class":424},"args",[222,641,431],{"class":263},[222,643,629],{"class":263},[222,645,646],{"class":259},"[post]",[222,648,629],{"class":263},[222,650,651],{"class":263},">\n",[222,653,654],{"class":224,"line":267},[222,655,656],{"class":259},"  \u003Cbutton>Edit\u003C\u002Fbutton>\n",[222,658,659,662,664],{"class":224,"line":312},[222,660,661],{"class":263},"\u003C\u002F",[222,663,618],{"class":270},[222,665,651],{"class":263},[667,668,669,670,673,674,677,678,682,683,464],"warning",{},"The module adds a ",[188,671,672],{},"role"," column to ",[188,675,676],{},"users"," (see ",[163,679,681],{"href":680},"#database","Database","). That only changes the generated Drizzle schema,\nso generate and commit a migration in your app and in every fixture that uses the module. See\n",[163,684,101],{"href":102},[208,686,688],{"id":687},"options","Options",[690,691,692,711],"table",{},[693,694,695],"thead",{},[696,697,698,702,705,708],"tr",{},[699,700,701],"th",{},"Option",[699,703,704],{},"Type",[699,706,707],{},"Default",[699,709,710],{},"Purpose",[712,713,714,739,760,780],"tbody",{},[696,715,716,722,727,736],{},[717,718,719],"td",{},[188,720,721],{},"abilities",[717,723,724],{},[188,725,726],{},"string",[717,728,729,732,733],{},[188,730,731],{},"shared\u002Futils\u002Fabilities.ts",", else ",[188,734,735],{},"shared\u002Fabilities.ts",[717,737,738],{},"Path to the abilities file. Needed to refer to abilities by name in route rules and page meta.",[696,740,741,746,750,753],{},[717,742,743],{},[188,744,745],{},"resolvers.server",[717,747,748],{},[188,749,726],{},[717,751,752],{},"session or bearer user",[717,754,755,756,759],{},"Path to a default-export ",[188,757,758],{},"(event: H3Event) => User | null"," replacing the server resolver.",[696,761,762,767,771,774],{},[717,763,764],{},[188,765,766],{},"resolvers.client",[717,768,769],{},[188,770,726],{},[717,772,773],{},"session user",[717,775,755,776,779],{},[188,777,778],{},"() => User | null"," replacing the app resolver.",[696,781,782,787,791,794],{},[717,783,784],{},[188,785,786],{},"redirectTo",[717,788,789],{},[188,790,726],{},[717,792,793],{},"-",[717,795,796,797,800],{},"Redirect target for unauthenticated page navigation. Without it a ",[188,798,799],{},"401"," error is shown.",[208,802,804],{"id":803},"defining-abilities","Defining abilities",[159,806,807,191,810,813,814,817],{},[188,808,809],{},"defineAbility",[188,811,812],{},"allow"," and ",[188,815,816],{},"deny"," are auto-imported in app and server. The first argument of a policy is the resolved\nuser, the rest are the arguments passed when checking.",[213,819,821],{"className":239,"code":820,"language":241,"meta":218,"style":218},"\u002F\u002F shared\u002Futils\u002Fabilities.ts\nexport const isAdmin = defineAbility(user => user.role === 'admin')\n\nexport const editPost = defineAbility((user, post: Post) =>\n  user.id === post.userId || user.role === 'admin' || deny({ message: 'Not your post' }))\n\n\u002F\u002F Let guests reach the policy (it receives `null`).\nexport const viewPost = defineAbility({ allowGuest: true }, (user, post: Post) => post.published || user?.id === post.userId)\n",[188,822,823,828,863,869,900,961,965,970],{"__ignoreMap":218},[222,824,825],{"class":224,"line":225},[222,826,827],{"class":392},"\u002F\u002F shared\u002Futils\u002Fabilities.ts\n",[222,829,830,832,834,837,839,841,843,845,847,849,851,853,855,857,859,861],{"class":224,"line":267},[222,831,249],{"class":248},[222,833,425],{"class":424},[222,835,836],{"class":259}," isAdmin ",[222,838,431],{"class":263},[222,840,434],{"class":255},[222,842,260],{"class":259},[222,844,442],{"class":441},[222,846,458],{"class":424},[222,848,461],{"class":259},[222,850,464],{"class":263},[222,852,487],{"class":259},[222,854,470],{"class":263},[222,856,290],{"class":263},[222,858,348],{"class":232},[222,860,280],{"class":263},[222,862,407],{"class":259},[222,864,865],{"class":224,"line":312},[222,866,868],{"emptyLinePlaceholder":867},true,"\n",[222,870,871,873,875,877,879,881,883,885,887,889,891,893,895,897],{"class":224,"line":323},[222,872,249],{"class":248},[222,874,425],{"class":424},[222,876,428],{"class":259},[222,878,431],{"class":263},[222,880,434],{"class":255},[222,882,260],{"class":259},[222,884,260],{"class":263},[222,886,442],{"class":441},[222,888,287],{"class":263},[222,890,447],{"class":441},[222,892,274],{"class":263},[222,894,452],{"class":228},[222,896,455],{"class":263},[222,898,899],{"class":424}," =>\n",[222,901,902,905,907,909,911,913,915,917,919,921,923,925,927,929,931,933,936,939,941,944,947,949,951,954,956,959],{"class":224,"line":359},[222,903,904],{"class":259},"  user",[222,906,464],{"class":263},[222,908,467],{"class":259},[222,910,470],{"class":263},[222,912,447],{"class":259},[222,914,464],{"class":263},[222,916,477],{"class":259},[222,918,480],{"class":263},[222,920,461],{"class":259},[222,922,464],{"class":263},[222,924,487],{"class":259},[222,926,470],{"class":263},[222,928,290],{"class":263},[222,930,348],{"class":232},[222,932,280],{"class":263},[222,934,935],{"class":263}," ||",[222,937,938],{"class":255}," deny",[222,940,260],{"class":259},[222,942,943],{"class":263},"{",[222,945,946],{"class":270}," message",[222,948,274],{"class":263},[222,950,290],{"class":263},[222,952,953],{"class":232},"Not your post",[222,955,280],{"class":263},[222,957,958],{"class":263}," }",[222,960,570],{"class":259},[222,962,963],{"class":224,"line":365},[222,964,868],{"emptyLinePlaceholder":867},[222,966,967],{"class":224,"line":375},[222,968,969],{"class":392},"\u002F\u002F Let guests reach the policy (it receives `null`).\n",[222,971,972,974,976,979,981,983,985,987,990,992,996,999,1001,1003,1005,1007,1009,1011,1013,1015,1017,1019,1022,1024,1026,1029,1031,1033,1035,1037],{"class":224,"line":396},[222,973,249],{"class":248},[222,975,425],{"class":424},[222,977,978],{"class":259}," viewPost ",[222,980,431],{"class":263},[222,982,434],{"class":255},[222,984,260],{"class":259},[222,986,943],{"class":263},[222,988,989],{"class":270}," allowGuest",[222,991,274],{"class":263},[222,993,995],{"class":994},"sfNiH"," true",[222,997,998],{"class":263}," },",[222,1000,524],{"class":263},[222,1002,442],{"class":441},[222,1004,287],{"class":263},[222,1006,447],{"class":441},[222,1008,274],{"class":263},[222,1010,452],{"class":228},[222,1012,455],{"class":263},[222,1014,458],{"class":424},[222,1016,447],{"class":259},[222,1018,464],{"class":263},[222,1020,1021],{"class":259},"published ",[222,1023,480],{"class":263},[222,1025,461],{"class":259},[222,1027,1028],{"class":263},"?.",[222,1030,467],{"class":259},[222,1032,470],{"class":263},[222,1034,447],{"class":259},[222,1036,464],{"class":263},[222,1038,1039],{"class":259},"userId)\n",[159,1041,1042,1043,1046],{},"Without ",[188,1044,1045],{},"allowGuest",", guests are denied before the policy runs.",[213,1048,1050],{"className":239,"code":1049,"language":241,"meta":218,"style":218},"type AuthorizationResponse = { authorized: boolean, statusCode?: number, message?: string }\ntype AuthorizerResponse = boolean | AuthorizationResponse | Promise\u003Cboolean | AuthorizationResponse>\ntype Authorizer\u003CUser = any> = (user: User, ...args: any[]) => AuthorizerResponse\n\ninterface Ability\u003CUser = any> {\n  allowGuest: boolean\n  original: Authorizer\u003CUser>\n  execute: (user: User | null, ...args: any[]) => AuthorizerResponse\n}\n\nallow() \u002F\u002F { authorized: true }\ndeny({ statusCode?, message? }) \u002F\u002F statusCode defaults to 403\n",[188,1051,1052,1095,1127,1179,1183,1203,1213,1228,1266,1271,1276,1287],{"__ignoreMap":218},[222,1053,1054,1057,1060,1062,1064,1067,1069,1072,1074,1077,1080,1083,1085,1087,1089,1092],{"class":224,"line":225},[222,1055,1056],{"class":424},"type",[222,1058,1059],{"class":228}," AuthorizationResponse",[222,1061,543],{"class":263},[222,1063,336],{"class":263},[222,1065,1066],{"class":270}," authorized",[222,1068,274],{"class":263},[222,1070,1071],{"class":228}," boolean",[222,1073,287],{"class":263},[222,1075,1076],{"class":270}," statusCode",[222,1078,1079],{"class":263},"?:",[222,1081,1082],{"class":228}," number",[222,1084,287],{"class":263},[222,1086,946],{"class":270},[222,1088,1079],{"class":263},[222,1090,1091],{"class":228}," string",[222,1093,1094],{"class":263}," }\n",[222,1096,1097,1099,1102,1104,1106,1109,1111,1113,1116,1118,1121,1123,1125],{"class":224,"line":267},[222,1098,1056],{"class":424},[222,1100,1101],{"class":228}," AuthorizerResponse",[222,1103,543],{"class":263},[222,1105,1071],{"class":228},[222,1107,1108],{"class":263}," |",[222,1110,1059],{"class":228},[222,1112,1108],{"class":263},[222,1114,1115],{"class":228}," Promise",[222,1117,615],{"class":263},[222,1119,1120],{"class":228},"boolean",[222,1122,1108],{"class":263},[222,1124,1059],{"class":228},[222,1126,651],{"class":263},[222,1128,1129,1131,1134,1136,1139,1141,1144,1147,1149,1151,1153,1155,1158,1160,1163,1165,1167,1169,1172,1174,1176],{"class":224,"line":312},[222,1130,1056],{"class":424},[222,1132,1133],{"class":228}," Authorizer",[222,1135,615],{"class":263},[222,1137,1138],{"class":228},"User",[222,1140,543],{"class":263},[222,1142,1143],{"class":228}," any",[222,1145,1146],{"class":263},">",[222,1148,543],{"class":263},[222,1150,524],{"class":263},[222,1152,442],{"class":441},[222,1154,274],{"class":263},[222,1156,1157],{"class":228}," User",[222,1159,287],{"class":263},[222,1161,1162],{"class":263}," ...",[222,1164,639],{"class":441},[222,1166,274],{"class":263},[222,1168,1143],{"class":228},[222,1170,1171],{"class":259},"[]",[222,1173,455],{"class":263},[222,1175,458],{"class":424},[222,1177,1178],{"class":228}," AuthorizerResponse\n",[222,1180,1181],{"class":224,"line":323},[222,1182,868],{"emptyLinePlaceholder":867},[222,1184,1185,1188,1191,1193,1195,1197,1199,1201],{"class":224,"line":359},[222,1186,1187],{"class":424},"interface",[222,1189,1190],{"class":228}," Ability",[222,1192,615],{"class":263},[222,1194,1138],{"class":228},[222,1196,543],{"class":263},[222,1198,1143],{"class":228},[222,1200,1146],{"class":263},[222,1202,320],{"class":263},[222,1204,1205,1208,1210],{"class":224,"line":365},[222,1206,1207],{"class":270},"  allowGuest",[222,1209,274],{"class":263},[222,1211,1212],{"class":228}," boolean\n",[222,1214,1215,1218,1220,1222,1224,1226],{"class":224,"line":375},[222,1216,1217],{"class":270},"  original",[222,1219,274],{"class":263},[222,1221,1133],{"class":228},[222,1223,615],{"class":263},[222,1225,1138],{"class":228},[222,1227,651],{"class":263},[222,1229,1230,1233,1235,1237,1239,1241,1243,1245,1248,1250,1252,1254,1256,1258,1260,1262,1264],{"class":224,"line":396},[222,1231,1232],{"class":270},"  execute",[222,1234,274],{"class":263},[222,1236,524],{"class":263},[222,1238,442],{"class":441},[222,1240,274],{"class":263},[222,1242,1157],{"class":228},[222,1244,1108],{"class":263},[222,1246,1247],{"class":228}," null",[222,1249,287],{"class":263},[222,1251,1162],{"class":263},[222,1253,639],{"class":441},[222,1255,274],{"class":263},[222,1257,1143],{"class":228},[222,1259,1171],{"class":259},[222,1261,455],{"class":263},[222,1263,458],{"class":424},[222,1265,1178],{"class":228},[222,1267,1268],{"class":224,"line":401},[222,1269,1270],{"class":263},"}\n",[222,1272,1274],{"class":224,"line":1273},10,[222,1275,868],{"emptyLinePlaceholder":867},[222,1277,1279,1281,1284],{"class":224,"line":1278},11,[222,1280,812],{"class":255},[222,1282,1283],{"class":259},"() ",[222,1285,1286],{"class":392},"\u002F\u002F { authorized: true }\n",[222,1288,1290,1292,1294,1296,1299,1301,1304,1306,1308],{"class":224,"line":1289},12,[222,1291,816],{"class":255},[222,1293,260],{"class":259},[222,1295,943],{"class":263},[222,1297,1298],{"class":259}," statusCode?",[222,1300,287],{"class":263},[222,1302,1303],{"class":259}," message? ",[222,1305,404],{"class":263},[222,1307,594],{"class":259},[222,1309,1310],{"class":392},"\u002F\u002F statusCode defaults to 403\n",[208,1312,1314],{"id":1313},"server","Server",[159,1316,1317,1318,1320],{},"The server helpers take the ",[188,1319,527],{}," first and are auto-imported.",[213,1322,1324],{"className":239,"code":1323,"language":241,"meta":218,"style":218},"await authorize(event, editPost, post) \u002F\u002F throws an h3 error when denied (403 by default)\nif (await allows(event, isAdmin)) { \u002F* ... *\u002F }\nif (await denies(event, isAdmin)) { \u002F* ... *\u002F }\nconst user = await resolveAuthorizationUser(event) \u002F\u002F the configured server resolver\n",[188,1325,1326,1348,1374,1397],{"__ignoreMap":218},[222,1327,1328,1331,1333,1336,1338,1340,1342,1345],{"class":224,"line":225},[222,1329,1330],{"class":248},"await",[222,1332,578],{"class":255},[222,1334,1335],{"class":259},"(event",[222,1337,287],{"class":263},[222,1339,587],{"class":259},[222,1341,287],{"class":263},[222,1343,1344],{"class":259}," post) ",[222,1346,1347],{"class":392},"\u002F\u002F throws an h3 error when denied (403 by default)\n",[222,1349,1350,1353,1355,1357,1360,1362,1364,1367,1369,1372],{"class":224,"line":267},[222,1351,1352],{"class":248},"if",[222,1354,524],{"class":259},[222,1356,1330],{"class":248},[222,1358,1359],{"class":255}," allows",[222,1361,1335],{"class":259},[222,1363,287],{"class":263},[222,1365,1366],{"class":259}," isAdmin)) ",[222,1368,943],{"class":263},[222,1370,1371],{"class":392}," \u002F* ... *\u002F",[222,1373,1094],{"class":263},[222,1375,1376,1378,1380,1382,1385,1387,1389,1391,1393,1395],{"class":224,"line":312},[222,1377,1352],{"class":248},[222,1379,524],{"class":259},[222,1381,1330],{"class":248},[222,1383,1384],{"class":255}," denies",[222,1386,1335],{"class":259},[222,1388,287],{"class":263},[222,1390,1366],{"class":259},[222,1392,943],{"class":263},[222,1394,1371],{"class":392},[222,1396,1094],{"class":263},[222,1398,1399,1402,1405,1407,1409,1412,1415],{"class":224,"line":323},[222,1400,1401],{"class":424},"const",[222,1403,1404],{"class":259}," user ",[222,1406,431],{"class":263},[222,1408,546],{"class":248},[222,1410,1411],{"class":255}," resolveAuthorizationUser",[222,1413,1414],{"class":259},"(event) ",[222,1416,1417],{"class":392},"\u002F\u002F the configured server resolver\n",[1419,1420,1422],"h3",{"id":1421},"roles-in-sessions-and-tokens","Roles in sessions and tokens",[159,1424,1425,1426,1432,1433,1435,1436,1439],{},"The default server resolver uses ",[163,1427,1429],{"href":1428},"\u002Fmodules\u002Fauth#protecting-a-route",[188,1430,1431],{},"getAuth",", so route rules and abilities apply to\ncookie sessions, user API tokens and OAuth access tokens alike. A bearer request loads the user from the database, so\n",[188,1434,672],{}," is always current. A cookie session carries the user stored at login, so a role change reaches it after the next\nsign-in (or when your code calls ",[188,1437,1438],{},"setUserSession","). The default app resolver reads the same session user.",[159,1441,1442,1443,191,1446,191,1449,191,1452,1455,1456,1459,1460,1463],{},"Policy hooks of other modules (",[188,1444,1445],{},"events:authorize",[188,1447,1448],{},"forms:authorize",[188,1450,1451],{},"users:admin:authorize",[188,1453,1454],{},"oauth:authorize",")\nreceive ",[188,1457,1458],{},"ctx.userId",". Identify the caller from it, not from the session on ",[188,1461,1462],{},"ctx.event",": the session is empty for bearer\nrequests.",[1419,1465,1467],{"id":1466},"pure-helpers","Pure helpers",[159,1469,1470,1473],{},[188,1471,1472],{},"@frigear-nu\u002Fauthorization\u002Futils"," exports framework-agnostic functions, used by the helpers above and useful in tests:",[213,1475,1477],{"className":239,"code":1476,"language":241,"meta":218,"style":218},"import {\n  check, allows, denies, authorize, \u002F\u002F (ability, user, ...args), no event\n  matchRoute, resolveRule, evaluateRule, normalizeAuthorizeMeta,\n  roleIsHigher, roleIsHigherOrEqual, canManageRole,\n  AuthorizationError, createAuthorizationError, isAbility, ROUTE_RULE_KEYS,\n} from '@frigear-nu\u002Fauthorization\u002Futils'\n\ncheck(ability, user, ...args) \u002F\u002F Promise\u003CAuthorizationResponse>\nmatchRoute('\u002Fadmin\u002F**', '\u002Fadmin\u002Fusers') \u002F\u002F true: '\u002Fx\u002F**' prefix, '*' one segment, or an exact path\n",[188,1478,1479,1486,1508,1530,1547,1569,1583,1587,1609],{"__ignoreMap":218},[222,1480,1481,1484],{"class":224,"line":225},[222,1482,1483],{"class":248},"import",[222,1485,320],{"class":263},[222,1487,1488,1491,1493,1495,1497,1499,1501,1503,1505],{"class":224,"line":267},[222,1489,1490],{"class":259},"  check",[222,1492,287],{"class":263},[222,1494,1359],{"class":259},[222,1496,287],{"class":263},[222,1498,1384],{"class":259},[222,1500,287],{"class":263},[222,1502,578],{"class":259},[222,1504,287],{"class":263},[222,1506,1507],{"class":392}," \u002F\u002F (ability, user, ...args), no event\n",[222,1509,1510,1513,1515,1518,1520,1523,1525,1528],{"class":224,"line":312},[222,1511,1512],{"class":259},"  matchRoute",[222,1514,287],{"class":263},[222,1516,1517],{"class":259}," resolveRule",[222,1519,287],{"class":263},[222,1521,1522],{"class":259}," evaluateRule",[222,1524,287],{"class":263},[222,1526,1527],{"class":259}," normalizeAuthorizeMeta",[222,1529,309],{"class":263},[222,1531,1532,1535,1537,1540,1542,1545],{"class":224,"line":323},[222,1533,1534],{"class":259},"  roleIsHigher",[222,1536,287],{"class":263},[222,1538,1539],{"class":259}," roleIsHigherOrEqual",[222,1541,287],{"class":263},[222,1543,1544],{"class":259}," canManageRole",[222,1546,309],{"class":263},[222,1548,1549,1552,1554,1557,1559,1562,1564,1567],{"class":224,"line":359},[222,1550,1551],{"class":259},"  AuthorizationError",[222,1553,287],{"class":263},[222,1555,1556],{"class":259}," createAuthorizationError",[222,1558,287],{"class":263},[222,1560,1561],{"class":259}," isAbility",[222,1563,287],{"class":263},[222,1565,1566],{"class":259}," ROUTE_RULE_KEYS",[222,1568,309],{"class":263},[222,1570,1571,1573,1576,1578,1580],{"class":224,"line":365},[222,1572,404],{"class":263},[222,1574,1575],{"class":248}," from",[222,1577,290],{"class":263},[222,1579,1472],{"class":232},[222,1581,1582],{"class":263},"'\n",[222,1584,1585],{"class":224,"line":375},[222,1586,868],{"emptyLinePlaceholder":867},[222,1588,1589,1592,1595,1597,1599,1601,1603,1606],{"class":224,"line":396},[222,1590,1591],{"class":255},"check",[222,1593,1594],{"class":259},"(ability",[222,1596,287],{"class":263},[222,1598,461],{"class":259},[222,1600,287],{"class":263},[222,1602,1162],{"class":263},[222,1604,1605],{"class":259},"args) ",[222,1607,1608],{"class":392},"\u002F\u002F Promise\u003CAuthorizationResponse>\n",[222,1610,1611,1614,1616,1618,1620,1622,1624,1626,1629,1631,1633],{"class":224,"line":401},[222,1612,1613],{"class":255},"matchRoute",[222,1615,260],{"class":259},[222,1617,280],{"class":263},[222,1619,329],{"class":232},[222,1621,280],{"class":263},[222,1623,287],{"class":263},[222,1625,290],{"class":263},[222,1627,1628],{"class":232},"\u002Fadmin\u002Fusers",[222,1630,280],{"class":263},[222,1632,594],{"class":259},[222,1634,1635],{"class":392},"\u002F\u002F true: '\u002Fx\u002F**' prefix, '*' one segment, or an exact path\n",[159,1637,1638,1639,1642],{},"For apps with ranked roles, the role helpers take a hierarchy ",[183,1640,1641],{},"from highest to lowest"," rank; unknown roles never\noutrank or equal anything:",[213,1644,1646],{"className":239,"code":1645,"language":241,"meta":218,"style":218},"const roles = ['admin', 'manager', 'member', 'user'] as const\nroleIsHigher(roles, 'manager', 'member') \u002F\u002F true\nroleIsHigherOrEqual(roles, 'member', 'member') \u002F\u002F true\ncanManageRole(roles, 'manager', 'manager') \u002F\u002F false: only strictly lower roles\ncanManageRole(roles, 'admin', 'admin', { equalAllowedFor: ['admin'] }) \u002F\u002F true\n",[188,1647,1648,1699,1728,1755,1783],{"__ignoreMap":218},[222,1649,1650,1652,1655,1657,1659,1661,1663,1665,1667,1669,1672,1674,1676,1678,1681,1683,1685,1687,1689,1691,1693,1696],{"class":224,"line":225},[222,1651,1401],{"class":424},[222,1653,1654],{"class":259}," roles ",[222,1656,431],{"class":263},[222,1658,277],{"class":259},[222,1660,280],{"class":263},[222,1662,348],{"class":232},[222,1664,280],{"class":263},[222,1666,287],{"class":263},[222,1668,290],{"class":263},[222,1670,1671],{"class":232},"manager",[222,1673,280],{"class":263},[222,1675,287],{"class":263},[222,1677,290],{"class":263},[222,1679,1680],{"class":232},"member",[222,1682,280],{"class":263},[222,1684,287],{"class":263},[222,1686,290],{"class":263},[222,1688,442],{"class":232},[222,1690,280],{"class":263},[222,1692,353],{"class":259},[222,1694,1695],{"class":248},"as",[222,1697,1698],{"class":424}," const\n",[222,1700,1701,1704,1707,1709,1711,1713,1715,1717,1719,1721,1723,1725],{"class":224,"line":267},[222,1702,1703],{"class":255},"roleIsHigher",[222,1705,1706],{"class":259},"(roles",[222,1708,287],{"class":263},[222,1710,290],{"class":263},[222,1712,1671],{"class":232},[222,1714,280],{"class":263},[222,1716,287],{"class":263},[222,1718,290],{"class":263},[222,1720,1680],{"class":232},[222,1722,280],{"class":263},[222,1724,594],{"class":259},[222,1726,1727],{"class":392},"\u002F\u002F true\n",[222,1729,1730,1733,1735,1737,1739,1741,1743,1745,1747,1749,1751,1753],{"class":224,"line":312},[222,1731,1732],{"class":255},"roleIsHigherOrEqual",[222,1734,1706],{"class":259},[222,1736,287],{"class":263},[222,1738,290],{"class":263},[222,1740,1680],{"class":232},[222,1742,280],{"class":263},[222,1744,287],{"class":263},[222,1746,290],{"class":263},[222,1748,1680],{"class":232},[222,1750,280],{"class":263},[222,1752,594],{"class":259},[222,1754,1727],{"class":392},[222,1756,1757,1760,1762,1764,1766,1768,1770,1772,1774,1776,1778,1780],{"class":224,"line":323},[222,1758,1759],{"class":255},"canManageRole",[222,1761,1706],{"class":259},[222,1763,287],{"class":263},[222,1765,290],{"class":263},[222,1767,1671],{"class":232},[222,1769,280],{"class":263},[222,1771,287],{"class":263},[222,1773,290],{"class":263},[222,1775,1671],{"class":232},[222,1777,280],{"class":263},[222,1779,594],{"class":259},[222,1781,1782],{"class":392},"\u002F\u002F false: only strictly lower roles\n",[222,1784,1785,1787,1789,1791,1793,1795,1797,1799,1801,1803,1805,1807,1809,1812,1814,1816,1818,1820,1822,1824,1826,1828],{"class":224,"line":359},[222,1786,1759],{"class":255},[222,1788,1706],{"class":259},[222,1790,287],{"class":263},[222,1792,290],{"class":263},[222,1794,348],{"class":232},[222,1796,280],{"class":263},[222,1798,287],{"class":263},[222,1800,290],{"class":263},[222,1802,348],{"class":232},[222,1804,280],{"class":263},[222,1806,287],{"class":263},[222,1808,336],{"class":263},[222,1810,1811],{"class":270}," equalAllowedFor",[222,1813,274],{"class":263},[222,1815,277],{"class":259},[222,1817,280],{"class":263},[222,1819,348],{"class":232},[222,1821,280],{"class":263},[222,1823,353],{"class":259},[222,1825,404],{"class":263},[222,1827,594],{"class":259},[222,1829,1727],{"class":392},[208,1831,1833],{"id":1832},"app","App",[213,1835,1837],{"className":606,"code":1836,"language":608,"meta":218,"style":218},"\u003CCan :ability=\"editPost\" :args=\"[post]\">\n  \u003Cbutton>Edit\u003C\u002Fbutton>\n  \u003Ctemplate #fallback>\u003Cspan>Read only\u003C\u002Fspan>\u003C\u002Ftemplate>\n\u003C\u002FCan>\n\u003CCannot :ability=\"isAdmin\">You are not an admin.\u003C\u002FCannot>\n",[188,1838,1839,1871,1875,1880,1888],{"__ignoreMap":218},[222,1840,1841,1843,1845,1847,1849,1851,1853,1855,1857,1859,1861,1863,1865,1867,1869],{"class":224,"line":225},[222,1842,615],{"class":263},[222,1844,618],{"class":270},[222,1846,621],{"class":263},[222,1848,624],{"class":424},[222,1850,431],{"class":263},[222,1852,629],{"class":263},[222,1854,632],{"class":259},[222,1856,629],{"class":263},[222,1858,621],{"class":263},[222,1860,639],{"class":424},[222,1862,431],{"class":263},[222,1864,629],{"class":263},[222,1866,646],{"class":259},[222,1868,629],{"class":263},[222,1870,651],{"class":263},[222,1872,1873],{"class":224,"line":267},[222,1874,656],{"class":259},[222,1876,1877],{"class":224,"line":312},[222,1878,1879],{"class":259},"  \u003Ctemplate #fallback>\u003Cspan>Read only\u003C\u002Fspan>\u003C\u002Ftemplate>\n",[222,1881,1882,1884,1886],{"class":224,"line":323},[222,1883,661],{"class":263},[222,1885,618],{"class":270},[222,1887,651],{"class":263},[222,1889,1890,1892,1895,1897,1899,1901,1903,1906,1908,1910,1913,1915,1917],{"class":224,"line":359},[222,1891,615],{"class":263},[222,1893,1894],{"class":270},"Cannot",[222,1896,621],{"class":263},[222,1898,624],{"class":424},[222,1900,431],{"class":263},[222,1902,629],{"class":263},[222,1904,1905],{"class":259},"isAdmin",[222,1907,629],{"class":263},[222,1909,1146],{"class":263},[222,1911,1912],{"class":259},"You are not an admin.",[222,1914,661],{"class":263},[222,1916,1894],{"class":270},[222,1918,651],{"class":263},[159,1920,1921,1923,1924,1926],{},[188,1922,618],{}," accepts one ability, or an array that must all pass (then ",[188,1925,639],{}," is an array of argument arrays).",[213,1928,1930],{"className":239,"code":1929,"language":241,"meta":218,"style":218},"const { allows, denies, authorize } = useAuthorization() \u002F\u002F each is also auto-imported on its own\nif (await allows(editPost, post)) { \u002F* ... *\u002F }\n",[188,1931,1932,1961],{"__ignoreMap":218},[222,1933,1934,1936,1938,1940,1942,1944,1946,1949,1951,1953,1956,1958],{"class":224,"line":225},[222,1935,1401],{"class":424},[222,1937,336],{"class":263},[222,1939,1359],{"class":259},[222,1941,287],{"class":263},[222,1943,1384],{"class":259},[222,1945,287],{"class":263},[222,1947,1948],{"class":259}," authorize ",[222,1950,404],{"class":263},[222,1952,543],{"class":263},[222,1954,1955],{"class":255}," useAuthorization",[222,1957,1283],{"class":259},[222,1959,1960],{"class":392},"\u002F\u002F each is also auto-imported on its own\n",[222,1962,1963,1965,1967,1969,1971,1974,1976,1979,1981,1983],{"class":224,"line":267},[222,1964,1352],{"class":248},[222,1966,524],{"class":259},[222,1968,1330],{"class":248},[222,1970,1359],{"class":255},[222,1972,1973],{"class":259},"(editPost",[222,1975,287],{"class":263},[222,1977,1978],{"class":259}," post)) ",[222,1980,943],{"class":263},[222,1982,1371],{"class":392},[222,1984,1094],{"class":263},[667,1986,1987,1988,1991],{},"Client checks only improve the UI. Enforce permissions on the server with ",[188,1989,1990],{},"authorize(event, ...)"," or route rules.",[1419,1993,1995],{"id":1994},"route-rules","Route rules",[159,1997,1998,1999,2006,2007,2009,2010,2013,2014,2017],{},"Rules are keys on Nuxt's native ",[163,2000,2003],{"href":2001,"rel":2002},"https:\u002F\u002Fnuxt.com\u002Fdocs\u002F4.x\u002Fguide\u002Fconcepts\u002Frendering#hybrid-rendering",[167],[188,2004,2005],{},"routeRules",".\nPatterns follow route rules (",[188,2008,329],{}," prefix, ",[188,2011,2012],{},"*"," one segment, or an exact path). Every matching pattern contributes\nand keys of more specific patterns override less specific ones. Pages are gated by a global route middleware (also\nduring SSR); rules for ",[188,2015,2016],{},"\u002Fapi\u002F**"," are also enforced by a Nitro middleware.",[213,2019,2021],{"className":239,"code":2020,"language":241,"meta":218,"style":218},"export default defineNuxtConfig({\n  routeRules: {\n    '\u002Fadmin\u002F**': { roles: ['admin'], ssr: false },\n    '\u002Fapi\u002Fadmin\u002F**': { roles: ['admin'] },\n    '\u002Fadmin\u002Flogin': { authenticated: false }, \u002F\u002F opens a sub-route of a protected pattern\n    '\u002Fbilling': { ability: 'isAdmin' }, \u002F\u002F export name from the abilities file; no arguments\n    '\u002Fmembers\u002F**': { authenticated: true },\n    '\u002Fpricing': { guest: true },\n  },\n})\n",[188,2022,2023,2035,2043,2082,2111,2136,2165,2186,2208,2212],{"__ignoreMap":218},[222,2024,2025,2027,2029,2031,2033],{"class":224,"line":225},[222,2026,249],{"class":248},[222,2028,252],{"class":248},[222,2030,256],{"class":255},[222,2032,260],{"class":259},[222,2034,264],{"class":263},[222,2036,2037,2039,2041],{"class":224,"line":267},[222,2038,315],{"class":270},[222,2040,274],{"class":263},[222,2042,320],{"class":263},[222,2044,2045,2047,2049,2051,2053,2055,2057,2059,2061,2063,2065,2067,2069,2071,2074,2076,2079],{"class":224,"line":312},[222,2046,326],{"class":263},[222,2048,329],{"class":270},[222,2050,280],{"class":263},[222,2052,274],{"class":263},[222,2054,336],{"class":263},[222,2056,339],{"class":270},[222,2058,274],{"class":263},[222,2060,277],{"class":259},[222,2062,280],{"class":263},[222,2064,348],{"class":232},[222,2066,280],{"class":263},[222,2068,306],{"class":259},[222,2070,287],{"class":263},[222,2072,2073],{"class":270}," ssr",[222,2075,274],{"class":263},[222,2077,2078],{"class":994}," false",[222,2080,2081],{"class":263}," },\n",[222,2083,2084,2086,2089,2091,2093,2095,2097,2099,2101,2103,2105,2107,2109],{"class":224,"line":323},[222,2085,326],{"class":263},[222,2087,2088],{"class":270},"\u002Fapi\u002Fadmin\u002F**",[222,2090,280],{"class":263},[222,2092,274],{"class":263},[222,2094,336],{"class":263},[222,2096,339],{"class":270},[222,2098,274],{"class":263},[222,2100,277],{"class":259},[222,2102,280],{"class":263},[222,2104,348],{"class":232},[222,2106,280],{"class":263},[222,2108,353],{"class":259},[222,2110,356],{"class":263},[222,2112,2113,2115,2118,2120,2122,2124,2127,2129,2131,2133],{"class":224,"line":359},[222,2114,326],{"class":263},[222,2116,2117],{"class":270},"\u002Fadmin\u002Flogin",[222,2119,280],{"class":263},[222,2121,274],{"class":263},[222,2123,336],{"class":263},[222,2125,2126],{"class":270}," authenticated",[222,2128,274],{"class":263},[222,2130,2078],{"class":994},[222,2132,998],{"class":263},[222,2134,2135],{"class":392}," \u002F\u002F opens a sub-route of a protected pattern\n",[222,2137,2138,2140,2143,2145,2147,2149,2152,2154,2156,2158,2160,2162],{"class":224,"line":365},[222,2139,326],{"class":263},[222,2141,2142],{"class":270},"\u002Fbilling",[222,2144,280],{"class":263},[222,2146,274],{"class":263},[222,2148,336],{"class":263},[222,2150,2151],{"class":270}," ability",[222,2153,274],{"class":263},[222,2155,290],{"class":263},[222,2157,1905],{"class":232},[222,2159,280],{"class":263},[222,2161,998],{"class":263},[222,2163,2164],{"class":392}," \u002F\u002F export name from the abilities file; no arguments\n",[222,2166,2167,2169,2172,2174,2176,2178,2180,2182,2184],{"class":224,"line":375},[222,2168,326],{"class":263},[222,2170,2171],{"class":270},"\u002Fmembers\u002F**",[222,2173,280],{"class":263},[222,2175,274],{"class":263},[222,2177,336],{"class":263},[222,2179,2126],{"class":270},[222,2181,274],{"class":263},[222,2183,995],{"class":994},[222,2185,2081],{"class":263},[222,2187,2188,2190,2193,2195,2197,2199,2202,2204,2206],{"class":224,"line":396},[222,2189,326],{"class":263},[222,2191,2192],{"class":270},"\u002Fpricing",[222,2194,280],{"class":263},[222,2196,274],{"class":263},[222,2198,336],{"class":263},[222,2200,2201],{"class":270}," guest",[222,2203,274],{"class":263},[222,2205,995],{"class":994},[222,2207,2081],{"class":263},[222,2209,2210],{"class":224,"line":401},[222,2211,362],{"class":263},[222,2213,2214,2216],{"class":224,"line":1273},[222,2215,404],{"class":263},[222,2217,407],{"class":259},[690,2219,2220,2230],{},[693,2221,2222],{},[696,2223,2224,2227],{},[699,2225,2226],{},"Key",[699,2228,2229],{},"Meaning",[712,2231,2232,2249,2258,2268],{},[696,2233,2234,2239],{},[717,2235,2236],{},[188,2237,2238],{},"roles",[717,2240,2241,2242,2245,2246,2248],{},"Allowed ",[188,2243,2244],{},"user.role"," values (",[188,2247,1171],{}," clears an inherited restriction).",[696,2250,2251,2255],{},[717,2252,2253],{},[188,2254,624],{},[717,2256,2257],{},"Name of an exported ability that must allow the user.",[696,2259,2260,2265],{},[717,2261,2262],{},[188,2263,2264],{},"guest",[717,2266,2267],{},"Let unauthenticated visitors reach the checks (they still apply).",[696,2269,2270,2275],{},[717,2271,2272],{},[188,2273,2274],{},"authenticated",[717,2276,2277,2280,2281,2284],{},[188,2278,2279],{},"true"," requires a logged-in user; ",[188,2282,2283],{},"false"," disables authorization for the path.",[159,2286,2287,2288,2290,2291,2294,2295,186,2298,2301],{},"Guests get ",[188,2289,799],{},"; a wrong role or a denied ability gets ",[188,2292,2293],{},"403",". Per page, ",[188,2296,2297],{},"definePageMeta",[183,2299,2300],{},"replaces"," the matching route\nrules:",[213,2303,2305],{"className":606,"code":2304,"language":608,"meta":218,"style":218},"\u003Cscript setup lang=\"ts\">\ndefinePageMeta({ authorize: isAdmin }) \u002F\u002F an ability, an ability name, or { roles, ability, args, guest }\n\u003C\u002Fscript>\n",[188,2306,2307,2330,2351],{"__ignoreMap":218},[222,2308,2309,2311,2314,2317,2320,2322,2324,2326,2328],{"class":224,"line":225},[222,2310,615],{"class":263},[222,2312,2313],{"class":270},"script",[222,2315,2316],{"class":424}," setup",[222,2318,2319],{"class":424}," lang",[222,2321,431],{"class":263},[222,2323,629],{"class":263},[222,2325,241],{"class":232},[222,2327,629],{"class":263},[222,2329,651],{"class":263},[222,2331,2332,2334,2336,2338,2340,2342,2344,2346,2348],{"class":224,"line":267},[222,2333,2297],{"class":255},[222,2335,260],{"class":259},[222,2337,943],{"class":263},[222,2339,578],{"class":270},[222,2341,274],{"class":263},[222,2343,836],{"class":259},[222,2345,404],{"class":263},[222,2347,594],{"class":259},[222,2349,2350],{"class":392},"\u002F\u002F an ability, an ability name, or { roles, ability, args, guest }\n",[222,2352,2353,2355,2357],{"class":224,"line":312},[222,2354,661],{"class":263},[222,2356,2313],{"class":270},[222,2358,651],{"class":263},[213,2360,2362],{"className":239,"code":2361,"language":241,"meta":218,"style":218},"interface RouteRule {\n  roles?: string[]\n  ability?: string | Ability\n  args?: unknown[] \u002F\u002F page meta only\n  guest?: boolean\n  authenticated?: boolean\n}\ntype AuthorizeMeta = string | Ability | RouteRule\n",[188,2363,2364,2373,2385,2399,2415,2424,2433,2437],{"__ignoreMap":218},[222,2365,2366,2368,2371],{"class":224,"line":225},[222,2367,1187],{"class":424},[222,2369,2370],{"class":228}," RouteRule",[222,2372,320],{"class":263},[222,2374,2375,2378,2380,2382],{"class":224,"line":267},[222,2376,2377],{"class":270},"  roles",[222,2379,1079],{"class":263},[222,2381,1091],{"class":228},[222,2383,2384],{"class":259},"[]\n",[222,2386,2387,2390,2392,2394,2396],{"class":224,"line":312},[222,2388,2389],{"class":270},"  ability",[222,2391,1079],{"class":263},[222,2393,1091],{"class":228},[222,2395,1108],{"class":263},[222,2397,2398],{"class":228}," Ability\n",[222,2400,2401,2404,2406,2409,2412],{"class":224,"line":323},[222,2402,2403],{"class":270},"  args",[222,2405,1079],{"class":263},[222,2407,2408],{"class":228}," unknown",[222,2410,2411],{"class":259},"[] ",[222,2413,2414],{"class":392},"\u002F\u002F page meta only\n",[222,2416,2417,2420,2422],{"class":224,"line":359},[222,2418,2419],{"class":270},"  guest",[222,2421,1079],{"class":263},[222,2423,1212],{"class":228},[222,2425,2426,2429,2431],{"class":224,"line":365},[222,2427,2428],{"class":270},"  authenticated",[222,2430,1079],{"class":263},[222,2432,1212],{"class":228},[222,2434,2435],{"class":224,"line":375},[222,2436,1270],{"class":263},[222,2438,2439,2441,2444,2446,2448,2450,2452,2454],{"class":224,"line":396},[222,2440,1056],{"class":424},[222,2442,2443],{"class":228}," AuthorizeMeta",[222,2445,543],{"class":263},[222,2447,1091],{"class":228},[222,2449,1108],{"class":263},[222,2451,1190],{"class":228},[222,2453,1108],{"class":263},[222,2455,2456],{"class":228}," RouteRule\n",[180,2458,2459,2460,813,2462,2465],{},"Nuxt's app-side route rules matcher only keeps a fixed set of keys, so the module collects the authorization keys from\n",[188,2461,2005],{},[188,2463,2464],{},"nitro.routeRules"," at build time. Rules added at runtime are not picked up.",[208,2467,681],{"id":2468},"database",[159,2470,2471,2472,2474,2475,2480,2481,524,2483,2486,2487,2490],{},"The module extends the ",[188,2473,676],{}," table through ",[163,2476,2477],{"href":102},[188,2478,2479],{},"extendDatabaseTable"," with one column:\n",[188,2482,672],{},[188,2484,2485],{},"text",", not null, default ",[188,2488,2489],{},"'user'",").",[2492,2493,2494],"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 .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}",{"title":218,"searchDepth":267,"depth":267,"links":2496},[2497,2498,2499,2500,2504,2507],{"id":210,"depth":267,"text":211},{"id":687,"depth":267,"text":688},{"id":803,"depth":267,"text":804},{"id":1313,"depth":267,"text":1314,"children":2501},[2502,2503],{"id":1421,"depth":312,"text":1422},{"id":1466,"depth":312,"text":1467},{"id":1832,"depth":267,"text":1833,"children":2505},[2506],{"id":1994,"depth":312,"text":1995},{"id":2468,"depth":267,"text":681},"Policy-based authorization (abilities, route rules and \u003CCan>) with a role column on users.","md",null,{},{"title":77,"description":2508},"Rm7cdUvBmoDc8h-succmglgEkNliI8QqfYvpjLLumf8",[2515,2517],{"title":73,"path":74,"stem":75,"description":2516,"children":-1},"Sign-in (password, magic link, OAuth, passkeys), user API tokens and one requireAuth for cookie sessions, tokens and OAuth access tokens, with scopes.",{"title":81,"path":82,"stem":83,"description":2518,"children":-1},"GDPR cookie banner with categories other modules contribute to, consent gating hooks and proof of consent stored on the user.",1792824485286]