[{"data":1,"prerenderedAt":1536},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Fpackages\u002Fauth\u002Fjwt":176,"\u002Fdocs\u002Fpackages\u002Fauth\u002Fjwt-surround":1531},[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":119,"body":178,"description":1526,"extension":1527,"meta":1528,"navigation":377,"path":120,"seo":1529,"status":103,"stem":121,"__hash__":1530},"docs\u002F1.docs\u002F3.packages\u002F2.auth\u002F2.jwt.md",{"type":179,"value":180,"toc":1512},"minimark",[181,186,203,207,227,743,746,750,753,849,852,1039,1045,1065,1145,1158,1162,1167,1203,1207,1237,1241,1270,1273,1397,1401,1469,1473,1508],[182,183,185],"h2",{"id":184},"problem","Problem",[187,188,189,190,194,195,198,199,202],"p",{},"You want every protected route to have a fully populated ",[191,192,193],"code",{},"ctx.user",", derived from a JWT in the ",[191,196,197],{},"Authorization: Bearer \u003Ctoken>"," header. If the token is missing, expired, or invalid, the request should be rejected with ",[191,200,201],{},"401",".",[182,204,206],{"id":205},"solution","Solution",[187,208,209,210,213,214,220,221,226],{},"A single ",[191,211,212],{},"@Injectable()"," provider that combines ",[215,216,217],"a",{"href":132},[191,218,219],{},"JwtService"," with the ",[215,222,223],{"href":114},[191,224,225],{},"fromHeader"," extractor.",[228,229,234],"pre",{"className":230,"code":231,"language":232,"meta":233,"style":233},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F src\u002Fauth\u002Fproviders\u002Fjwt-auth.provider.ts\nimport { Injectable, inject, UnauthorizedException, type RequestContext } from '@miiajs\u002Fcore'\nimport { fromHeader, type AuthProvider } from '@miiajs\u002Fauth'\nimport { JwtService, type JwtPayload } from '@miiajs\u002Fjwt'\nimport { UsersService } from '..\u002F..\u002Fusers\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    let payload: JwtPayload\n    try {\n      payload = await this.jwtService.verify(token)\n    } catch {\n      throw new UnauthorizedException('Invalid token')\n    }\n\n    const user = await this.usersService.findById(payload.sub as number)\n    if (!user) throw new UnauthorizedException('User no longer exists')\n    return user\n  }\n}\n","typescript","",[191,235,236,245,295,323,351,372,379,392,414,432,447,461,466,492,516,554,559,573,581,608,619,640,646,651,691,722,731,737],{"__ignoreMap":233},[237,238,241],"span",{"class":239,"line":240},"line",1,[237,242,244],{"class":243},"sHwdD","\u002F\u002F src\u002Fauth\u002Fproviders\u002Fjwt-auth.provider.ts\n",[237,246,248,252,256,260,263,266,268,271,273,276,279,282,285,288,292],{"class":239,"line":247},2,[237,249,251],{"class":250},"s7zQu","import",[237,253,255],{"class":254},"sMK4o"," {",[237,257,259],{"class":258},"sTEyZ"," Injectable",[237,261,262],{"class":254},",",[237,264,265],{"class":258}," inject",[237,267,262],{"class":254},[237,269,270],{"class":258}," UnauthorizedException",[237,272,262],{"class":254},[237,274,275],{"class":250}," type",[237,277,278],{"class":258}," RequestContext",[237,280,281],{"class":254}," }",[237,283,284],{"class":250}," from",[237,286,287],{"class":254}," '",[237,289,291],{"class":290},"sfazB","@miiajs\u002Fcore",[237,293,294],{"class":254},"'\n",[237,296,298,300,302,305,307,309,312,314,316,318,321],{"class":239,"line":297},3,[237,299,251],{"class":250},[237,301,255],{"class":254},[237,303,304],{"class":258}," fromHeader",[237,306,262],{"class":254},[237,308,275],{"class":250},[237,310,311],{"class":258}," AuthProvider",[237,313,281],{"class":254},[237,315,284],{"class":250},[237,317,287],{"class":254},[237,319,320],{"class":290},"@miiajs\u002Fauth",[237,322,294],{"class":254},[237,324,326,328,330,333,335,337,340,342,344,346,349],{"class":239,"line":325},4,[237,327,251],{"class":250},[237,329,255],{"class":254},[237,331,332],{"class":258}," JwtService",[237,334,262],{"class":254},[237,336,275],{"class":250},[237,338,339],{"class":258}," JwtPayload",[237,341,281],{"class":254},[237,343,284],{"class":250},[237,345,287],{"class":254},[237,347,348],{"class":290},"@miiajs\u002Fjwt",[237,350,294],{"class":254},[237,352,354,356,358,361,363,365,367,370],{"class":239,"line":353},5,[237,355,251],{"class":250},[237,357,255],{"class":254},[237,359,360],{"class":258}," UsersService",[237,362,281],{"class":254},[237,364,284],{"class":250},[237,366,287],{"class":254},[237,368,369],{"class":290},"..\u002F..\u002Fusers\u002Fusers.service.js",[237,371,294],{"class":254},[237,373,375],{"class":239,"line":374},6,[237,376,378],{"emptyLinePlaceholder":377},true,"\n",[237,380,382,385,389],{"class":239,"line":381},7,[237,383,384],{"class":254},"@",[237,386,388],{"class":387},"s2Zo4","Injectable",[237,390,391],{"class":258},"()\n",[237,393,395,398,402,406,409,411],{"class":239,"line":394},8,[237,396,397],{"class":250},"export",[237,399,401],{"class":400},"spNyl"," class",[237,403,405],{"class":404},"sBMFI"," JwtAuth",[237,407,408],{"class":400}," implements",[237,410,311],{"class":404},[237,412,413],{"class":254}," {\n",[237,415,417,420,424,427,429],{"class":239,"line":416},9,[237,418,419],{"class":400},"  private",[237,421,423],{"class":422},"swJcz"," jwtService",[237,425,426],{"class":254}," =",[237,428,265],{"class":422},[237,430,431],{"class":258},"(JwtService)\n",[237,433,435,437,440,442,444],{"class":239,"line":434},10,[237,436,419],{"class":400},[237,438,439],{"class":422}," usersService",[237,441,426],{"class":254},[237,443,265],{"class":422},[237,445,446],{"class":258},"(UsersService)\n",[237,448,450,452,455,457,459],{"class":239,"line":449},11,[237,451,419],{"class":400},[237,453,454],{"class":422}," extract",[237,456,426],{"class":254},[237,458,304],{"class":422},[237,460,391],{"class":258},[237,462,464],{"class":239,"line":463},12,[237,465,378],{"emptyLinePlaceholder":377},[237,467,469,472,475,478,482,485,487,490],{"class":239,"line":468},13,[237,470,471],{"class":400},"  async",[237,473,474],{"class":422}," authenticate",[237,476,477],{"class":254},"(",[237,479,481],{"class":480},"sHdIc","ctx",[237,483,484],{"class":254},":",[237,486,278],{"class":404},[237,488,489],{"class":254},")",[237,491,413],{"class":254},[237,493,495,498,501,503,506,509,511,513],{"class":239,"line":494},14,[237,496,497],{"class":400},"    const",[237,499,500],{"class":258}," token",[237,502,426],{"class":254},[237,504,505],{"class":254}," this.",[237,507,508],{"class":387},"extract",[237,510,477],{"class":422},[237,512,481],{"class":258},[237,514,515],{"class":422},")\n",[237,517,519,522,525,528,531,534,537,540,542,544,547,550,552],{"class":239,"line":518},15,[237,520,521],{"class":250},"    if",[237,523,524],{"class":422}," (",[237,526,527],{"class":254},"!",[237,529,530],{"class":258},"token",[237,532,533],{"class":422},") ",[237,535,536],{"class":250},"throw",[237,538,539],{"class":254}," new",[237,541,270],{"class":387},[237,543,477],{"class":422},[237,545,546],{"class":254},"'",[237,548,549],{"class":290},"Missing token",[237,551,546],{"class":254},[237,553,515],{"class":422},[237,555,557],{"class":239,"line":556},16,[237,558,378],{"emptyLinePlaceholder":377},[237,560,562,565,568,570],{"class":239,"line":561},17,[237,563,564],{"class":400},"    let",[237,566,567],{"class":258}," payload",[237,569,484],{"class":254},[237,571,572],{"class":404}," JwtPayload\n",[237,574,576,579],{"class":239,"line":575},18,[237,577,578],{"class":250},"    try",[237,580,413],{"class":254},[237,582,584,587,589,592,594,597,599,602,604,606],{"class":239,"line":583},19,[237,585,586],{"class":258},"      payload",[237,588,426],{"class":254},[237,590,591],{"class":250}," await",[237,593,505],{"class":254},[237,595,596],{"class":258},"jwtService",[237,598,202],{"class":254},[237,600,601],{"class":387},"verify",[237,603,477],{"class":422},[237,605,530],{"class":258},[237,607,515],{"class":422},[237,609,611,614,617],{"class":239,"line":610},20,[237,612,613],{"class":254},"    }",[237,615,616],{"class":250}," catch",[237,618,413],{"class":254},[237,620,622,625,627,629,631,633,636,638],{"class":239,"line":621},21,[237,623,624],{"class":250},"      throw",[237,626,539],{"class":254},[237,628,270],{"class":387},[237,630,477],{"class":422},[237,632,546],{"class":254},[237,634,635],{"class":290},"Invalid token",[237,637,546],{"class":254},[237,639,515],{"class":422},[237,641,643],{"class":239,"line":642},22,[237,644,645],{"class":254},"    }\n",[237,647,649],{"class":239,"line":648},23,[237,650,378],{"emptyLinePlaceholder":377},[237,652,654,656,659,661,663,665,668,670,673,675,678,680,683,686,689],{"class":239,"line":653},24,[237,655,497],{"class":400},[237,657,658],{"class":258}," user",[237,660,426],{"class":254},[237,662,591],{"class":250},[237,664,505],{"class":254},[237,666,667],{"class":258},"usersService",[237,669,202],{"class":254},[237,671,672],{"class":387},"findById",[237,674,477],{"class":422},[237,676,677],{"class":258},"payload",[237,679,202],{"class":254},[237,681,682],{"class":258},"sub",[237,684,685],{"class":250}," as",[237,687,688],{"class":404}," number",[237,690,515],{"class":422},[237,692,694,696,698,700,703,705,707,709,711,713,715,718,720],{"class":239,"line":693},25,[237,695,521],{"class":250},[237,697,524],{"class":422},[237,699,527],{"class":254},[237,701,702],{"class":258},"user",[237,704,533],{"class":422},[237,706,536],{"class":250},[237,708,539],{"class":254},[237,710,270],{"class":387},[237,712,477],{"class":422},[237,714,546],{"class":254},[237,716,717],{"class":290},"User no longer exists",[237,719,546],{"class":254},[237,721,515],{"class":422},[237,723,725,728],{"class":239,"line":724},26,[237,726,727],{"class":250},"    return",[237,729,730],{"class":258}," user\n",[237,732,734],{"class":239,"line":733},27,[237,735,736],{"class":254},"  }\n",[237,738,740],{"class":239,"line":739},28,[237,741,742],{"class":254},"}\n",[187,744,745],{},"That's it. Fifteen lines of logic, fully typed, fully injectable.",[182,747,749],{"id":748},"wire-it-up","Wire it up",[187,751,752],{},"Register the provider in your auth module:",[228,754,756],{"className":230,"code":755,"language":232,"meta":233,"style":233},"\u002F\u002F src\u002Fauth\u002Fauth.module.ts\nimport { Module } from '@miiajs\u002Fcore'\nimport { JwtAuth } from '.\u002Fproviders\u002Fjwt-auth.provider.js'\n\n@Module({\n  providers: [JwtAuth],\n})\nexport class AuthModule {}\n",[191,757,758,763,782,801,805,817,830,837],{"__ignoreMap":233},[237,759,760],{"class":239,"line":240},[237,761,762],{"class":243},"\u002F\u002F src\u002Fauth\u002Fauth.module.ts\n",[237,764,765,767,769,772,774,776,778,780],{"class":239,"line":247},[237,766,251],{"class":250},[237,768,255],{"class":254},[237,770,771],{"class":258}," Module",[237,773,281],{"class":254},[237,775,284],{"class":250},[237,777,287],{"class":254},[237,779,291],{"class":290},[237,781,294],{"class":254},[237,783,784,786,788,790,792,794,796,799],{"class":239,"line":297},[237,785,251],{"class":250},[237,787,255],{"class":254},[237,789,405],{"class":258},[237,791,281],{"class":254},[237,793,284],{"class":250},[237,795,287],{"class":254},[237,797,798],{"class":290},".\u002Fproviders\u002Fjwt-auth.provider.js",[237,800,294],{"class":254},[237,802,803],{"class":239,"line":325},[237,804,378],{"emptyLinePlaceholder":377},[237,806,807,809,812,814],{"class":239,"line":353},[237,808,384],{"class":254},[237,810,811],{"class":387},"Module",[237,813,477],{"class":258},[237,815,816],{"class":254},"{\n",[237,818,819,822,824,827],{"class":239,"line":374},[237,820,821],{"class":422},"  providers",[237,823,484],{"class":254},[237,825,826],{"class":258}," [JwtAuth]",[237,828,829],{"class":254},",\n",[237,831,832,835],{"class":239,"line":381},[237,833,834],{"class":254},"}",[237,836,515],{"class":258},[237,838,839,841,843,846],{"class":239,"line":394},[237,840,397],{"class":250},[237,842,401],{"class":400},[237,844,845],{"class":404}," AuthModule",[237,847,848],{"class":254}," {}\n",[187,850,851],{},"Apply the guard to any controller or route:",[228,853,855],{"className":230,"code":854,"language":232,"meta":233,"style":233},"\u002F\u002F src\u002Fusers\u002Fusers.controller.ts\nimport { Controller, Get, UseGuard, type RequestContext } from '@miiajs\u002Fcore'\nimport { AuthGuard } from '@miiajs\u002Fauth'\nimport { JwtAuth } from '..\u002Fauth\u002Fproviders\u002Fjwt-auth.provider.js'\n\n@Controller('\u002Fusers')\n@UseGuard(AuthGuard(JwtAuth))\nexport class UsersController {\n  @Get('\u002Fme')\n  me(ctx: RequestContext) {\n    return ctx.user\n  }\n}\n",[191,856,857,862,897,916,935,939,957,972,983,1002,1019,1031,1035],{"__ignoreMap":233},[237,858,859],{"class":239,"line":240},[237,860,861],{"class":243},"\u002F\u002F src\u002Fusers\u002Fusers.controller.ts\n",[237,863,864,866,868,871,873,876,878,881,883,885,887,889,891,893,895],{"class":239,"line":247},[237,865,251],{"class":250},[237,867,255],{"class":254},[237,869,870],{"class":258}," Controller",[237,872,262],{"class":254},[237,874,875],{"class":258}," Get",[237,877,262],{"class":254},[237,879,880],{"class":258}," UseGuard",[237,882,262],{"class":254},[237,884,275],{"class":250},[237,886,278],{"class":258},[237,888,281],{"class":254},[237,890,284],{"class":250},[237,892,287],{"class":254},[237,894,291],{"class":290},[237,896,294],{"class":254},[237,898,899,901,903,906,908,910,912,914],{"class":239,"line":297},[237,900,251],{"class":250},[237,902,255],{"class":254},[237,904,905],{"class":258}," AuthGuard",[237,907,281],{"class":254},[237,909,284],{"class":250},[237,911,287],{"class":254},[237,913,320],{"class":290},[237,915,294],{"class":254},[237,917,918,920,922,924,926,928,930,933],{"class":239,"line":325},[237,919,251],{"class":250},[237,921,255],{"class":254},[237,923,405],{"class":258},[237,925,281],{"class":254},[237,927,284],{"class":250},[237,929,287],{"class":254},[237,931,932],{"class":290},"..\u002Fauth\u002Fproviders\u002Fjwt-auth.provider.js",[237,934,294],{"class":254},[237,936,937],{"class":239,"line":353},[237,938,378],{"emptyLinePlaceholder":377},[237,940,941,943,946,948,950,953,955],{"class":239,"line":374},[237,942,384],{"class":254},[237,944,945],{"class":387},"Controller",[237,947,477],{"class":258},[237,949,546],{"class":254},[237,951,952],{"class":290},"\u002Fusers",[237,954,546],{"class":254},[237,956,515],{"class":258},[237,958,959,961,964,966,969],{"class":239,"line":381},[237,960,384],{"class":254},[237,962,963],{"class":387},"UseGuard",[237,965,477],{"class":258},[237,967,968],{"class":387},"AuthGuard",[237,970,971],{"class":258},"(JwtAuth))\n",[237,973,974,976,978,981],{"class":239,"line":394},[237,975,397],{"class":250},[237,977,401],{"class":400},[237,979,980],{"class":404}," UsersController",[237,982,413],{"class":254},[237,984,985,988,991,993,995,998,1000],{"class":239,"line":416},[237,986,987],{"class":254},"  @",[237,989,990],{"class":387},"Get",[237,992,477],{"class":258},[237,994,546],{"class":254},[237,996,997],{"class":290},"\u002Fme",[237,999,546],{"class":254},[237,1001,515],{"class":258},[237,1003,1004,1007,1009,1011,1013,1015,1017],{"class":239,"line":434},[237,1005,1006],{"class":422},"  me",[237,1008,477],{"class":254},[237,1010,481],{"class":480},[237,1012,484],{"class":254},[237,1014,278],{"class":404},[237,1016,489],{"class":254},[237,1018,413],{"class":254},[237,1020,1021,1023,1026,1028],{"class":239,"line":449},[237,1022,727],{"class":250},[237,1024,1025],{"class":258}," ctx",[237,1027,202],{"class":254},[237,1029,1030],{"class":258},"user\n",[237,1032,1033],{"class":239,"line":463},[237,1034,736],{"class":254},[237,1036,1037],{"class":239,"line":468},[237,1038,742],{"class":254},[182,1040,1042,1043],{"id":1041},"declaring-ctxuser","Declaring ",[191,1044,193],{},[187,1046,1047,1049,1050,1054,1055,1057,1058,1061,1062,1064],{},[191,1048,291],{}," intentionally does ",[1051,1052,1053],"strong",{},"not"," pre-declare ",[191,1056,702],{}," on ",[191,1059,1060],{},"RequestContext"," - the package has no opinion on what an authenticated subject looks like. Before you can touch ",[191,1063,193],{}," anywhere, augment the interface once in your project with the type your provider returns:",[228,1066,1068],{"className":230,"code":1067,"language":232,"meta":233,"style":233},"\u002F\u002F src\u002Ftypes\u002Fauth.d.ts\nimport type { User } from '..\u002Fusers\u002Fusers.schema.js'\n\ndeclare module '@miiajs\u002Fcore' {\n  interface RequestContext {\n    user?: User\n  }\n}\n",[191,1069,1070,1075,1097,1101,1117,1126,1137,1141],{"__ignoreMap":233},[237,1071,1072],{"class":239,"line":240},[237,1073,1074],{"class":243},"\u002F\u002F src\u002Ftypes\u002Fauth.d.ts\n",[237,1076,1077,1079,1081,1083,1086,1088,1090,1092,1095],{"class":239,"line":247},[237,1078,251],{"class":250},[237,1080,275],{"class":250},[237,1082,255],{"class":254},[237,1084,1085],{"class":258}," User",[237,1087,281],{"class":254},[237,1089,284],{"class":250},[237,1091,287],{"class":254},[237,1093,1094],{"class":290},"..\u002Fusers\u002Fusers.schema.js",[237,1096,294],{"class":254},[237,1098,1099],{"class":239,"line":297},[237,1100,378],{"emptyLinePlaceholder":377},[237,1102,1103,1106,1109,1111,1113,1115],{"class":239,"line":325},[237,1104,1105],{"class":400},"declare",[237,1107,1108],{"class":400}," module",[237,1110,287],{"class":254},[237,1112,291],{"class":290},[237,1114,546],{"class":254},[237,1116,413],{"class":254},[237,1118,1119,1122,1124],{"class":239,"line":353},[237,1120,1121],{"class":400},"  interface",[237,1123,278],{"class":404},[237,1125,413],{"class":254},[237,1127,1128,1131,1134],{"class":239,"line":374},[237,1129,1130],{"class":422},"    user",[237,1132,1133],{"class":254},"?:",[237,1135,1136],{"class":404}," User\n",[237,1138,1139],{"class":239,"line":381},[237,1140,736],{"class":254},[237,1142,1143],{"class":239,"line":394},[237,1144,742],{"class":254},[187,1146,1147,1148,1150,1151,1154,1155,202],{},"Now ",[191,1149,193],{}," is ",[191,1152,1153],{},"User | undefined"," everywhere - and inside guarded routes you can safely treat it as ",[191,1156,1157],{},"User",[182,1159,1161],{"id":1160},"variations","Variations",[1163,1164,1166],"h3",{"id":1165},"custom-header","Custom header",[228,1168,1170],{"className":230,"code":1169,"language":232,"meta":233,"style":233},"private extract = fromHeader('x-auth-token', '')\n\u002F\u002F reads X-Auth-Token: \u003Craw token>\n",[191,1171,1172,1198],{"__ignoreMap":233},[237,1173,1174,1177,1180,1182,1184,1186,1189,1191,1193,1196],{"class":239,"line":240},[237,1175,1176],{"class":258},"private extract ",[237,1178,1179],{"class":254},"=",[237,1181,304],{"class":387},[237,1183,477],{"class":258},[237,1185,546],{"class":254},[237,1187,1188],{"class":290},"x-auth-token",[237,1190,546],{"class":254},[237,1192,262],{"class":254},[237,1194,1195],{"class":254}," ''",[237,1197,515],{"class":258},[237,1199,1200],{"class":239,"line":247},[237,1201,1202],{"class":243},"\u002F\u002F reads X-Auth-Token: \u003Craw token>\n",[1163,1204,1206],{"id":1205},"cookie-based","Cookie-based",[228,1208,1210],{"className":230,"code":1209,"language":232,"meta":233,"style":233},"private extract = fromCookie('access_token')\n\u002F\u002F reads Cookie: access_token=\u003Ctoken>\n",[191,1211,1212,1232],{"__ignoreMap":233},[237,1213,1214,1216,1218,1221,1223,1225,1228,1230],{"class":239,"line":240},[237,1215,1176],{"class":258},[237,1217,1179],{"class":254},[237,1219,1220],{"class":387}," fromCookie",[237,1222,477],{"class":258},[237,1224,546],{"class":254},[237,1226,1227],{"class":290},"access_token",[237,1229,546],{"class":254},[237,1231,515],{"class":258},[237,1233,1234],{"class":239,"line":247},[237,1235,1236],{"class":243},"\u002F\u002F reads Cookie: access_token=\u003Ctoken>\n",[1163,1238,1240],{"id":1239},"query-string-download-links","Query string (download links)",[228,1242,1244],{"className":230,"code":1243,"language":232,"meta":233,"style":233},"private extract = fromQuery('token')\n\u002F\u002F reads ?token=\u003Cjwt>\n",[191,1245,1246,1265],{"__ignoreMap":233},[237,1247,1248,1250,1252,1255,1257,1259,1261,1263],{"class":239,"line":240},[237,1249,1176],{"class":258},[237,1251,1179],{"class":254},[237,1253,1254],{"class":387}," fromQuery",[237,1256,477],{"class":258},[237,1258,546],{"class":254},[237,1260,530],{"class":290},[237,1262,546],{"class":254},[237,1264,515],{"class":258},[237,1266,1267],{"class":239,"line":247},[237,1268,1269],{"class":243},"\u002F\u002F reads ?token=\u003Cjwt>\n",[187,1271,1272],{},"You can also accept multiple sources with a fallback:",[228,1274,1276],{"className":230,"code":1275,"language":232,"meta":233,"style":233},"private extractHeader = fromHeader()\nprivate extractQuery = fromQuery('token')\n\nasync authenticate(ctx: RequestContext) {\n  const token = this.extractHeader(ctx) ?? this.extractQuery(ctx)\n  if (!token) throw new UnauthorizedException('Missing token')\n  \u002F\u002F ...\n}\n",[191,1277,1278,1289,1308,1312,1325,1359,1388,1393],{"__ignoreMap":233},[237,1279,1280,1283,1285,1287],{"class":239,"line":240},[237,1281,1282],{"class":258},"private extractHeader ",[237,1284,1179],{"class":254},[237,1286,304],{"class":387},[237,1288,391],{"class":258},[237,1290,1291,1294,1296,1298,1300,1302,1304,1306],{"class":239,"line":247},[237,1292,1293],{"class":258},"private extractQuery ",[237,1295,1179],{"class":254},[237,1297,1254],{"class":387},[237,1299,477],{"class":258},[237,1301,546],{"class":254},[237,1303,530],{"class":290},[237,1305,546],{"class":254},[237,1307,515],{"class":258},[237,1309,1310],{"class":239,"line":297},[237,1311,378],{"emptyLinePlaceholder":377},[237,1313,1314,1317,1320,1323],{"class":239,"line":325},[237,1315,1316],{"class":258},"async ",[237,1318,1319],{"class":387},"authenticate",[237,1321,1322],{"class":258},"(ctx: RequestContext) ",[237,1324,816],{"class":254},[237,1326,1327,1330,1332,1334,1336,1339,1341,1343,1345,1348,1350,1353,1355,1357],{"class":239,"line":353},[237,1328,1329],{"class":400},"  const",[237,1331,500],{"class":258},[237,1333,426],{"class":254},[237,1335,505],{"class":254},[237,1337,1338],{"class":387},"extractHeader",[237,1340,477],{"class":422},[237,1342,481],{"class":258},[237,1344,533],{"class":422},[237,1346,1347],{"class":254},"??",[237,1349,505],{"class":254},[237,1351,1352],{"class":387},"extractQuery",[237,1354,477],{"class":422},[237,1356,481],{"class":258},[237,1358,515],{"class":422},[237,1360,1361,1364,1366,1368,1370,1372,1374,1376,1378,1380,1382,1384,1386],{"class":239,"line":374},[237,1362,1363],{"class":250},"  if",[237,1365,524],{"class":422},[237,1367,527],{"class":254},[237,1369,530],{"class":258},[237,1371,533],{"class":422},[237,1373,536],{"class":250},[237,1375,539],{"class":254},[237,1377,270],{"class":387},[237,1379,477],{"class":422},[237,1381,546],{"class":254},[237,1383,549],{"class":290},[237,1385,546],{"class":254},[237,1387,515],{"class":422},[237,1389,1390],{"class":239,"line":381},[237,1391,1392],{"class":243},"  \u002F\u002F ...\n",[237,1394,1395],{"class":239,"line":394},[237,1396,742],{"class":254},[182,1398,1400],{"id":1399},"security-notes","Security notes",[1402,1403,1404,1432,1442,1448],"ul",{},[1405,1406,1407,1410,1411,1414,1415,1418,1419,1422,1423,1426,1427,1431],"li",{},[1051,1408,1409],{},"Pin the signing algorithm."," Configure ",[191,1412,1413],{},"JwtModule"," with a fixed ",[191,1416,1417],{},"alg"," and use ",[191,1420,1421],{},"allowedAlgorithms"," on verify - otherwise an attacker can forge tokens by swapping to a weaker algorithm (or to ",[191,1424,1425],{},"none","). See ",[215,1428,1429],{"href":132},[191,1430,348],{}," for the options.",[1405,1433,1434,1437,1438,1441],{},[1051,1435,1436],{},"Short-lived tokens."," Sign with ",[191,1439,1440],{},"expiresIn"," set to minutes-to-hours, not days. Use a refresh-token flow or server-side session for longer-lived access.",[1405,1443,1444,1447],{},[1051,1445,1446],{},"Revocation."," JWTs are stateless, so logout is best-effort - you need either short TTLs (the common answer) or a denylist checked on verify.",[1405,1449,1450,1453,1454,1457,1458,1461,1462,1461,1465,1468],{},[1051,1451,1452],{},"Clock skew."," ",[191,1455,1456],{},"jose"," tolerates small ",[191,1459,1460],{},"iat","\u002F",[191,1463,1464],{},"nbf",[191,1466,1467],{},"exp"," skew by default; be explicit about it if your verifiers and signers run on different machines.",[182,1470,1472],{"id":1471},"see-also","See also",[1402,1474,1475,1489,1498,1503],{},[1405,1476,1477,1481,1482,1485,1486,1488],{},[215,1478,1479],{"href":114},[191,1480,320],{}," - ",[191,1483,1484],{},"AuthProvider"," interface, ",[191,1487,968],{},", extractors",[1405,1490,1491,1481,1495,1497],{},[215,1492,1493],{"href":132},[191,1494,348],{},[191,1496,219],{}," configuration and API",[1405,1499,1500,1502],{},[215,1501,123],{"href":124}," - username\u002Fpassword login",[1405,1504,1505,1507],{},[215,1506,127],{"href":128}," - GitHub login",[1509,1510,1511],"style",{},"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 .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .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 .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);}",{"title":233,"searchDepth":247,"depth":247,"links":1513},[1514,1515,1516,1517,1519,1524,1525],{"id":184,"depth":247,"text":185},{"id":205,"depth":247,"text":206},{"id":748,"depth":247,"text":749},{"id":1041,"depth":247,"text":1518},"Declaring ctx.user",{"id":1160,"depth":247,"text":1161,"children":1520},[1521,1522,1523],{"id":1165,"depth":297,"text":1166},{"id":1205,"depth":297,"text":1206},{"id":1239,"depth":297,"text":1240},{"id":1399,"depth":247,"text":1400},{"id":1471,"depth":247,"text":1472},"A 15-line Injectable class that authenticates Bearer tokens with JwtService and loads the user.","md",{},{"title":119,"description":1526},"Wgkr_u8H5duQgnMOIaItIV07RM92Rt0Ulm84eHjwa9M",[1532,1534],{"title":27,"path":114,"stem":115,"description":1533,"children":-1},"Lightweight auth primitives - AuthProvider interface, AuthGuard factory, HTTP token extractors, timing-safe utilities.",{"title":123,"path":124,"stem":125,"description":1535,"children":-1},"Username\u002Fpassword login as an AuthProvider - argon2 password verification, Zod body validation inside the provider.",1778575278206]