[{"data":1,"prerenderedAt":1930},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Fpackages\u002Fauth":176,"\u002Fdocs\u002Fpackages\u002Fauth-surround":1925},[4,21,86,158],{"title":5,"path":6,"stem":7,"children":8,"status":11,"icon":20},"Getting Started","\u002Fdocs\u002Fgetting-started","1.docs\u002F1.getting-started\u002F1.index",[9,12,16],{"title":10,"path":6,"stem":7,"status":11},"Introduction",null,{"title":13,"path":14,"stem":15,"status":11},"Installation","\u002Fdocs\u002Fgetting-started\u002Finstallation","1.docs\u002F1.getting-started\u002F2.installation",{"title":17,"path":18,"stem":19,"status":11},"Quick Start","\u002Fdocs\u002Fgetting-started\u002Fquick-start","1.docs\u002F1.getting-started\u002F3.quick-start",false,{"title":22,"path":23,"stem":24,"children":25,"status":11,"icon":20},"Core Concepts","\u002Fdocs\u002Fcore-concepts","1.docs\u002F2.core-concepts\u002F1.index",[26,28,32,36,46,50,54,58,62,66,70,74,78,82],{"title":27,"path":23,"stem":24,"status":11},"Overview",{"title":29,"path":30,"stem":31,"status":11},"Response","\u002Fdocs\u002Fcore-concepts\u002Fresponse","1.docs\u002F2.core-concepts\u002F10.response",{"title":33,"path":34,"stem":35,"status":11},"Testing","\u002Fdocs\u002Fcore-concepts\u002Ftesting","1.docs\u002F2.core-concepts\u002F12.testing",{"title":37,"path":38,"stem":39,"children":40,"status":11,"icon":20,"defaultOpen":20},"Decorators","\u002Fdocs\u002Fcore-concepts\u002Fdecorators","1.docs\u002F2.core-concepts\u002F13.decorators\u002F1.index",[41,42],{"title":27,"path":38,"stem":39,"status":11},{"title":43,"path":44,"stem":45,"status":11},"Custom","\u002Fdocs\u002Fcore-concepts\u002Fdecorators\u002Fcustom","1.docs\u002F2.core-concepts\u002F13.decorators\u002F2.custom",{"title":47,"path":48,"stem":49,"status":11},"Discovery Service","\u002Fdocs\u002Fcore-concepts\u002Fdiscovery","1.docs\u002F2.core-concepts\u002F14.discovery",{"title":51,"path":52,"stem":53,"status":11},"Application Lifecycle","\u002Fdocs\u002Fcore-concepts\u002Fapp-lifecycle","1.docs\u002F2.core-concepts\u002F15.app-lifecycle",{"title":55,"path":56,"stem":57,"status":11},"Controllers","\u002Fdocs\u002Fcore-concepts\u002Fcontrollers","1.docs\u002F2.core-concepts\u002F2.controllers",{"title":59,"path":60,"stem":61,"status":11},"Routing","\u002Fdocs\u002Fcore-concepts\u002Frouting","1.docs\u002F2.core-concepts\u002F3.routing",{"title":63,"path":64,"stem":65,"status":11},"Providers","\u002Fdocs\u002Fcore-concepts\u002Fproviders","1.docs\u002F2.core-concepts\u002F4.providers",{"title":67,"path":68,"stem":69,"status":11},"Modules","\u002Fdocs\u002Fcore-concepts\u002Fmodules","1.docs\u002F2.core-concepts\u002F5.modules",{"title":71,"path":72,"stem":73,"status":11},"Configuration","\u002Fdocs\u002Fcore-concepts\u002Fconfiguration","1.docs\u002F2.core-concepts\u002F6.configuration",{"title":75,"path":76,"stem":77,"status":11},"Middleware","\u002Fdocs\u002Fcore-concepts\u002Fmiddleware","1.docs\u002F2.core-concepts\u002F7.middleware",{"title":79,"path":80,"stem":81,"status":11},"Guards","\u002Fdocs\u002Fcore-concepts\u002Fguards","1.docs\u002F2.core-concepts\u002F8.guards",{"title":83,"path":84,"stem":85,"status":11},"Exceptions","\u002Fdocs\u002Fcore-concepts\u002Fexceptions","1.docs\u002F2.core-concepts\u002F9.exceptions",{"title":87,"path":88,"stem":89,"children":90,"status":11,"icon":20},"Packages","\u002Fdocs\u002Fpackages","1.docs\u002F3.packages\u002F1.index",[91,92,97,108,112,130,134,138,142,146,150,154],{"title":27,"path":88,"stem":89,"status":11},{"title":93,"path":94,"stem":95,"status":96},"CLI","\u002Fdocs\u002Fpackages\u002Fcli","1.docs\u002F3.packages\u002F10.cli","experimental",{"title":98,"path":99,"stem":100,"children":101,"status":11,"icon":20,"defaultOpen":20},"Events","\u002Fdocs\u002Fpackages\u002Fmessaging","1.docs\u002F3.packages\u002F11.messaging\u002F1.index",[102,104],{"title":27,"path":99,"stem":100,"status":103},"beta",{"title":105,"path":106,"stem":107,"status":96},"Redis","\u002Fdocs\u002Fpackages\u002Fmessaging\u002Fredis","1.docs\u002F3.packages\u002F11.messaging\u002F2.redis",{"title":109,"path":110,"stem":111,"status":103},"Serve Static","\u002Fdocs\u002Fpackages\u002Fserve-static","1.docs\u002F3.packages\u002F12.serve-static",{"title":113,"path":114,"stem":115,"children":116,"status":11,"icon":20,"defaultOpen":20},"Auth","\u002Fdocs\u002Fpackages\u002Fauth","1.docs\u002F3.packages\u002F2.auth\u002F1.index",[117,118,122,126],{"title":27,"path":114,"stem":115,"status":103},{"title":119,"path":120,"stem":121,"status":103},"JWT Provider","\u002Fdocs\u002Fpackages\u002Fauth\u002Fjwt","1.docs\u002F3.packages\u002F2.auth\u002F2.jwt",{"title":123,"path":124,"stem":125,"status":103},"Local Provider","\u002Fdocs\u002Fpackages\u002Fauth\u002Flocal","1.docs\u002F3.packages\u002F2.auth\u002F3.local",{"title":127,"path":128,"stem":129,"status":96},"OAuth2 Provider","\u002Fdocs\u002Fpackages\u002Fauth\u002Foauth2","1.docs\u002F3.packages\u002F2.auth\u002F4.oauth2",{"title":131,"path":132,"stem":133,"status":103},"JWT","\u002Fdocs\u002Fpackages\u002Fjwt","1.docs\u002F3.packages\u002F3.jwt",{"title":135,"path":136,"stem":137,"status":103},"Drizzle","\u002Fdocs\u002Fpackages\u002Fdrizzle","1.docs\u002F3.packages\u002F4.drizzle",{"title":139,"path":140,"stem":141,"status":103},"Papr","\u002Fdocs\u002Fpackages\u002Fpapr","1.docs\u002F3.packages\u002F5.papr",{"title":143,"path":144,"stem":145,"status":103},"Mongoose","\u002Fdocs\u002Fpackages\u002Fmongoose","1.docs\u002F3.packages\u002F6.mongoose",{"title":147,"path":148,"stem":149,"status":103},"Swagger","\u002Fdocs\u002Fpackages\u002Fswagger","1.docs\u002F3.packages\u002F7.swagger",{"title":151,"path":152,"stem":153,"status":103},"Node Server","\u002Fdocs\u002Fpackages\u002Fnode-server","1.docs\u002F3.packages\u002F8.node-server",{"title":155,"path":156,"stem":157,"status":103},"uWS Server","\u002Fdocs\u002Fpackages\u002Fuws-server","1.docs\u002F3.packages\u002F9.uws-server",{"title":159,"path":160,"stem":161,"children":162,"status":11,"icon":20},"Roadmap","\u002Fdocs\u002Froadmap","1.docs\u002F4.roadmap\u002F1.index",[163,164,168,172],{"title":27,"path":160,"stem":161,"status":11},{"title":165,"path":166,"stem":167,"status":11},"Short term (0-3 months)","\u002Fdocs\u002Froadmap\u002Fshort-term","1.docs\u002F4.roadmap\u002F2.short-term",{"title":169,"path":170,"stem":171,"status":11},"Mid term (3-9 months)","\u002Fdocs\u002Froadmap\u002Fmid-term","1.docs\u002F4.roadmap\u002F3.mid-term",{"title":173,"path":174,"stem":175,"status":11},"Long term (9-12+ months)","\u002Fdocs\u002Froadmap\u002Flong-term","1.docs\u002F4.roadmap\u002F4.long-term",{"id":177,"title":27,"body":178,"description":1920,"extension":1921,"meta":1922,"navigation":443,"path":114,"seo":1923,"status":103,"stem":115,"__hash__":1924},"docs\u002F1.docs\u002F3.packages\u002F2.auth\u002F1.index.md",{"type":179,"value":180,"toc":1906},"minimark",[181,189,216,226,230,301,304,315,802,805,851,855,863,1042,1047,1060,1083,1089,1093,1096,1131,1135,1141,1262,1266,1377,1388,1392,1395,1460,1474,1478,1484,1501,1504,1514,1808,1821,1825,1902],[182,183,184,188],"p",{},[185,186,187],"code",{},"@miiajs\u002Fauth"," is a thin layer of primitives for building authentication into MiiaJS applications. It does not ship built-in JWT, OAuth, or password logic - those are application-level concerns. Instead, it gives you three things:",[190,191,192,202,210],"ul",{},[193,194,195,201],"li",{},[196,197,198],"strong",{},[185,199,200],{},"AuthProvider"," - an interface describing a class that authenticates a request.",[193,203,204,209],{},[196,205,206],{},[185,207,208],{},"AuthGuard(...Providers)"," - a guard factory that runs one or more providers.",[193,211,212,215],{},[196,213,214],{},"HTTP utilities"," - token extractors, constant-time string comparison.",[182,217,218,219,225],{},"For JWT signing and verification, see ",[220,221,222],"a",{"href":132},[185,223,224],{},"@miiajs\u002Fjwt",". For end-to-end examples, see the recipes linked below.",[227,228,13],"h2",{"id":229},"installation",[231,232,233,258,273,287],"code-group",{},[234,235,241],"pre",{"className":236,"code":237,"filename":238,"language":239,"meta":240,"style":240},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","bun add @miiajs\u002Fauth\n","bun","bash","",[185,242,243],{"__ignoreMap":240},[244,245,248,251,255],"span",{"class":246,"line":247},"line",1,[244,249,238],{"class":250},"sBMFI",[244,252,254],{"class":253},"sfazB"," add",[244,256,257],{"class":253}," @miiajs\u002Fauth\n",[234,259,262],{"className":236,"code":260,"filename":261,"language":239,"meta":240,"style":240},"npm install @miiajs\u002Fauth\n","npm",[185,263,264],{"__ignoreMap":240},[244,265,266,268,271],{"class":246,"line":247},[244,267,261],{"class":250},[244,269,270],{"class":253}," install",[244,272,257],{"class":253},[234,274,277],{"className":236,"code":275,"filename":276,"language":239,"meta":240,"style":240},"pnpm add @miiajs\u002Fauth\n","pnpm",[185,278,279],{"__ignoreMap":240},[244,280,281,283,285],{"class":246,"line":247},[244,282,276],{"class":250},[244,284,254],{"class":253},[244,286,257],{"class":253},[234,288,291],{"className":236,"code":289,"filename":290,"language":239,"meta":240,"style":240},"yarn add @miiajs\u002Fauth\n","yarn",[185,292,293],{"__ignoreMap":240},[244,294,295,297,299],{"class":246,"line":247},[244,296,290],{"class":250},[244,298,254],{"class":253},[244,300,257],{"class":253},[227,302,200],{"id":303},"authprovider",[182,305,306,307,310,311,314],{},"A provider is a regular ",[185,308,309],{},"@Injectable()"," class that reads a request and returns the authenticated subject - or throws an ",[185,312,313],{},"HttpException",".",[234,316,320],{"className":317,"code":318,"language":319,"meta":240,"style":240},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { Injectable, inject, UnauthorizedException, type RequestContext } from '@miiajs\u002Fcore'\nimport { fromHeader, type AuthProvider } from '@miiajs\u002Fauth'\nimport { JwtService } from '@miiajs\u002Fjwt'\nimport { UsersService } from '.\u002Fusers.service.js'\n\n@Injectable()\nexport class JwtAuth implements AuthProvider {\n  private jwtService = inject(JwtService)\n  private usersService = inject(UsersService)\n  private extract = fromHeader()\n\n  async authenticate(ctx: RequestContext) {\n    const token = this.extract(ctx)\n    if (!token) throw new UnauthorizedException('Missing token')\n\n    const payload = await this.jwtService.verify\u003C{ sub: number }>(token).catch(() => {\n      throw new UnauthorizedException('Invalid token')\n    })\n\n    const user = await this.usersService.findById(payload.sub)\n    if (!user) throw new UnauthorizedException('User not found')\n    return user\n  }\n}\n","typescript",[185,321,322,370,397,417,438,445,458,479,497,512,526,531,557,581,619,624,682,703,711,716,750,781,790,796],{"__ignoreMap":240},[244,323,324,328,332,336,339,342,344,347,349,352,355,358,361,364,367],{"class":246,"line":247},[244,325,327],{"class":326},"s7zQu","import",[244,329,331],{"class":330},"sMK4o"," {",[244,333,335],{"class":334},"sTEyZ"," Injectable",[244,337,338],{"class":330},",",[244,340,341],{"class":334}," inject",[244,343,338],{"class":330},[244,345,346],{"class":334}," UnauthorizedException",[244,348,338],{"class":330},[244,350,351],{"class":326}," type",[244,353,354],{"class":334}," RequestContext",[244,356,357],{"class":330}," }",[244,359,360],{"class":326}," from",[244,362,363],{"class":330}," '",[244,365,366],{"class":253},"@miiajs\u002Fcore",[244,368,369],{"class":330},"'\n",[244,371,373,375,377,380,382,384,387,389,391,393,395],{"class":246,"line":372},2,[244,374,327],{"class":326},[244,376,331],{"class":330},[244,378,379],{"class":334}," fromHeader",[244,381,338],{"class":330},[244,383,351],{"class":326},[244,385,386],{"class":334}," AuthProvider",[244,388,357],{"class":330},[244,390,360],{"class":326},[244,392,363],{"class":330},[244,394,187],{"class":253},[244,396,369],{"class":330},[244,398,400,402,404,407,409,411,413,415],{"class":246,"line":399},3,[244,401,327],{"class":326},[244,403,331],{"class":330},[244,405,406],{"class":334}," JwtService",[244,408,357],{"class":330},[244,410,360],{"class":326},[244,412,363],{"class":330},[244,414,224],{"class":253},[244,416,369],{"class":330},[244,418,420,422,424,427,429,431,433,436],{"class":246,"line":419},4,[244,421,327],{"class":326},[244,423,331],{"class":330},[244,425,426],{"class":334}," UsersService",[244,428,357],{"class":330},[244,430,360],{"class":326},[244,432,363],{"class":330},[244,434,435],{"class":253},".\u002Fusers.service.js",[244,437,369],{"class":330},[244,439,441],{"class":246,"line":440},5,[244,442,444],{"emptyLinePlaceholder":443},true,"\n",[244,446,448,451,455],{"class":246,"line":447},6,[244,449,450],{"class":330},"@",[244,452,454],{"class":453},"s2Zo4","Injectable",[244,456,457],{"class":334},"()\n",[244,459,461,464,468,471,474,476],{"class":246,"line":460},7,[244,462,463],{"class":326},"export",[244,465,467],{"class":466},"spNyl"," class",[244,469,470],{"class":250}," JwtAuth",[244,472,473],{"class":466}," implements",[244,475,386],{"class":250},[244,477,478],{"class":330}," {\n",[244,480,482,485,489,492,494],{"class":246,"line":481},8,[244,483,484],{"class":466},"  private",[244,486,488],{"class":487},"swJcz"," jwtService",[244,490,491],{"class":330}," =",[244,493,341],{"class":487},[244,495,496],{"class":334},"(JwtService)\n",[244,498,500,502,505,507,509],{"class":246,"line":499},9,[244,501,484],{"class":466},[244,503,504],{"class":487}," usersService",[244,506,491],{"class":330},[244,508,341],{"class":487},[244,510,511],{"class":334},"(UsersService)\n",[244,513,515,517,520,522,524],{"class":246,"line":514},10,[244,516,484],{"class":466},[244,518,519],{"class":487}," extract",[244,521,491],{"class":330},[244,523,379],{"class":487},[244,525,457],{"class":334},[244,527,529],{"class":246,"line":528},11,[244,530,444],{"emptyLinePlaceholder":443},[244,532,534,537,540,543,547,550,552,555],{"class":246,"line":533},12,[244,535,536],{"class":466},"  async",[244,538,539],{"class":487}," authenticate",[244,541,542],{"class":330},"(",[244,544,546],{"class":545},"sHdIc","ctx",[244,548,549],{"class":330},":",[244,551,354],{"class":250},[244,553,554],{"class":330},")",[244,556,478],{"class":330},[244,558,560,563,566,568,571,574,576,578],{"class":246,"line":559},13,[244,561,562],{"class":466},"    const",[244,564,565],{"class":334}," token",[244,567,491],{"class":330},[244,569,570],{"class":330}," this.",[244,572,573],{"class":453},"extract",[244,575,542],{"class":487},[244,577,546],{"class":334},[244,579,580],{"class":487},")\n",[244,582,584,587,590,593,596,599,602,605,607,609,612,615,617],{"class":246,"line":583},14,[244,585,586],{"class":326},"    if",[244,588,589],{"class":487}," (",[244,591,592],{"class":330},"!",[244,594,595],{"class":334},"token",[244,597,598],{"class":487},") ",[244,600,601],{"class":326},"throw",[244,603,604],{"class":330}," new",[244,606,346],{"class":453},[244,608,542],{"class":487},[244,610,611],{"class":330},"'",[244,613,614],{"class":253},"Missing token",[244,616,611],{"class":330},[244,618,580],{"class":487},[244,620,622],{"class":246,"line":621},15,[244,623,444],{"emptyLinePlaceholder":443},[244,625,627,629,632,634,637,639,642,644,647,650,653,655,658,661,663,665,667,669,672,674,677,680],{"class":246,"line":626},16,[244,628,562],{"class":466},[244,630,631],{"class":334}," payload",[244,633,491],{"class":330},[244,635,636],{"class":326}," await",[244,638,570],{"class":330},[244,640,641],{"class":334},"jwtService",[244,643,314],{"class":330},[244,645,646],{"class":453},"verify",[244,648,649],{"class":330},"\u003C{",[244,651,652],{"class":487}," sub",[244,654,549],{"class":330},[244,656,657],{"class":250}," number",[244,659,660],{"class":330}," }>",[244,662,542],{"class":487},[244,664,595],{"class":334},[244,666,554],{"class":487},[244,668,314],{"class":330},[244,670,671],{"class":453},"catch",[244,673,542],{"class":487},[244,675,676],{"class":330},"()",[244,678,679],{"class":466}," =>",[244,681,478],{"class":330},[244,683,685,688,690,692,694,696,699,701],{"class":246,"line":684},17,[244,686,687],{"class":326},"      throw",[244,689,604],{"class":330},[244,691,346],{"class":453},[244,693,542],{"class":487},[244,695,611],{"class":330},[244,697,698],{"class":253},"Invalid token",[244,700,611],{"class":330},[244,702,580],{"class":487},[244,704,706,709],{"class":246,"line":705},18,[244,707,708],{"class":330},"    }",[244,710,580],{"class":487},[244,712,714],{"class":246,"line":713},19,[244,715,444],{"emptyLinePlaceholder":443},[244,717,719,721,724,726,728,730,733,735,738,740,743,745,748],{"class":246,"line":718},20,[244,720,562],{"class":466},[244,722,723],{"class":334}," user",[244,725,491],{"class":330},[244,727,636],{"class":326},[244,729,570],{"class":330},[244,731,732],{"class":334},"usersService",[244,734,314],{"class":330},[244,736,737],{"class":453},"findById",[244,739,542],{"class":487},[244,741,742],{"class":334},"payload",[244,744,314],{"class":330},[244,746,747],{"class":334},"sub",[244,749,580],{"class":487},[244,751,753,755,757,759,762,764,766,768,770,772,774,777,779],{"class":246,"line":752},21,[244,754,586],{"class":326},[244,756,589],{"class":487},[244,758,592],{"class":330},[244,760,761],{"class":334},"user",[244,763,598],{"class":487},[244,765,601],{"class":326},[244,767,604],{"class":330},[244,769,346],{"class":453},[244,771,542],{"class":487},[244,773,611],{"class":330},[244,775,776],{"class":253},"User not found",[244,778,611],{"class":330},[244,780,580],{"class":487},[244,782,784,787],{"class":246,"line":783},22,[244,785,786],{"class":326},"    return",[244,788,789],{"class":334}," user\n",[244,791,793],{"class":246,"line":792},23,[244,794,795],{"class":330},"  }\n",[244,797,799],{"class":246,"line":798},24,[244,800,801],{"class":330},"}\n",[182,803,804],{},"Register it like any other provider:",[234,806,808],{"className":317,"code":807,"language":319,"meta":240,"style":240},"@Module({ providers: [JwtAuth, UsersService] })\nclass AuthModule {}\n",[185,809,810,840],{"__ignoreMap":240},[244,811,812,814,817,819,822,825,827,830,832,835,838],{"class":246,"line":247},[244,813,450],{"class":330},[244,815,816],{"class":453},"Module",[244,818,542],{"class":334},[244,820,821],{"class":330},"{",[244,823,824],{"class":487}," providers",[244,826,549],{"class":330},[244,828,829],{"class":334}," [JwtAuth",[244,831,338],{"class":330},[244,833,834],{"class":334}," UsersService] ",[244,836,837],{"class":330},"}",[244,839,580],{"class":334},[244,841,842,845,848],{"class":246,"line":372},[244,843,844],{"class":466},"class",[244,846,847],{"class":250}," AuthModule",[244,849,850],{"class":330}," {}\n",[227,852,854],{"id":853},"authguard","AuthGuard",[182,856,857,859,860,314],{},[185,858,208],{}," builds a guard that tries each provider in order and assigns the first success to ",[185,861,862],{},"ctx.user",[234,864,866],{"className":317,"code":865,"language":319,"meta":240,"style":240},"import { AuthGuard } from '@miiajs\u002Fauth'\nimport { UseGuard, Controller, Get, type RequestContext } from '@miiajs\u002Fcore'\nimport { JwtAuth } from '.\u002Fproviders\u002Fjwt-auth.js'\n\n@Controller('\u002Fusers')\n@UseGuard(AuthGuard(JwtAuth))\nclass UserController {\n  @Get('\u002Fme')\n  me(ctx: RequestContext) {\n    return ctx.user\n  }\n}\n",[185,867,868,887,922,941,945,963,977,986,1005,1022,1034,1038],{"__ignoreMap":240},[244,869,870,872,874,877,879,881,883,885],{"class":246,"line":247},[244,871,327],{"class":326},[244,873,331],{"class":330},[244,875,876],{"class":334}," AuthGuard",[244,878,357],{"class":330},[244,880,360],{"class":326},[244,882,363],{"class":330},[244,884,187],{"class":253},[244,886,369],{"class":330},[244,888,889,891,893,896,898,901,903,906,908,910,912,914,916,918,920],{"class":246,"line":372},[244,890,327],{"class":326},[244,892,331],{"class":330},[244,894,895],{"class":334}," UseGuard",[244,897,338],{"class":330},[244,899,900],{"class":334}," Controller",[244,902,338],{"class":330},[244,904,905],{"class":334}," Get",[244,907,338],{"class":330},[244,909,351],{"class":326},[244,911,354],{"class":334},[244,913,357],{"class":330},[244,915,360],{"class":326},[244,917,363],{"class":330},[244,919,366],{"class":253},[244,921,369],{"class":330},[244,923,924,926,928,930,932,934,936,939],{"class":246,"line":399},[244,925,327],{"class":326},[244,927,331],{"class":330},[244,929,470],{"class":334},[244,931,357],{"class":330},[244,933,360],{"class":326},[244,935,363],{"class":330},[244,937,938],{"class":253},".\u002Fproviders\u002Fjwt-auth.js",[244,940,369],{"class":330},[244,942,943],{"class":246,"line":419},[244,944,444],{"emptyLinePlaceholder":443},[244,946,947,949,952,954,956,959,961],{"class":246,"line":440},[244,948,450],{"class":330},[244,950,951],{"class":453},"Controller",[244,953,542],{"class":334},[244,955,611],{"class":330},[244,957,958],{"class":253},"\u002Fusers",[244,960,611],{"class":330},[244,962,580],{"class":334},[244,964,965,967,970,972,974],{"class":246,"line":447},[244,966,450],{"class":330},[244,968,969],{"class":453},"UseGuard",[244,971,542],{"class":334},[244,973,854],{"class":453},[244,975,976],{"class":334},"(JwtAuth))\n",[244,978,979,981,984],{"class":246,"line":460},[244,980,844],{"class":466},[244,982,983],{"class":250}," UserController",[244,985,478],{"class":330},[244,987,988,991,994,996,998,1001,1003],{"class":246,"line":481},[244,989,990],{"class":330},"  @",[244,992,993],{"class":453},"Get",[244,995,542],{"class":334},[244,997,611],{"class":330},[244,999,1000],{"class":253},"\u002Fme",[244,1002,611],{"class":330},[244,1004,580],{"class":334},[244,1006,1007,1010,1012,1014,1016,1018,1020],{"class":246,"line":499},[244,1008,1009],{"class":487},"  me",[244,1011,542],{"class":330},[244,1013,546],{"class":545},[244,1015,549],{"class":330},[244,1017,354],{"class":250},[244,1019,554],{"class":330},[244,1021,478],{"class":330},[244,1023,1024,1026,1029,1031],{"class":246,"line":514},[244,1025,786],{"class":326},[244,1027,1028],{"class":334}," ctx",[244,1030,314],{"class":330},[244,1032,1033],{"class":334},"user\n",[244,1035,1036],{"class":246,"line":528},[244,1037,795],{"class":330},[244,1039,1040],{"class":246,"line":533},[244,1041,801],{"class":330},[1043,1044,1046],"h3",{"id":1045},"multi-provider-or","Multi-provider (OR)",[182,1048,1049,1050,1052,1053,1055,1056,1059],{},"Pass more than one provider class for fall-back authentication. The first provider that succeeds wins, and its result becomes ",[185,1051,862],{},". If a provider throws an ",[185,1054,313],{},", the guard moves on to the next one. Any other error (TypeError, ReferenceError, etc.) is treated as a programming bug and propagates immediately - it is ",[196,1057,1058],{},"never"," silently swallowed.",[234,1061,1063],{"className":317,"code":1062,"language":319,"meta":240,"style":240},"@UseGuard(AuthGuard(JwtAuth, ApiKeyAuth))\n",[185,1064,1065],{"__ignoreMap":240},[244,1066,1067,1069,1071,1073,1075,1078,1080],{"class":246,"line":247},[244,1068,450],{"class":330},[244,1070,969],{"class":453},[244,1072,542],{"class":334},[244,1074,854],{"class":453},[244,1076,1077],{"class":334},"(JwtAuth",[244,1079,338],{"class":330},[244,1081,1082],{"class":334}," ApiKeyAuth))\n",[182,1084,1085,1086,1088],{},"If every provider throws an ",[185,1087,313],{},", the last error is rethrown.",[1043,1090,1092],{"id":1091},"and-semantics","AND semantics",[182,1094,1095],{},"Stack guards on top of each other to require multiple checks:",[234,1097,1099],{"className":317,"code":1098,"language":319,"meta":240,"style":240},"@UseGuard(AuthGuard(JwtAuth), Roles('admin'))\n",[185,1100,1101],{"__ignoreMap":240},[244,1102,1103,1105,1107,1109,1111,1114,1116,1119,1121,1123,1126,1128],{"class":246,"line":247},[244,1104,450],{"class":330},[244,1106,969],{"class":453},[244,1108,542],{"class":334},[244,1110,854],{"class":453},[244,1112,1113],{"class":334},"(JwtAuth)",[244,1115,338],{"class":330},[244,1117,1118],{"class":453}," Roles",[244,1120,542],{"class":334},[244,1122,611],{"class":330},[244,1124,1125],{"class":253},"admin",[244,1127,611],{"class":330},[244,1129,1130],{"class":334},"))\n",[1043,1132,1134],{"id":1133},"skipping","Skipping",[182,1136,1137,1140],{},[185,1138,1139],{},"@SkipGuard(AuthGuard)"," (referencing the factory itself) removes the auth guard from a specific route at compile time - zero runtime cost.",[234,1142,1144],{"className":317,"code":1143,"language":319,"meta":240,"style":240},"import { SkipGuard } from '@miiajs\u002Fcore'\n\n@Controller('\u002Fposts')\n@UseGuard(AuthGuard(JwtAuth))\nclass PostController {\n  @Get('\u002F')\n  @SkipGuard(AuthGuard)\n  list() {\n    return [] \u002F\u002F public\n  }\n}\n",[185,1145,1146,1165,1169,1186,1198,1207,1224,1234,1243,1254,1258],{"__ignoreMap":240},[244,1147,1148,1150,1152,1155,1157,1159,1161,1163],{"class":246,"line":247},[244,1149,327],{"class":326},[244,1151,331],{"class":330},[244,1153,1154],{"class":334}," SkipGuard",[244,1156,357],{"class":330},[244,1158,360],{"class":326},[244,1160,363],{"class":330},[244,1162,366],{"class":253},[244,1164,369],{"class":330},[244,1166,1167],{"class":246,"line":372},[244,1168,444],{"emptyLinePlaceholder":443},[244,1170,1171,1173,1175,1177,1179,1182,1184],{"class":246,"line":399},[244,1172,450],{"class":330},[244,1174,951],{"class":453},[244,1176,542],{"class":334},[244,1178,611],{"class":330},[244,1180,1181],{"class":253},"\u002Fposts",[244,1183,611],{"class":330},[244,1185,580],{"class":334},[244,1187,1188,1190,1192,1194,1196],{"class":246,"line":419},[244,1189,450],{"class":330},[244,1191,969],{"class":453},[244,1193,542],{"class":334},[244,1195,854],{"class":453},[244,1197,976],{"class":334},[244,1199,1200,1202,1205],{"class":246,"line":440},[244,1201,844],{"class":466},[244,1203,1204],{"class":250}," PostController",[244,1206,478],{"class":330},[244,1208,1209,1211,1213,1215,1217,1220,1222],{"class":246,"line":447},[244,1210,990],{"class":330},[244,1212,993],{"class":453},[244,1214,542],{"class":334},[244,1216,611],{"class":330},[244,1218,1219],{"class":253},"\u002F",[244,1221,611],{"class":330},[244,1223,580],{"class":334},[244,1225,1226,1228,1231],{"class":246,"line":460},[244,1227,990],{"class":330},[244,1229,1230],{"class":453},"SkipGuard",[244,1232,1233],{"class":334},"(AuthGuard)\n",[244,1235,1236,1239,1241],{"class":246,"line":481},[244,1237,1238],{"class":487},"  list",[244,1240,676],{"class":330},[244,1242,478],{"class":330},[244,1244,1245,1247,1250],{"class":246,"line":499},[244,1246,786],{"class":326},[244,1248,1249],{"class":487}," [] ",[244,1251,1253],{"class":1252},"sHwdD","\u002F\u002F public\n",[244,1255,1256],{"class":246,"line":514},[244,1257,795],{"class":330},[244,1259,1260],{"class":246,"line":528},[244,1261,801],{"class":330},[227,1263,1265],{"id":1264},"token-extractors","Token extractors",[234,1267,1269],{"className":317,"code":1268,"language":319,"meta":240,"style":240},"import { fromHeader, fromCookie, fromQuery } from '@miiajs\u002Fauth'\n\nfromHeader()                  \u002F\u002F Authorization: Bearer \u003Ctoken>\nfromHeader('x-auth', '')      \u002F\u002F X-Auth: \u003Ctoken>\nfromCookie('access_token')    \u002F\u002F Cookie: access_token=\u003C...>\nfromQuery('token')            \u002F\u002F ?token=\u003C...>\n",[185,1270,1271,1299,1303,1314,1338,1358],{"__ignoreMap":240},[244,1272,1273,1275,1277,1279,1281,1284,1286,1289,1291,1293,1295,1297],{"class":246,"line":247},[244,1274,327],{"class":326},[244,1276,331],{"class":330},[244,1278,379],{"class":334},[244,1280,338],{"class":330},[244,1282,1283],{"class":334}," fromCookie",[244,1285,338],{"class":330},[244,1287,1288],{"class":334}," fromQuery",[244,1290,357],{"class":330},[244,1292,360],{"class":326},[244,1294,363],{"class":330},[244,1296,187],{"class":253},[244,1298,369],{"class":330},[244,1300,1301],{"class":246,"line":372},[244,1302,444],{"emptyLinePlaceholder":443},[244,1304,1305,1308,1311],{"class":246,"line":399},[244,1306,1307],{"class":453},"fromHeader",[244,1309,1310],{"class":334},"()                  ",[244,1312,1313],{"class":1252},"\u002F\u002F Authorization: Bearer \u003Ctoken>\n",[244,1315,1316,1318,1320,1322,1325,1327,1329,1332,1335],{"class":246,"line":419},[244,1317,1307],{"class":453},[244,1319,542],{"class":334},[244,1321,611],{"class":330},[244,1323,1324],{"class":253},"x-auth",[244,1326,611],{"class":330},[244,1328,338],{"class":330},[244,1330,1331],{"class":330}," ''",[244,1333,1334],{"class":334},")      ",[244,1336,1337],{"class":1252},"\u002F\u002F X-Auth: \u003Ctoken>\n",[244,1339,1340,1343,1345,1347,1350,1352,1355],{"class":246,"line":440},[244,1341,1342],{"class":453},"fromCookie",[244,1344,542],{"class":334},[244,1346,611],{"class":330},[244,1348,1349],{"class":253},"access_token",[244,1351,611],{"class":330},[244,1353,1354],{"class":334},")    ",[244,1356,1357],{"class":1252},"\u002F\u002F Cookie: access_token=\u003C...>\n",[244,1359,1360,1363,1365,1367,1369,1371,1374],{"class":246,"line":447},[244,1361,1362],{"class":453},"fromQuery",[244,1364,542],{"class":334},[244,1366,611],{"class":330},[244,1368,595],{"class":253},[244,1370,611],{"class":330},[244,1372,1373],{"class":334},")            ",[244,1375,1376],{"class":1252},"\u002F\u002F ?token=\u003C...>\n",[182,1378,1379,1380,1383,1384,1387],{},"Each extractor returns ",[185,1381,1382],{},"(ctx: RequestContext) => string | null",". Use them inside your provider's ",[185,1385,1386],{},"authenticate()"," method - they are not coupled to JWT, you can use them for API keys, session cookies, anything header- or cookie-based.",[227,1389,1391],{"id":1390},"timingsafeequal","timingSafeEqual",[182,1393,1394],{},"Constant-time string comparison - use it when comparing pre-hashed tokens, HMAC digests, or API keys to avoid leaking length\u002Fposition information through timing side channels.",[234,1396,1398],{"className":317,"code":1397,"language":319,"meta":240,"style":240},"import { timingSafeEqual } from '@miiajs\u002Fauth'\n\nif (!timingSafeEqual(providedHash, expectedHash)) {\n  throw new UnauthorizedException()\n}\n",[185,1399,1400,1419,1423,1445,1456],{"__ignoreMap":240},[244,1401,1402,1404,1406,1409,1411,1413,1415,1417],{"class":246,"line":247},[244,1403,327],{"class":326},[244,1405,331],{"class":330},[244,1407,1408],{"class":334}," timingSafeEqual",[244,1410,357],{"class":330},[244,1412,360],{"class":326},[244,1414,363],{"class":330},[244,1416,187],{"class":253},[244,1418,369],{"class":330},[244,1420,1421],{"class":246,"line":372},[244,1422,444],{"emptyLinePlaceholder":443},[244,1424,1425,1428,1430,1432,1434,1437,1439,1442],{"class":246,"line":399},[244,1426,1427],{"class":326},"if",[244,1429,589],{"class":334},[244,1431,592],{"class":330},[244,1433,1391],{"class":453},[244,1435,1436],{"class":334},"(providedHash",[244,1438,338],{"class":330},[244,1440,1441],{"class":334}," expectedHash)) ",[244,1443,1444],{"class":330},"{\n",[244,1446,1447,1450,1452,1454],{"class":246,"line":419},[244,1448,1449],{"class":326},"  throw",[244,1451,604],{"class":330},[244,1453,346],{"class":453},[244,1455,457],{"class":487},[244,1457,1458],{"class":246,"line":440},[244,1459,801],{"class":330},[182,1461,1462,1465,1466,1469,1470,1473],{},[196,1463,1464],{},"Not for plaintext passwords"," - use ",[185,1467,1468],{},"bcrypt.compare"," or ",[185,1471,1472],{},"argon2.verify"," instead.",[227,1475,1477],{"id":1476},"recipes","Recipes",[182,1479,1480,1481,1483],{},"Complete worked examples - standalone, copy-pasteable patterns. Each recipe demonstrates the ",[185,1482,200],{}," interface for a different credential source:",[190,1485,1486,1491,1496],{},[193,1487,1488,1490],{},[220,1489,119],{"href":120}," - verify Bearer tokens",[193,1492,1493,1495],{},[220,1494,123],{"href":124}," - username\u002Fpassword login with argon2",[193,1497,1498,1500],{},[220,1499,127],{"href":128}," - GitHub login flow",[227,1502,33],{"id":1503},"testing",[182,1505,1506,1507,1509,1510,1513],{},"Override the ",[185,1508,200],{}," at the DI level with ",[185,1511,1512],{},"TestApp.override()",". Guards run unchanged - they resolve whichever provider you wired up, so a stub provider is enough to drive any auth path:",[234,1515,1517],{"className":317,"code":1516,"language":319,"meta":240,"style":240},"import { Injectable } from '@miiajs\u002Fcore'\nimport { TestApp } from '@miiajs\u002Fcore\u002Ftesting'\nimport type { AuthProvider } from '@miiajs\u002Fauth'\nimport { JwtProvider } from '.\u002Fjwt.provider.js'\n\n@Injectable()\nclass StubProvider implements AuthProvider {\n  authenticate() {\n    return { id: 1, email: 'alice@example.com' }\n  }\n}\n\nconst app = await TestApp.create(AppModule)\n  .override(JwtProvider, StubProvider)\n  .compile()\n\nconst res = await app.request('GET', '\u002Fme')\nexpect(res.status).toBe(200)\n\nawait app.close()\n",[185,1518,1519,1537,1557,1577,1597,1601,1609,1622,1631,1663,1667,1671,1675,1698,1714,1723,1727,1765,1790,1794],{"__ignoreMap":240},[244,1520,1521,1523,1525,1527,1529,1531,1533,1535],{"class":246,"line":247},[244,1522,327],{"class":326},[244,1524,331],{"class":330},[244,1526,335],{"class":334},[244,1528,357],{"class":330},[244,1530,360],{"class":326},[244,1532,363],{"class":330},[244,1534,366],{"class":253},[244,1536,369],{"class":330},[244,1538,1539,1541,1543,1546,1548,1550,1552,1555],{"class":246,"line":372},[244,1540,327],{"class":326},[244,1542,331],{"class":330},[244,1544,1545],{"class":334}," TestApp",[244,1547,357],{"class":330},[244,1549,360],{"class":326},[244,1551,363],{"class":330},[244,1553,1554],{"class":253},"@miiajs\u002Fcore\u002Ftesting",[244,1556,369],{"class":330},[244,1558,1559,1561,1563,1565,1567,1569,1571,1573,1575],{"class":246,"line":399},[244,1560,327],{"class":326},[244,1562,351],{"class":326},[244,1564,331],{"class":330},[244,1566,386],{"class":334},[244,1568,357],{"class":330},[244,1570,360],{"class":326},[244,1572,363],{"class":330},[244,1574,187],{"class":253},[244,1576,369],{"class":330},[244,1578,1579,1581,1583,1586,1588,1590,1592,1595],{"class":246,"line":419},[244,1580,327],{"class":326},[244,1582,331],{"class":330},[244,1584,1585],{"class":334}," JwtProvider",[244,1587,357],{"class":330},[244,1589,360],{"class":326},[244,1591,363],{"class":330},[244,1593,1594],{"class":253},".\u002Fjwt.provider.js",[244,1596,369],{"class":330},[244,1598,1599],{"class":246,"line":440},[244,1600,444],{"emptyLinePlaceholder":443},[244,1602,1603,1605,1607],{"class":246,"line":447},[244,1604,450],{"class":330},[244,1606,454],{"class":453},[244,1608,457],{"class":334},[244,1610,1611,1613,1616,1618,1620],{"class":246,"line":460},[244,1612,844],{"class":466},[244,1614,1615],{"class":250}," StubProvider",[244,1617,473],{"class":466},[244,1619,386],{"class":250},[244,1621,478],{"class":330},[244,1623,1624,1627,1629],{"class":246,"line":481},[244,1625,1626],{"class":487},"  authenticate",[244,1628,676],{"class":330},[244,1630,478],{"class":330},[244,1632,1633,1635,1637,1640,1642,1646,1648,1651,1653,1655,1658,1660],{"class":246,"line":499},[244,1634,786],{"class":326},[244,1636,331],{"class":330},[244,1638,1639],{"class":487}," id",[244,1641,549],{"class":330},[244,1643,1645],{"class":1644},"sbssI"," 1",[244,1647,338],{"class":330},[244,1649,1650],{"class":487}," email",[244,1652,549],{"class":330},[244,1654,363],{"class":330},[244,1656,1657],{"class":253},"alice@example.com",[244,1659,611],{"class":330},[244,1661,1662],{"class":330}," }\n",[244,1664,1665],{"class":246,"line":514},[244,1666,795],{"class":330},[244,1668,1669],{"class":246,"line":528},[244,1670,801],{"class":330},[244,1672,1673],{"class":246,"line":533},[244,1674,444],{"emptyLinePlaceholder":443},[244,1676,1677,1680,1683,1686,1688,1690,1692,1695],{"class":246,"line":559},[244,1678,1679],{"class":466},"const",[244,1681,1682],{"class":334}," app ",[244,1684,1685],{"class":330},"=",[244,1687,636],{"class":326},[244,1689,1545],{"class":334},[244,1691,314],{"class":330},[244,1693,1694],{"class":453},"create",[244,1696,1697],{"class":334},"(AppModule)\n",[244,1699,1700,1703,1706,1709,1711],{"class":246,"line":583},[244,1701,1702],{"class":330},"  .",[244,1704,1705],{"class":453},"override",[244,1707,1708],{"class":334},"(JwtProvider",[244,1710,338],{"class":330},[244,1712,1713],{"class":334}," StubProvider)\n",[244,1715,1716,1718,1721],{"class":246,"line":621},[244,1717,1702],{"class":330},[244,1719,1720],{"class":453},"compile",[244,1722,457],{"class":334},[244,1724,1725],{"class":246,"line":626},[244,1726,444],{"emptyLinePlaceholder":443},[244,1728,1729,1731,1734,1736,1738,1741,1743,1746,1748,1750,1753,1755,1757,1759,1761,1763],{"class":246,"line":684},[244,1730,1679],{"class":466},[244,1732,1733],{"class":334}," res ",[244,1735,1685],{"class":330},[244,1737,636],{"class":326},[244,1739,1740],{"class":334}," app",[244,1742,314],{"class":330},[244,1744,1745],{"class":453},"request",[244,1747,542],{"class":334},[244,1749,611],{"class":330},[244,1751,1752],{"class":253},"GET",[244,1754,611],{"class":330},[244,1756,338],{"class":330},[244,1758,363],{"class":330},[244,1760,1000],{"class":253},[244,1762,611],{"class":330},[244,1764,580],{"class":334},[244,1766,1767,1770,1773,1775,1778,1780,1783,1785,1788],{"class":246,"line":705},[244,1768,1769],{"class":453},"expect",[244,1771,1772],{"class":334},"(res",[244,1774,314],{"class":330},[244,1776,1777],{"class":334},"status)",[244,1779,314],{"class":330},[244,1781,1782],{"class":453},"toBe",[244,1784,542],{"class":334},[244,1786,1787],{"class":1644},"200",[244,1789,580],{"class":334},[244,1791,1792],{"class":246,"line":713},[244,1793,444],{"emptyLinePlaceholder":443},[244,1795,1796,1799,1801,1803,1806],{"class":246,"line":718},[244,1797,1798],{"class":326},"await",[244,1800,1740],{"class":334},[244,1802,314],{"class":330},[244,1804,1805],{"class":453},"close",[244,1807,457],{"class":334},[182,1809,1810,1811,1469,1814,1817,1818,1820],{},"To exercise 401\u002F403 paths, override with a provider that throws ",[185,1812,1813],{},"UnauthorizedException",[185,1815,1816],{},"ForbiddenException"," from ",[185,1819,366],{},". The guard rethrows them unchanged.",[227,1822,1824],{"id":1823},"exports","Exports",[234,1826,1828],{"className":317,"code":1827,"language":319,"meta":240,"style":240},"import {\n  AuthGuard,\n  fromHeader,\n  fromCookie,\n  fromQuery,\n  timingSafeEqual,\n  type AuthProvider,\n  type TokenExtractor,\n} from '@miiajs\u002Fauth'\n",[185,1829,1830,1836,1844,1851,1858,1865,1872,1881,1890],{"__ignoreMap":240},[244,1831,1832,1834],{"class":246,"line":247},[244,1833,327],{"class":326},[244,1835,478],{"class":330},[244,1837,1838,1841],{"class":246,"line":372},[244,1839,1840],{"class":334},"  AuthGuard",[244,1842,1843],{"class":330},",\n",[244,1845,1846,1849],{"class":246,"line":399},[244,1847,1848],{"class":334},"  fromHeader",[244,1850,1843],{"class":330},[244,1852,1853,1856],{"class":246,"line":419},[244,1854,1855],{"class":334},"  fromCookie",[244,1857,1843],{"class":330},[244,1859,1860,1863],{"class":246,"line":440},[244,1861,1862],{"class":334},"  fromQuery",[244,1864,1843],{"class":330},[244,1866,1867,1870],{"class":246,"line":447},[244,1868,1869],{"class":334},"  timingSafeEqual",[244,1871,1843],{"class":330},[244,1873,1874,1877,1879],{"class":246,"line":460},[244,1875,1876],{"class":326},"  type",[244,1878,386],{"class":334},[244,1880,1843],{"class":330},[244,1882,1883,1885,1888],{"class":246,"line":481},[244,1884,1876],{"class":326},[244,1886,1887],{"class":334}," TokenExtractor",[244,1889,1843],{"class":330},[244,1891,1892,1894,1896,1898,1900],{"class":246,"line":499},[244,1893,837],{"class":330},[244,1895,360],{"class":326},[244,1897,363],{"class":330},[244,1899,187],{"class":253},[244,1901,369],{"class":330},[1903,1904,1905],"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 .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}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 .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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}",{"title":240,"searchDepth":372,"depth":372,"links":1907},[1908,1909,1910,1915,1916,1917,1918,1919],{"id":229,"depth":372,"text":13},{"id":303,"depth":372,"text":200},{"id":853,"depth":372,"text":854,"children":1911},[1912,1913,1914],{"id":1045,"depth":399,"text":1046},{"id":1091,"depth":399,"text":1092},{"id":1133,"depth":399,"text":1134},{"id":1264,"depth":372,"text":1265},{"id":1390,"depth":372,"text":1391},{"id":1476,"depth":372,"text":1477},{"id":1503,"depth":372,"text":33},{"id":1823,"depth":372,"text":1824},"Lightweight auth primitives - AuthProvider interface, AuthGuard factory, HTTP token extractors, timing-safe utilities.","md",{},{"title":27,"description":1920},"CCZC_jrW9Q116MpnQZnUJ752sTVtJoQH1WQKbaygWj8",[1926,1928],{"title":109,"path":110,"stem":111,"description":1927,"children":-1},"Static file server with Range, conditional GET, charset, dotfile guard, and SPA fallback.",{"title":119,"path":120,"stem":121,"description":1929,"children":-1},"A 15-line Injectable class that authenticates Bearer tokens with JwtService and loads the user.",1778575276504]