[{"data":1,"prerenderedAt":2879},["ShallowReactive",2],{"navigation_docs":3,"-auth-jwt-providers":172,"-auth-jwt-providers-surround":2874},[4,26,67,98,124,140,161],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":25},"Getting Started","i-lucide-rocket","\u002Fgetting-started","1.getting-started",[10,15,20],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Installation","\u002Fgetting-started\u002Finstallation","1.getting-started\u002F2.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":24},"Quick Start","\u002Fgetting-started\u002Fquick-start","1.getting-started\u002F3.quick-start","i-lucide-play",false,{"title":27,"icon":28,"path":29,"stem":30,"children":31,"page":25},"Core","i-lucide-box","\u002Fcore","2.core",[32,37,42,47,52,57,62],{"title":33,"path":34,"stem":35,"icon":36},"Routing","\u002Fcore\u002Frouting","2.core\u002F1.routing","i-lucide-route",{"title":38,"path":39,"stem":40,"icon":41},"Handlers","\u002Fcore\u002Fhandlers","2.core\u002F2.handlers","i-lucide-braces",{"title":43,"path":44,"stem":45,"icon":46},"Request Binding","\u002Fcore\u002Frequest-binding","2.core\u002F3.request-binding","i-lucide-tags",{"title":48,"path":49,"stem":50,"icon":51},"Validation","\u002Fcore\u002Fvalidation","2.core\u002F4.validation","i-lucide-check-check",{"title":53,"path":54,"stem":55,"icon":56},"Context","\u002Fcore\u002Fcontext","2.core\u002F5.context","i-lucide-file-input",{"title":58,"path":59,"stem":60,"icon":61},"Errors","\u002Fcore\u002Ferrors","2.core\u002F6.errors","i-lucide-triangle-alert",{"title":63,"path":64,"stem":65,"icon":66},"Middleware","\u002Fcore\u002Fmiddleware","2.core\u002F7.middleware","i-lucide-layers",{"title":68,"icon":69,"path":70,"stem":71,"children":72,"page":25},"Auth","i-lucide-shield-check","\u002Fauth","3.auth",[73,78,83,88,93],{"title":74,"path":75,"stem":76,"icon":77},"Overview","\u002Fauth\u002Foverview","3.auth\u002F1.overview","i-lucide-shield",{"title":79,"path":80,"stem":81,"icon":82},"Auth Rules","\u002Fauth\u002Fauth-rules","3.auth\u002F2.auth-rules","i-lucide-lock",{"title":84,"path":85,"stem":86,"icon":87},"JWT Providers","\u002Fauth\u002Fjwt-providers","3.auth\u002F3.jwt-providers","i-lucide-key",{"title":89,"path":90,"stem":91,"icon":92},"Roles & Permissions","\u002Fauth\u002Froles-and-permissions","3.auth\u002F4.roles-and-permissions","i-lucide-users",{"title":94,"path":95,"stem":96,"icon":97},"Audit Logging","\u002Fauth\u002Faudit-logging","3.auth\u002F5.audit-logging","i-lucide-scroll-text",{"title":99,"icon":100,"path":101,"stem":102,"children":103,"page":25},"GoTrue","i-lucide-key-round","\u002Fgotrue","4.gotrue",[104,109,114,119],{"title":105,"path":106,"stem":107,"icon":108},"Proxy","\u002Fgotrue\u002Fproxy","4.gotrue\u002F1.proxy","i-lucide-shuffle",{"title":110,"path":111,"stem":112,"icon":113},"Endpoints","\u002Fgotrue\u002Fendpoints","4.gotrue\u002F2.endpoints","i-lucide-list",{"title":115,"path":116,"stem":117,"icon":118},"Client IP & Rate Limits","\u002Fgotrue\u002Fclient-ip-and-rate-limits","4.gotrue\u002F3.client-ip-and-rate-limits","i-lucide-network",{"title":120,"path":121,"stem":122,"icon":123},"Deployment","\u002Fgotrue\u002Fdeployment","4.gotrue\u002F4.deployment","i-lucide-server",{"title":125,"icon":126,"path":127,"stem":128,"children":129,"page":25},"API Docs","i-lucide-file-text","\u002Fapi-docs","5.api-docs",[130,135],{"title":131,"path":132,"stem":133,"icon":134},"OpenAPI","\u002Fapi-docs\u002Fopenapi","5.api-docs\u002F1.openapi","i-lucide-file-json",{"title":136,"path":137,"stem":138,"icon":139},"Scalar UI","\u002Fapi-docs\u002Fscalar","5.api-docs\u002F2.scalar","i-lucide-book-open-text",{"title":141,"icon":142,"path":143,"stem":144,"children":145,"page":25},"Guides","i-lucide-compass","\u002Fguides","6.guides",[146,151,156],{"title":147,"path":148,"stem":149,"icon":150},"Testing","\u002Fguides\u002Ftesting","6.guides\u002F1.testing","i-lucide-flask-conical",{"title":152,"path":153,"stem":154,"icon":155},"Performance","\u002Fguides\u002Fperformance","6.guides\u002F2.performance","i-lucide-gauge",{"title":157,"path":158,"stem":159,"icon":160},"Releasing","\u002Fguides\u002Freleasing","6.guides\u002F3.releasing","i-lucide-tag",{"title":162,"icon":163,"path":164,"stem":165,"children":166,"page":25},"Reference","i-lucide-code","\u002Freference","7.reference",[167],{"title":168,"path":169,"stem":170,"icon":171},"API Reference","\u002Freference\u002Fapi-reference","7.reference\u002F1.api-reference","i-lucide-list-tree",{"id":173,"title":84,"body":174,"description":2867,"extension":2868,"links":2869,"meta":2870,"navigation":2871,"path":85,"seo":2872,"stem":86,"__hash__":2873},"docs\u002F3.auth\u002F3.jwt-providers.md",{"type":175,"value":176,"toc":2858},"minimark",[177,186,286,292,295,450,475,479,485,578,581,1020,1029,1037,1041,1044,1123,1157,1274,1284,1314,1319,1338,1348,1352,1355,1991,1995,2008,2479,2482,2671,2675,2682,2772,2814,2835,2839,2854],[178,179,180,181,185],"p",{},"The app takes an ",[182,183,184],"code",{},"ezz.AuthProvider",". JWT support is one layer below that, behind a smaller interface:",[187,188,193],"pre",{"className":189,"code":190,"language":191,"meta":192,"style":192},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","type JWTProvider interface {\n    ValidateToken(token string) (*Claims, error)\n    GenerateToken(claims *Claims) (string, error)\n}\n","go","",[182,194,195,214,250,280],{"__ignoreMap":192},[196,197,200,204,208,211],"span",{"class":198,"line":199},"line",1,[196,201,203],{"class":202},"sMK4o","type",[196,205,207],{"class":206},"sBMFI"," JWTProvider",[196,209,210],{"class":202}," interface",[196,212,213],{"class":202}," {\n",[196,215,217,221,224,228,232,235,238,241,244,247],{"class":198,"line":216},2,[196,218,220],{"class":219},"s2Zo4","    ValidateToken",[196,222,223],{"class":202},"(",[196,225,227],{"class":226},"sHdIc","token",[196,229,231],{"class":230},"spNyl"," string",[196,233,234],{"class":202},")",[196,236,237],{"class":202}," (*",[196,239,240],{"class":206},"Claims",[196,242,243],{"class":202},",",[196,245,246],{"class":230}," error",[196,248,249],{"class":202},")\n",[196,251,253,256,258,261,264,266,268,271,274,276,278],{"class":198,"line":252},3,[196,254,255],{"class":219},"    GenerateToken",[196,257,223],{"class":202},[196,259,260],{"class":226},"claims",[196,262,263],{"class":202}," *",[196,265,240],{"class":206},[196,267,234],{"class":202},[196,269,270],{"class":202}," (",[196,272,273],{"class":230},"string",[196,275,243],{"class":202},[196,277,246],{"class":230},[196,279,249],{"class":202},[196,281,283],{"class":198,"line":282},4,[196,284,285],{"class":202},"}\n",[178,287,288,291],{},[182,289,290],{},"auth.NewJWTAuthProvider"," adapts any implementation to the app.",[293,294,240],"h2",{"id":260},[187,296,298],{"className":189,"code":297,"language":191,"meta":192,"style":192},"type Claims struct {\n    Subject   string         `json:\"sub\"`\n    Issuer    string         `json:\"iss\"`\n    Audience  string         `json:\"aud\"`\n    ExpiresAt int64          `json:\"exp\"`\n    IssuedAt  int64          `json:\"iat\"`\n    NotBefore int64          `json:\"nbf\"`\n    ID        string         `json:\"jti\"`\n    Custom    map[string]any `json:\"custom,omitempty\"`\n}\n",[182,299,300,312,330,344,358,375,390,405,420,445],{"__ignoreMap":192},[196,301,302,304,307,310],{"class":198,"line":199},[196,303,203],{"class":202},[196,305,306],{"class":206}," Claims",[196,308,309],{"class":202}," struct",[196,311,213],{"class":202},[196,313,314,318,320,323,327],{"class":198,"line":216},[196,315,317],{"class":316},"sTEyZ","    Subject   ",[196,319,273],{"class":230},[196,321,322],{"class":202},"         `",[196,324,326],{"class":325},"sfazB","json:\"sub\"",[196,328,329],{"class":202},"`\n",[196,331,332,335,337,339,342],{"class":198,"line":252},[196,333,334],{"class":316},"    Issuer    ",[196,336,273],{"class":230},[196,338,322],{"class":202},[196,340,341],{"class":325},"json:\"iss\"",[196,343,329],{"class":202},[196,345,346,349,351,353,356],{"class":198,"line":282},[196,347,348],{"class":316},"    Audience  ",[196,350,273],{"class":230},[196,352,322],{"class":202},[196,354,355],{"class":325},"json:\"aud\"",[196,357,329],{"class":202},[196,359,361,364,367,370,373],{"class":198,"line":360},5,[196,362,363],{"class":316},"    ExpiresAt ",[196,365,366],{"class":230},"int64",[196,368,369],{"class":202},"          `",[196,371,372],{"class":325},"json:\"exp\"",[196,374,329],{"class":202},[196,376,378,381,383,385,388],{"class":198,"line":377},6,[196,379,380],{"class":316},"    IssuedAt  ",[196,382,366],{"class":230},[196,384,369],{"class":202},[196,386,387],{"class":325},"json:\"iat\"",[196,389,329],{"class":202},[196,391,393,396,398,400,403],{"class":198,"line":392},7,[196,394,395],{"class":316},"    NotBefore ",[196,397,366],{"class":230},[196,399,369],{"class":202},[196,401,402],{"class":325},"json:\"nbf\"",[196,404,329],{"class":202},[196,406,408,411,413,415,418],{"class":198,"line":407},8,[196,409,410],{"class":316},"    ID        ",[196,412,273],{"class":230},[196,414,322],{"class":202},[196,416,417],{"class":325},"json:\"jti\"",[196,419,329],{"class":202},[196,421,423,426,429,431,434,437,440,443],{"class":198,"line":422},9,[196,424,425],{"class":316},"    Custom    ",[196,427,428],{"class":202},"map[",[196,430,273],{"class":230},[196,432,433],{"class":202},"]",[196,435,436],{"class":206},"any",[196,438,439],{"class":202}," `",[196,441,442],{"class":325},"json:\"custom,omitempty\"",[196,444,329],{"class":202},[196,446,448],{"class":198,"line":447},10,[196,449,285],{"class":202},[178,451,452,455,456,459,460,463,464,467,468,459,471,474],{},[182,453,454],{},"Valid()"," checks ",[182,457,458],{},"exp"," and ",[182,461,462],{},"nbf"," against the current time. Everything application-specific goes in ",[182,465,466],{},"Custom",", which is where the ",[182,469,470],{},"role",[182,472,473],{},"roles"," claims are read from when no resolver is configured.",[293,476,478],{"id":477},"issue-and-validate-your-own-tokens","Issue and validate your own tokens",[178,480,481,484],{},[182,482,483],{},"HMACProvider"," signs and verifies HS256 tokens with no external dependency.",[187,486,488],{"className":189,"code":487,"language":191,"meta":192,"style":192},"jwt := auth.NewHMACProvider(os.Getenv(\"JWT_SECRET\"), \"my-service\")\napp := ezz.New().Auth(auth.NewJWTAuthProvider(jwt))\n",[182,489,490,540],{"__ignoreMap":192},[196,491,492,495,498,501,504,507,509,512,514,517,519,522,525,527,530,533,536,538],{"class":198,"line":199},[196,493,494],{"class":316},"jwt ",[196,496,497],{"class":202},":=",[196,499,500],{"class":316}," auth",[196,502,503],{"class":202},".",[196,505,506],{"class":219},"NewHMACProvider",[196,508,223],{"class":202},[196,510,511],{"class":316},"os",[196,513,503],{"class":202},[196,515,516],{"class":219},"Getenv",[196,518,223],{"class":202},[196,520,521],{"class":202},"\"",[196,523,524],{"class":325},"JWT_SECRET",[196,526,521],{"class":202},[196,528,529],{"class":202},"),",[196,531,532],{"class":202}," \"",[196,534,535],{"class":325},"my-service",[196,537,521],{"class":202},[196,539,249],{"class":202},[196,541,542,545,547,550,552,555,558,560,562,565,567,570,572,575],{"class":198,"line":216},[196,543,544],{"class":316},"app ",[196,546,497],{"class":202},[196,548,549],{"class":316}," ezz",[196,551,503],{"class":202},[196,553,554],{"class":219},"New",[196,556,557],{"class":202},"().",[196,559,68],{"class":219},[196,561,223],{"class":202},[196,563,564],{"class":316},"auth",[196,566,503],{"class":202},[196,568,569],{"class":219},"NewJWTAuthProvider",[196,571,223],{"class":202},[196,573,574],{"class":316},"jwt",[196,576,577],{"class":202},"))\n",[178,579,580],{},"A login handler mints the token:",[187,582,584],{"className":189,"code":583,"language":191,"meta":192,"style":192},"app.POST(\"\u002Flogin\", ezz.H(func(ctx *ezz.Context, req LoginRequest) (*LoginResponse, error) {\n    user, ok := accounts.Verify(ctx, req.Email, req.Password)\n    if !ok {\n        return nil, ezz.Unauthorized(\"invalid email or password\")\n    }\n\n    expires := time.Now().Add(1 * time.Hour)\n    token, err := jwt.GenerateToken(&auth.Claims{\n        Subject:   user.ID,\n        ExpiresAt: expires.Unix(),\n        Custom: map[string]any{\n            \"email\": user.Email,\n            \"roles\": user.Roles,\n        },\n    })\n    if err != nil {\n        return nil, ezz.InternalServerError(\"could not issue token\")\n    }\n    return &LoginResponse{Token: token, ExpiresAt: expires}, nil\n})).Public()\n",[182,585,586,652,696,711,737,742,748,785,816,835,853,872,894,914,920,926,941,966,971,1008],{"__ignoreMap":192},[196,587,588,591,593,596,598,600,603,605,607,609,611,614,617,620,622,625,627,629,631,634,637,639,641,644,646,648,650],{"class":198,"line":199},[196,589,590],{"class":316},"app",[196,592,503],{"class":202},[196,594,595],{"class":219},"POST",[196,597,223],{"class":202},[196,599,521],{"class":202},[196,601,602],{"class":325},"\u002Flogin",[196,604,521],{"class":202},[196,606,243],{"class":202},[196,608,549],{"class":316},[196,610,503],{"class":202},[196,612,613],{"class":219},"H",[196,615,616],{"class":202},"(func(",[196,618,619],{"class":226},"ctx",[196,621,263],{"class":202},[196,623,624],{"class":206},"ezz",[196,626,503],{"class":202},[196,628,53],{"class":206},[196,630,243],{"class":202},[196,632,633],{"class":226}," req",[196,635,636],{"class":206}," LoginRequest",[196,638,234],{"class":202},[196,640,237],{"class":202},[196,642,643],{"class":206},"LoginResponse",[196,645,243],{"class":202},[196,647,246],{"class":230},[196,649,234],{"class":202},[196,651,213],{"class":202},[196,653,654,657,659,662,664,667,669,672,674,676,678,680,682,685,687,689,691,694],{"class":198,"line":216},[196,655,656],{"class":316},"    user",[196,658,243],{"class":202},[196,660,661],{"class":316}," ok ",[196,663,497],{"class":202},[196,665,666],{"class":316}," accounts",[196,668,503],{"class":202},[196,670,671],{"class":219},"Verify",[196,673,223],{"class":202},[196,675,619],{"class":316},[196,677,243],{"class":202},[196,679,633],{"class":316},[196,681,503],{"class":202},[196,683,684],{"class":316},"Email",[196,686,243],{"class":202},[196,688,633],{"class":316},[196,690,503],{"class":202},[196,692,693],{"class":316},"Password",[196,695,249],{"class":202},[196,697,698,702,705,708],{"class":198,"line":252},[196,699,701],{"class":700},"s7zQu","    if",[196,703,704],{"class":202}," !",[196,706,707],{"class":316},"ok ",[196,709,710],{"class":202},"{\n",[196,712,713,716,719,721,723,726,728,730,733,735],{"class":198,"line":282},[196,714,715],{"class":700},"        return",[196,717,718],{"class":202}," nil,",[196,720,549],{"class":316},[196,722,503],{"class":202},[196,724,725],{"class":219},"Unauthorized",[196,727,223],{"class":202},[196,729,521],{"class":202},[196,731,732],{"class":325},"invalid email or password",[196,734,521],{"class":202},[196,736,249],{"class":202},[196,738,739],{"class":198,"line":360},[196,740,741],{"class":202},"    }\n",[196,743,744],{"class":198,"line":377},[196,745,747],{"emptyLinePlaceholder":746},true,"\n",[196,749,750,753,755,758,760,763,765,768,770,774,776,778,780,783],{"class":198,"line":392},[196,751,752],{"class":316},"    expires ",[196,754,497],{"class":202},[196,756,757],{"class":316}," time",[196,759,503],{"class":202},[196,761,762],{"class":219},"Now",[196,764,557],{"class":202},[196,766,767],{"class":219},"Add",[196,769,223],{"class":202},[196,771,773],{"class":772},"sbssI","1",[196,775,263],{"class":202},[196,777,757],{"class":316},[196,779,503],{"class":202},[196,781,782],{"class":316},"Hour",[196,784,249],{"class":202},[196,786,787,790,792,795,797,800,802,805,808,810,812,814],{"class":198,"line":407},[196,788,789],{"class":316},"    token",[196,791,243],{"class":202},[196,793,794],{"class":316}," err ",[196,796,497],{"class":202},[196,798,799],{"class":316}," jwt",[196,801,503],{"class":202},[196,803,804],{"class":219},"GenerateToken",[196,806,807],{"class":202},"(&",[196,809,564],{"class":206},[196,811,503],{"class":202},[196,813,240],{"class":206},[196,815,710],{"class":202},[196,817,818,821,824,827,829,832],{"class":198,"line":422},[196,819,820],{"class":316},"        Subject",[196,822,823],{"class":202},":",[196,825,826],{"class":316},"   user",[196,828,503],{"class":202},[196,830,831],{"class":316},"ID",[196,833,834],{"class":202},",\n",[196,836,837,840,842,845,847,850],{"class":198,"line":447},[196,838,839],{"class":316},"        ExpiresAt",[196,841,823],{"class":202},[196,843,844],{"class":316}," expires",[196,846,503],{"class":202},[196,848,849],{"class":219},"Unix",[196,851,852],{"class":202},"(),\n",[196,854,856,859,861,864,866,868,870],{"class":198,"line":855},11,[196,857,858],{"class":316},"        Custom",[196,860,823],{"class":202},[196,862,863],{"class":202}," map[",[196,865,273],{"class":230},[196,867,433],{"class":202},[196,869,436],{"class":206},[196,871,710],{"class":202},[196,873,875,878,881,883,885,888,890,892],{"class":198,"line":874},12,[196,876,877],{"class":202},"            \"",[196,879,880],{"class":325},"email",[196,882,521],{"class":202},[196,884,823],{"class":202},[196,886,887],{"class":316}," user",[196,889,503],{"class":202},[196,891,684],{"class":316},[196,893,834],{"class":202},[196,895,897,899,901,903,905,907,909,912],{"class":198,"line":896},13,[196,898,877],{"class":202},[196,900,473],{"class":325},[196,902,521],{"class":202},[196,904,823],{"class":202},[196,906,887],{"class":316},[196,908,503],{"class":202},[196,910,911],{"class":316},"Roles",[196,913,834],{"class":202},[196,915,917],{"class":198,"line":916},14,[196,918,919],{"class":202},"        },\n",[196,921,923],{"class":198,"line":922},15,[196,924,925],{"class":202},"    })\n",[196,927,929,931,933,936,939],{"class":198,"line":928},16,[196,930,701],{"class":700},[196,932,794],{"class":316},[196,934,935],{"class":202},"!=",[196,937,938],{"class":202}," nil",[196,940,213],{"class":202},[196,942,944,946,948,950,952,955,957,959,962,964],{"class":198,"line":943},17,[196,945,715],{"class":700},[196,947,718],{"class":202},[196,949,549],{"class":316},[196,951,503],{"class":202},[196,953,954],{"class":219},"InternalServerError",[196,956,223],{"class":202},[196,958,521],{"class":202},[196,960,961],{"class":325},"could not issue token",[196,963,521],{"class":202},[196,965,249],{"class":202},[196,967,969],{"class":198,"line":968},18,[196,970,741],{"class":202},[196,972,974,977,980,982,985,988,990,993,995,998,1000,1002,1005],{"class":198,"line":973},19,[196,975,976],{"class":700},"    return",[196,978,979],{"class":202}," &",[196,981,643],{"class":206},[196,983,984],{"class":202},"{",[196,986,987],{"class":316},"Token",[196,989,823],{"class":202},[196,991,992],{"class":316}," token",[196,994,243],{"class":202},[196,996,997],{"class":316}," ExpiresAt",[196,999,823],{"class":202},[196,1001,844],{"class":316},[196,1003,1004],{"class":202},"},",[196,1006,1007],{"class":202}," nil\n",[196,1009,1011,1014,1017],{"class":198,"line":1010},20,[196,1012,1013],{"class":202},"})).",[196,1015,1016],{"class":219},"Public",[196,1018,1019],{"class":202},"()\n",[178,1021,1022,1024,1025,1028],{},[182,1023,804],{}," fills in the issuer from the provider and ",[182,1026,1027],{},"iat"," from the clock when they are unset. Validated tokens are cached in memory (1000 entries, keyed by the token string, expiring with the token) so a burst of requests from the same client verifies the signature once.",[1030,1031,1032,1033,1036],"warning",{},"Keep the secret out of source control and rotate it deliberately. Changing it invalidates every token immediately, since the provider holds a single key with no ",[182,1034,1035],{},"kid"," lookup.",[293,1038,1040],{"id":1039},"validate-gotrue-tokens","Validate GoTrue tokens",[178,1042,1043],{},"GoTrue and Supabase Auth sign with HS256 using the project's JWT secret, so validation is the same mechanism with GoTrue's claim layout on top.",[187,1045,1047],{"className":189,"code":1046,"language":191,"meta":192,"style":192},"gt := auth.NewGoTrueProvider(\"http:\u002F\u002Fgotrue:9999\", os.Getenv(\"GOTRUE_JWT_SECRET\"))\napp := ezz.New().Auth(auth.NewJWTAuthProvider(gt))\n",[182,1048,1049,1092],{"__ignoreMap":192},[196,1050,1051,1054,1056,1058,1060,1063,1065,1067,1070,1072,1074,1077,1079,1081,1083,1085,1088,1090],{"class":198,"line":199},[196,1052,1053],{"class":316},"gt ",[196,1055,497],{"class":202},[196,1057,500],{"class":316},[196,1059,503],{"class":202},[196,1061,1062],{"class":219},"NewGoTrueProvider",[196,1064,223],{"class":202},[196,1066,521],{"class":202},[196,1068,1069],{"class":325},"http:\u002F\u002Fgotrue:9999",[196,1071,521],{"class":202},[196,1073,243],{"class":202},[196,1075,1076],{"class":316}," os",[196,1078,503],{"class":202},[196,1080,516],{"class":219},[196,1082,223],{"class":202},[196,1084,521],{"class":202},[196,1086,1087],{"class":325},"GOTRUE_JWT_SECRET",[196,1089,521],{"class":202},[196,1091,577],{"class":202},[196,1093,1094,1096,1098,1100,1102,1104,1106,1108,1110,1112,1114,1116,1118,1121],{"class":198,"line":216},[196,1095,544],{"class":316},[196,1097,497],{"class":202},[196,1099,549],{"class":316},[196,1101,503],{"class":202},[196,1103,554],{"class":219},[196,1105,557],{"class":202},[196,1107,68],{"class":219},[196,1109,223],{"class":202},[196,1111,564],{"class":316},[196,1113,503],{"class":202},[196,1115,569],{"class":219},[196,1117,223],{"class":202},[196,1119,1120],{"class":316},"gt",[196,1122,577],{"class":202},[178,1124,1125,1126,1129,1130,1132,1133,1132,1136,1132,1138,1132,1141,1132,1144,1132,1147,1132,1150,1153,1154,503],{},"Beyond the standard fields, these claims are copied into ",[182,1127,1128],{},"Claims.Custom",": ",[182,1131,880],{},", ",[182,1134,1135],{},"phone",[182,1137,470],{},[182,1139,1140],{},"session_id",[182,1142,1143],{},"is_anonymous",[182,1145,1146],{},"user_metadata",[182,1148,1149],{},"app_metadata",[182,1151,1152],{},"identities",", and ",[182,1155,1156],{},"factors",[187,1158,1160],{"className":189,"code":1159,"language":191,"meta":192,"style":192},"user := ctx.User().(auth.User)\nclaims := user.GetClaims()\nemail, _ := claims.Custom[\"email\"].(string)\nmeta, _ := claims.Custom[\"user_metadata\"].(map[string]any)\n",[182,1161,1162,1188,1204,1238],{"__ignoreMap":192},[196,1163,1164,1167,1169,1172,1174,1177,1180,1182,1184,1186],{"class":198,"line":199},[196,1165,1166],{"class":316},"user ",[196,1168,497],{"class":202},[196,1170,1171],{"class":316}," ctx",[196,1173,503],{"class":202},[196,1175,1176],{"class":219},"User",[196,1178,1179],{"class":202},"().(",[196,1181,564],{"class":206},[196,1183,503],{"class":202},[196,1185,1176],{"class":206},[196,1187,249],{"class":202},[196,1189,1190,1193,1195,1197,1199,1202],{"class":198,"line":216},[196,1191,1192],{"class":316},"claims ",[196,1194,497],{"class":202},[196,1196,887],{"class":316},[196,1198,503],{"class":202},[196,1200,1201],{"class":219},"GetClaims",[196,1203,1019],{"class":202},[196,1205,1206,1208,1210,1213,1215,1218,1220,1222,1225,1227,1229,1231,1234,1236],{"class":198,"line":252},[196,1207,880],{"class":316},[196,1209,243],{"class":202},[196,1211,1212],{"class":316}," _ ",[196,1214,497],{"class":202},[196,1216,1217],{"class":316}," claims",[196,1219,503],{"class":202},[196,1221,466],{"class":316},[196,1223,1224],{"class":202},"[",[196,1226,521],{"class":202},[196,1228,880],{"class":325},[196,1230,521],{"class":202},[196,1232,1233],{"class":202},"].(",[196,1235,273],{"class":230},[196,1237,249],{"class":202},[196,1239,1240,1243,1245,1247,1249,1251,1253,1255,1257,1259,1261,1263,1266,1268,1270,1272],{"class":198,"line":282},[196,1241,1242],{"class":316},"meta",[196,1244,243],{"class":202},[196,1246,1212],{"class":316},[196,1248,497],{"class":202},[196,1250,1217],{"class":316},[196,1252,503],{"class":202},[196,1254,466],{"class":316},[196,1256,1224],{"class":202},[196,1258,521],{"class":202},[196,1260,1146],{"class":325},[196,1262,521],{"class":202},[196,1264,1265],{"class":202},"].(map[",[196,1267,273],{"class":230},[196,1269,433],{"class":202},[196,1271,436],{"class":206},[196,1273,249],{"class":202},[178,1275,1276,1279,1280,1283],{},[182,1277,1278],{},"GetUser(token)"," calls GoTrue's ",[182,1281,1282],{},"GET \u002Fuser"," when you need the full record rather than the claims:",[187,1285,1287],{"className":189,"code":1286,"language":191,"meta":192,"style":192},"gotrueUser, err := gt.GetUser(token)\n",[182,1288,1289],{"__ignoreMap":192},[196,1290,1291,1294,1296,1298,1300,1303,1305,1308,1310,1312],{"class":198,"line":199},[196,1292,1293],{"class":316},"gotrueUser",[196,1295,243],{"class":202},[196,1297,794],{"class":316},[196,1299,497],{"class":202},[196,1301,1302],{"class":316}," gt",[196,1304,503],{"class":202},[196,1306,1307],{"class":219},"GetUser",[196,1309,223],{"class":202},[196,1311,227],{"class":316},[196,1313,249],{"class":202},[178,1315,1316,1318],{},[182,1317,804],{}," returns an error here, since only GoTrue issues its tokens.",[1320,1321,1322,1323,1325,1326,1329,1330,1333,1334,503],"note",{},"GoTrue's ",[182,1324,470],{}," claim comes from ",[182,1327,1328],{},"auth.users.role"," and is ",[182,1331,1332],{},"authenticated"," for every normal user. It is not an application role. See ",[1335,1336,1337],"a",{"href":90},"Roles and permissions",[178,1339,1340,1341,1344,1345,503],{},"If you want ezz to be the only public entry point and expose typed ",[182,1342,1343],{},"\u002Fauth\u002F*"," routes, use the proxy instead of the bare provider. See ",[1335,1346,1347],{"href":106},"GoTrue proxy",[293,1349,1351],{"id":1350},"implement-a-custom-jwt-provider","Implement a custom JWT provider",[178,1353,1354],{},"Use this when your tokens are RS256, come from an external issuer with a JWKS endpoint, or need claims the built-in providers do not parse.",[187,1356,1358],{"className":189,"code":1357,"language":191,"meta":192,"style":192},"type OIDCProvider struct {\n    keys *keyfunc.JWKS\n}\n\nfunc (p *OIDCProvider) ValidateToken(token string) (*auth.Claims, error) {\n    parsed, err := jwt.Parse(token, p.keys.Keyfunc)\n    if err != nil || !parsed.Valid {\n        return nil, fmt.Errorf(\"invalid token: %w\", err)\n    }\n    mc := parsed.Claims.(jwt.MapClaims)\n\n    claims := &auth.Claims{Custom: map[string]any{}}\n    claims.Subject, _ = mc[\"sub\"].(string)\n    claims.Issuer, _ = mc[\"iss\"].(string)\n    if exp, ok := mc[\"exp\"].(float64); ok {\n        claims.ExpiresAt = int64(exp)\n    }\n    for _, k := range []string{\"email\", \"roles\", \"groups\"} {\n        if v, ok := mc[k]; ok {\n            claims.Custom[k] = v\n        }\n    }\n    return claims, claims.Valid()\n}\n\nfunc (p *OIDCProvider) GenerateToken(*auth.Claims) (string, error) {\n    return \"\", errors.New(\"tokens are issued by the identity provider\")\n}\n\napp := ezz.New().Auth(auth.NewJWTAuthProvider(&OIDCProvider{keys: keys}))\n",[182,1359,1360,1371,1387,1391,1395,1439,1478,1503,1537,1541,1567,1571,1603,1638,1670,1705,1726,1730,1783,1811,1832,1838,1843,1861,1866,1871,1912,1940,1945,1950],{"__ignoreMap":192},[196,1361,1362,1364,1367,1369],{"class":198,"line":199},[196,1363,203],{"class":202},[196,1365,1366],{"class":206}," OIDCProvider",[196,1368,309],{"class":202},[196,1370,213],{"class":202},[196,1372,1373,1376,1379,1382,1384],{"class":198,"line":216},[196,1374,1375],{"class":316},"    keys ",[196,1377,1378],{"class":202},"*",[196,1380,1381],{"class":206},"keyfunc",[196,1383,503],{"class":202},[196,1385,1386],{"class":206},"JWKS\n",[196,1388,1389],{"class":198,"line":252},[196,1390,285],{"class":202},[196,1392,1393],{"class":198,"line":282},[196,1394,747],{"emptyLinePlaceholder":746},[196,1396,1397,1400,1402,1405,1407,1410,1412,1415,1417,1419,1421,1423,1425,1427,1429,1431,1433,1435,1437],{"class":198,"line":360},[196,1398,1399],{"class":202},"func",[196,1401,270],{"class":202},[196,1403,1404],{"class":226},"p ",[196,1406,1378],{"class":202},[196,1408,1409],{"class":206},"OIDCProvider",[196,1411,234],{"class":202},[196,1413,1414],{"class":219}," ValidateToken",[196,1416,223],{"class":202},[196,1418,227],{"class":226},[196,1420,231],{"class":230},[196,1422,234],{"class":202},[196,1424,237],{"class":202},[196,1426,564],{"class":206},[196,1428,503],{"class":202},[196,1430,240],{"class":206},[196,1432,243],{"class":202},[196,1434,246],{"class":230},[196,1436,234],{"class":202},[196,1438,213],{"class":202},[196,1440,1441,1444,1446,1448,1450,1452,1454,1457,1459,1461,1463,1466,1468,1471,1473,1476],{"class":198,"line":377},[196,1442,1443],{"class":316},"    parsed",[196,1445,243],{"class":202},[196,1447,794],{"class":316},[196,1449,497],{"class":202},[196,1451,799],{"class":316},[196,1453,503],{"class":202},[196,1455,1456],{"class":219},"Parse",[196,1458,223],{"class":202},[196,1460,227],{"class":316},[196,1462,243],{"class":202},[196,1464,1465],{"class":316}," p",[196,1467,503],{"class":202},[196,1469,1470],{"class":316},"keys",[196,1472,503],{"class":202},[196,1474,1475],{"class":316},"Keyfunc",[196,1477,249],{"class":202},[196,1479,1480,1482,1484,1486,1488,1491,1493,1496,1498,1501],{"class":198,"line":392},[196,1481,701],{"class":700},[196,1483,794],{"class":316},[196,1485,935],{"class":202},[196,1487,938],{"class":202},[196,1489,1490],{"class":202}," ||",[196,1492,704],{"class":202},[196,1494,1495],{"class":316},"parsed",[196,1497,503],{"class":202},[196,1499,1500],{"class":316},"Valid ",[196,1502,710],{"class":202},[196,1504,1505,1507,1509,1512,1514,1517,1519,1521,1524,1528,1530,1532,1535],{"class":198,"line":407},[196,1506,715],{"class":700},[196,1508,718],{"class":202},[196,1510,1511],{"class":316}," fmt",[196,1513,503],{"class":202},[196,1515,1516],{"class":219},"Errorf",[196,1518,223],{"class":202},[196,1520,521],{"class":202},[196,1522,1523],{"class":325},"invalid token: ",[196,1525,1527],{"class":1526},"swJcz","%w",[196,1529,521],{"class":202},[196,1531,243],{"class":202},[196,1533,1534],{"class":316}," err",[196,1536,249],{"class":202},[196,1538,1539],{"class":198,"line":422},[196,1540,741],{"class":202},[196,1542,1543,1546,1548,1551,1553,1555,1558,1560,1562,1565],{"class":198,"line":447},[196,1544,1545],{"class":316},"    mc ",[196,1547,497],{"class":202},[196,1549,1550],{"class":316}," parsed",[196,1552,503],{"class":202},[196,1554,240],{"class":316},[196,1556,1557],{"class":202},".(",[196,1559,574],{"class":206},[196,1561,503],{"class":202},[196,1563,1564],{"class":206},"MapClaims",[196,1566,249],{"class":202},[196,1568,1569],{"class":198,"line":855},[196,1570,747],{"emptyLinePlaceholder":746},[196,1572,1573,1576,1578,1580,1582,1584,1586,1588,1590,1592,1594,1596,1598,1600],{"class":198,"line":874},[196,1574,1575],{"class":316},"    claims ",[196,1577,497],{"class":202},[196,1579,979],{"class":202},[196,1581,564],{"class":206},[196,1583,503],{"class":202},[196,1585,240],{"class":206},[196,1587,984],{"class":202},[196,1589,466],{"class":316},[196,1591,823],{"class":202},[196,1593,863],{"class":202},[196,1595,273],{"class":230},[196,1597,433],{"class":202},[196,1599,436],{"class":206},[196,1601,1602],{"class":202},"{}}\n",[196,1604,1605,1608,1610,1613,1615,1617,1620,1623,1625,1627,1630,1632,1634,1636],{"class":198,"line":896},[196,1606,1607],{"class":316},"    claims",[196,1609,503],{"class":202},[196,1611,1612],{"class":316},"Subject",[196,1614,243],{"class":202},[196,1616,1212],{"class":316},[196,1618,1619],{"class":202},"=",[196,1621,1622],{"class":316}," mc",[196,1624,1224],{"class":202},[196,1626,521],{"class":202},[196,1628,1629],{"class":325},"sub",[196,1631,521],{"class":202},[196,1633,1233],{"class":202},[196,1635,273],{"class":230},[196,1637,249],{"class":202},[196,1639,1640,1642,1644,1647,1649,1651,1653,1655,1657,1659,1662,1664,1666,1668],{"class":198,"line":916},[196,1641,1607],{"class":316},[196,1643,503],{"class":202},[196,1645,1646],{"class":316},"Issuer",[196,1648,243],{"class":202},[196,1650,1212],{"class":316},[196,1652,1619],{"class":202},[196,1654,1622],{"class":316},[196,1656,1224],{"class":202},[196,1658,521],{"class":202},[196,1660,1661],{"class":325},"iss",[196,1663,521],{"class":202},[196,1665,1233],{"class":202},[196,1667,273],{"class":230},[196,1669,249],{"class":202},[196,1671,1672,1674,1677,1679,1681,1683,1685,1687,1689,1691,1693,1695,1698,1701,1703],{"class":198,"line":922},[196,1673,701],{"class":700},[196,1675,1676],{"class":316}," exp",[196,1678,243],{"class":202},[196,1680,661],{"class":316},[196,1682,497],{"class":202},[196,1684,1622],{"class":316},[196,1686,1224],{"class":202},[196,1688,521],{"class":202},[196,1690,458],{"class":325},[196,1692,521],{"class":202},[196,1694,1233],{"class":202},[196,1696,1697],{"class":230},"float64",[196,1699,1700],{"class":202},");",[196,1702,661],{"class":316},[196,1704,710],{"class":202},[196,1706,1707,1710,1712,1715,1717,1720,1722,1724],{"class":198,"line":928},[196,1708,1709],{"class":316},"        claims",[196,1711,503],{"class":202},[196,1713,1714],{"class":316},"ExpiresAt ",[196,1716,1619],{"class":202},[196,1718,1719],{"class":230}," int64",[196,1721,223],{"class":202},[196,1723,458],{"class":316},[196,1725,249],{"class":202},[196,1727,1728],{"class":198,"line":943},[196,1729,741],{"class":202},[196,1731,1732,1735,1738,1740,1743,1745,1748,1751,1753,1755,1757,1759,1761,1763,1765,1767,1769,1771,1773,1776,1778,1781],{"class":198,"line":968},[196,1733,1734],{"class":700},"    for",[196,1736,1737],{"class":316}," _",[196,1739,243],{"class":202},[196,1741,1742],{"class":316}," k ",[196,1744,497],{"class":202},[196,1746,1747],{"class":700}," range",[196,1749,1750],{"class":202}," []",[196,1752,273],{"class":230},[196,1754,984],{"class":202},[196,1756,521],{"class":202},[196,1758,880],{"class":325},[196,1760,521],{"class":202},[196,1762,243],{"class":202},[196,1764,532],{"class":202},[196,1766,473],{"class":325},[196,1768,521],{"class":202},[196,1770,243],{"class":202},[196,1772,532],{"class":202},[196,1774,1775],{"class":325},"groups",[196,1777,521],{"class":202},[196,1779,1780],{"class":202},"}",[196,1782,213],{"class":202},[196,1784,1785,1788,1791,1793,1795,1797,1799,1801,1804,1807,1809],{"class":198,"line":973},[196,1786,1787],{"class":700},"        if",[196,1789,1790],{"class":316}," v",[196,1792,243],{"class":202},[196,1794,661],{"class":316},[196,1796,497],{"class":202},[196,1798,1622],{"class":316},[196,1800,1224],{"class":202},[196,1802,1803],{"class":316},"k",[196,1805,1806],{"class":202},"];",[196,1808,661],{"class":316},[196,1810,710],{"class":202},[196,1812,1813,1816,1818,1820,1822,1824,1826,1829],{"class":198,"line":1010},[196,1814,1815],{"class":316},"            claims",[196,1817,503],{"class":202},[196,1819,466],{"class":316},[196,1821,1224],{"class":202},[196,1823,1803],{"class":316},[196,1825,433],{"class":202},[196,1827,1828],{"class":202}," =",[196,1830,1831],{"class":316}," v\n",[196,1833,1835],{"class":198,"line":1834},21,[196,1836,1837],{"class":202},"        }\n",[196,1839,1841],{"class":198,"line":1840},22,[196,1842,741],{"class":202},[196,1844,1846,1848,1850,1852,1854,1856,1859],{"class":198,"line":1845},23,[196,1847,976],{"class":700},[196,1849,1217],{"class":316},[196,1851,243],{"class":202},[196,1853,1217],{"class":316},[196,1855,503],{"class":202},[196,1857,1858],{"class":219},"Valid",[196,1860,1019],{"class":202},[196,1862,1864],{"class":198,"line":1863},24,[196,1865,285],{"class":202},[196,1867,1869],{"class":198,"line":1868},25,[196,1870,747],{"emptyLinePlaceholder":746},[196,1872,1874,1876,1878,1880,1882,1884,1886,1889,1892,1894,1896,1898,1900,1902,1904,1906,1908,1910],{"class":198,"line":1873},26,[196,1875,1399],{"class":202},[196,1877,270],{"class":202},[196,1879,1404],{"class":226},[196,1881,1378],{"class":202},[196,1883,1409],{"class":206},[196,1885,234],{"class":202},[196,1887,1888],{"class":219}," GenerateToken",[196,1890,1891],{"class":202},"(*",[196,1893,564],{"class":206},[196,1895,503],{"class":202},[196,1897,240],{"class":206},[196,1899,234],{"class":202},[196,1901,270],{"class":202},[196,1903,273],{"class":230},[196,1905,243],{"class":202},[196,1907,246],{"class":230},[196,1909,234],{"class":202},[196,1911,213],{"class":202},[196,1913,1915,1917,1920,1922,1925,1927,1929,1931,1933,1936,1938],{"class":198,"line":1914},27,[196,1916,976],{"class":700},[196,1918,1919],{"class":202}," \"\"",[196,1921,243],{"class":202},[196,1923,1924],{"class":316}," errors",[196,1926,503],{"class":202},[196,1928,554],{"class":219},[196,1930,223],{"class":202},[196,1932,521],{"class":202},[196,1934,1935],{"class":325},"tokens are issued by the identity provider",[196,1937,521],{"class":202},[196,1939,249],{"class":202},[196,1941,1943],{"class":198,"line":1942},28,[196,1944,285],{"class":202},[196,1946,1948],{"class":198,"line":1947},29,[196,1949,747],{"emptyLinePlaceholder":746},[196,1951,1953,1955,1957,1959,1961,1963,1965,1967,1969,1971,1973,1975,1977,1979,1981,1983,1985,1988],{"class":198,"line":1952},30,[196,1954,544],{"class":316},[196,1956,497],{"class":202},[196,1958,549],{"class":316},[196,1960,503],{"class":202},[196,1962,554],{"class":219},[196,1964,557],{"class":202},[196,1966,68],{"class":219},[196,1968,223],{"class":202},[196,1970,564],{"class":316},[196,1972,503],{"class":202},[196,1974,569],{"class":219},[196,1976,807],{"class":202},[196,1978,1409],{"class":206},[196,1980,984],{"class":202},[196,1982,1470],{"class":316},[196,1984,823],{"class":202},[196,1986,1987],{"class":316}," keys",[196,1989,1990],{"class":202},"}))\n",[293,1992,1994],{"id":1993},"authenticate-something-other-than-a-jwt","Authenticate something other than a JWT",[178,1996,1997,1998,2000,2001,459,2004,2007],{},"For API keys, opaque sessions, or client certificates, implement ",[182,1999,184],{}," directly. Return a value with ",[182,2002,2003],{},"HasRole",[182,2005,2006],{},"HasPermission"," so the route rules keep working.",[187,2009,2011],{"className":189,"code":2010,"language":191,"meta":192,"style":192},"type APIKeyProvider struct{ store *KeyStore }\n\nfunc (p *APIKeyProvider) Authenticate(r *http.Request) (any, error) {\n    key := r.Header.Get(\"X-API-Key\")\n    if key == \"\" {\n        return nil, errors.New(\"missing api key\")\n    }\n    client, err := p.store.Lookup(r.Context(), key)\n    if err != nil {\n        return nil, err\n    }\n    return client, nil\n}\n\ntype Client struct {\n    Name   string\n    Scopes []string\n}\n\nfunc (c *Client) HasRole(role string) bool            { return slices.Contains(c.Scopes, role) }\nfunc (c *Client) HasPermission(perm string) bool      { return slices.Contains(c.Scopes, perm) }\n\napp := ezz.New().Auth(&APIKeyProvider{store: keys})\napp.GET(\"\u002Fmetrics\", metrics).Auth(ezz.Permission(\"metrics:read\"))\n",[182,2012,2013,2034,2038,2085,2116,2130,2153,2157,2196,2208,2217,2221,2232,2236,2240,2251,2259,2269,2273,2277,2340,2396,2400,2431],{"__ignoreMap":192},[196,2014,2015,2017,2020,2023,2026,2028,2031],{"class":198,"line":199},[196,2016,203],{"class":202},[196,2018,2019],{"class":206}," APIKeyProvider",[196,2021,2022],{"class":202}," struct{",[196,2024,2025],{"class":316}," store ",[196,2027,1378],{"class":202},[196,2029,2030],{"class":206},"KeyStore",[196,2032,2033],{"class":202}," }\n",[196,2035,2036],{"class":198,"line":216},[196,2037,747],{"emptyLinePlaceholder":746},[196,2039,2040,2042,2044,2046,2048,2051,2053,2056,2058,2061,2063,2066,2068,2071,2073,2075,2077,2079,2081,2083],{"class":198,"line":252},[196,2041,1399],{"class":202},[196,2043,270],{"class":202},[196,2045,1404],{"class":226},[196,2047,1378],{"class":202},[196,2049,2050],{"class":206},"APIKeyProvider",[196,2052,234],{"class":202},[196,2054,2055],{"class":219}," Authenticate",[196,2057,223],{"class":202},[196,2059,2060],{"class":226},"r",[196,2062,263],{"class":202},[196,2064,2065],{"class":206},"http",[196,2067,503],{"class":202},[196,2069,2070],{"class":206},"Request",[196,2072,234],{"class":202},[196,2074,270],{"class":202},[196,2076,436],{"class":206},[196,2078,243],{"class":202},[196,2080,246],{"class":230},[196,2082,234],{"class":202},[196,2084,213],{"class":202},[196,2086,2087,2090,2092,2095,2097,2100,2102,2105,2107,2109,2112,2114],{"class":198,"line":282},[196,2088,2089],{"class":316},"    key ",[196,2091,497],{"class":202},[196,2093,2094],{"class":316}," r",[196,2096,503],{"class":202},[196,2098,2099],{"class":316},"Header",[196,2101,503],{"class":202},[196,2103,2104],{"class":219},"Get",[196,2106,223],{"class":202},[196,2108,521],{"class":202},[196,2110,2111],{"class":325},"X-API-Key",[196,2113,521],{"class":202},[196,2115,249],{"class":202},[196,2117,2118,2120,2123,2126,2128],{"class":198,"line":360},[196,2119,701],{"class":700},[196,2121,2122],{"class":316}," key ",[196,2124,2125],{"class":202},"==",[196,2127,1919],{"class":202},[196,2129,213],{"class":202},[196,2131,2132,2134,2136,2138,2140,2142,2144,2146,2149,2151],{"class":198,"line":377},[196,2133,715],{"class":700},[196,2135,718],{"class":202},[196,2137,1924],{"class":316},[196,2139,503],{"class":202},[196,2141,554],{"class":219},[196,2143,223],{"class":202},[196,2145,521],{"class":202},[196,2147,2148],{"class":325},"missing api key",[196,2150,521],{"class":202},[196,2152,249],{"class":202},[196,2154,2155],{"class":198,"line":392},[196,2156,741],{"class":202},[196,2158,2159,2162,2164,2166,2168,2170,2172,2175,2177,2180,2182,2184,2186,2188,2191,2194],{"class":198,"line":407},[196,2160,2161],{"class":316},"    client",[196,2163,243],{"class":202},[196,2165,794],{"class":316},[196,2167,497],{"class":202},[196,2169,1465],{"class":316},[196,2171,503],{"class":202},[196,2173,2174],{"class":316},"store",[196,2176,503],{"class":202},[196,2178,2179],{"class":219},"Lookup",[196,2181,223],{"class":202},[196,2183,2060],{"class":316},[196,2185,503],{"class":202},[196,2187,53],{"class":219},[196,2189,2190],{"class":202},"(),",[196,2192,2193],{"class":316}," key",[196,2195,249],{"class":202},[196,2197,2198,2200,2202,2204,2206],{"class":198,"line":422},[196,2199,701],{"class":700},[196,2201,794],{"class":316},[196,2203,935],{"class":202},[196,2205,938],{"class":202},[196,2207,213],{"class":202},[196,2209,2210,2212,2214],{"class":198,"line":447},[196,2211,715],{"class":700},[196,2213,718],{"class":202},[196,2215,2216],{"class":316}," err\n",[196,2218,2219],{"class":198,"line":855},[196,2220,741],{"class":202},[196,2222,2223,2225,2228,2230],{"class":198,"line":874},[196,2224,976],{"class":700},[196,2226,2227],{"class":316}," client",[196,2229,243],{"class":202},[196,2231,1007],{"class":202},[196,2233,2234],{"class":198,"line":896},[196,2235,285],{"class":202},[196,2237,2238],{"class":198,"line":916},[196,2239,747],{"emptyLinePlaceholder":746},[196,2241,2242,2244,2247,2249],{"class":198,"line":922},[196,2243,203],{"class":202},[196,2245,2246],{"class":206}," Client",[196,2248,309],{"class":202},[196,2250,213],{"class":202},[196,2252,2253,2256],{"class":198,"line":928},[196,2254,2255],{"class":316},"    Name   ",[196,2257,2258],{"class":230},"string\n",[196,2260,2261,2264,2267],{"class":198,"line":943},[196,2262,2263],{"class":316},"    Scopes ",[196,2265,2266],{"class":202},"[]",[196,2268,2258],{"class":230},[196,2270,2271],{"class":198,"line":968},[196,2272,285],{"class":202},[196,2274,2275],{"class":198,"line":973},[196,2276,747],{"emptyLinePlaceholder":746},[196,2278,2279,2281,2283,2286,2288,2291,2293,2296,2298,2300,2302,2304,2307,2310,2313,2316,2318,2321,2323,2326,2328,2331,2333,2336,2338],{"class":198,"line":1010},[196,2280,1399],{"class":202},[196,2282,270],{"class":202},[196,2284,2285],{"class":226},"c ",[196,2287,1378],{"class":202},[196,2289,2290],{"class":206},"Client",[196,2292,234],{"class":202},[196,2294,2295],{"class":219}," HasRole",[196,2297,223],{"class":202},[196,2299,470],{"class":226},[196,2301,231],{"class":230},[196,2303,234],{"class":202},[196,2305,2306],{"class":230}," bool",[196,2308,2309],{"class":202},"            {",[196,2311,2312],{"class":700}," return",[196,2314,2315],{"class":316}," slices",[196,2317,503],{"class":202},[196,2319,2320],{"class":219},"Contains",[196,2322,223],{"class":202},[196,2324,2325],{"class":316},"c",[196,2327,503],{"class":202},[196,2329,2330],{"class":316},"Scopes",[196,2332,243],{"class":202},[196,2334,2335],{"class":316}," role",[196,2337,234],{"class":202},[196,2339,2033],{"class":202},[196,2341,2342,2344,2346,2348,2350,2352,2354,2357,2359,2362,2364,2366,2368,2371,2373,2375,2377,2379,2381,2383,2385,2387,2389,2392,2394],{"class":198,"line":1834},[196,2343,1399],{"class":202},[196,2345,270],{"class":202},[196,2347,2285],{"class":226},[196,2349,1378],{"class":202},[196,2351,2290],{"class":206},[196,2353,234],{"class":202},[196,2355,2356],{"class":219}," HasPermission",[196,2358,223],{"class":202},[196,2360,2361],{"class":226},"perm",[196,2363,231],{"class":230},[196,2365,234],{"class":202},[196,2367,2306],{"class":230},[196,2369,2370],{"class":202},"      {",[196,2372,2312],{"class":700},[196,2374,2315],{"class":316},[196,2376,503],{"class":202},[196,2378,2320],{"class":219},[196,2380,223],{"class":202},[196,2382,2325],{"class":316},[196,2384,503],{"class":202},[196,2386,2330],{"class":316},[196,2388,243],{"class":202},[196,2390,2391],{"class":316}," perm",[196,2393,234],{"class":202},[196,2395,2033],{"class":202},[196,2397,2398],{"class":198,"line":1840},[196,2399,747],{"emptyLinePlaceholder":746},[196,2401,2402,2404,2406,2408,2410,2412,2414,2416,2418,2420,2422,2424,2426,2428],{"class":198,"line":1845},[196,2403,544],{"class":316},[196,2405,497],{"class":202},[196,2407,549],{"class":316},[196,2409,503],{"class":202},[196,2411,554],{"class":219},[196,2413,557],{"class":202},[196,2415,68],{"class":219},[196,2417,807],{"class":202},[196,2419,2050],{"class":206},[196,2421,984],{"class":202},[196,2423,2174],{"class":316},[196,2425,823],{"class":202},[196,2427,1987],{"class":316},[196,2429,2430],{"class":202},"})\n",[196,2432,2433,2435,2437,2440,2442,2444,2447,2449,2451,2454,2457,2459,2461,2463,2465,2468,2470,2472,2475,2477],{"class":198,"line":1863},[196,2434,590],{"class":316},[196,2436,503],{"class":202},[196,2438,2439],{"class":219},"GET",[196,2441,223],{"class":202},[196,2443,521],{"class":202},[196,2445,2446],{"class":325},"\u002Fmetrics",[196,2448,521],{"class":202},[196,2450,243],{"class":202},[196,2452,2453],{"class":316}," metrics",[196,2455,2456],{"class":202},").",[196,2458,68],{"class":219},[196,2460,223],{"class":202},[196,2462,624],{"class":316},[196,2464,503],{"class":202},[196,2466,2467],{"class":219},"Permission",[196,2469,223],{"class":202},[196,2471,521],{"class":202},[196,2473,2474],{"class":325},"metrics:read",[196,2476,521],{"class":202},[196,2478,577],{"class":202},[178,2480,2481],{},"To support several credential types, try each in turn:",[187,2483,2485],{"className":189,"code":2484,"language":191,"meta":192,"style":192},"type MultiProvider struct{ providers []ezz.AuthProvider }\n\nfunc (m *MultiProvider) Authenticate(r *http.Request) (any, error) {\n    var last error\n    for _, p := range m.providers {\n        user, err := p.Authenticate(r)\n        if err == nil {\n            return user, nil\n        }\n        last = err\n    }\n    return nil, last\n}\n",[182,2486,2487,2510,2514,2558,2569,2594,2618,2630,2641,2645,2654,2658,2667],{"__ignoreMap":192},[196,2488,2489,2491,2494,2496,2499,2501,2503,2505,2508],{"class":198,"line":199},[196,2490,203],{"class":202},[196,2492,2493],{"class":206}," MultiProvider",[196,2495,2022],{"class":202},[196,2497,2498],{"class":316}," providers ",[196,2500,2266],{"class":202},[196,2502,624],{"class":206},[196,2504,503],{"class":202},[196,2506,2507],{"class":206},"AuthProvider",[196,2509,2033],{"class":202},[196,2511,2512],{"class":198,"line":216},[196,2513,747],{"emptyLinePlaceholder":746},[196,2515,2516,2518,2520,2523,2525,2528,2530,2532,2534,2536,2538,2540,2542,2544,2546,2548,2550,2552,2554,2556],{"class":198,"line":252},[196,2517,1399],{"class":202},[196,2519,270],{"class":202},[196,2521,2522],{"class":226},"m ",[196,2524,1378],{"class":202},[196,2526,2527],{"class":206},"MultiProvider",[196,2529,234],{"class":202},[196,2531,2055],{"class":219},[196,2533,223],{"class":202},[196,2535,2060],{"class":226},[196,2537,263],{"class":202},[196,2539,2065],{"class":206},[196,2541,503],{"class":202},[196,2543,2070],{"class":206},[196,2545,234],{"class":202},[196,2547,270],{"class":202},[196,2549,436],{"class":206},[196,2551,243],{"class":202},[196,2553,246],{"class":230},[196,2555,234],{"class":202},[196,2557,213],{"class":202},[196,2559,2560,2563,2566],{"class":198,"line":282},[196,2561,2562],{"class":202},"    var",[196,2564,2565],{"class":316}," last ",[196,2567,2568],{"class":230},"error\n",[196,2570,2571,2573,2575,2577,2580,2582,2584,2587,2589,2592],{"class":198,"line":360},[196,2572,1734],{"class":700},[196,2574,1737],{"class":316},[196,2576,243],{"class":202},[196,2578,2579],{"class":316}," p ",[196,2581,497],{"class":202},[196,2583,1747],{"class":700},[196,2585,2586],{"class":316}," m",[196,2588,503],{"class":202},[196,2590,2591],{"class":316},"providers ",[196,2593,710],{"class":202},[196,2595,2596,2599,2601,2603,2605,2607,2609,2612,2614,2616],{"class":198,"line":377},[196,2597,2598],{"class":316},"        user",[196,2600,243],{"class":202},[196,2602,794],{"class":316},[196,2604,497],{"class":202},[196,2606,1465],{"class":316},[196,2608,503],{"class":202},[196,2610,2611],{"class":219},"Authenticate",[196,2613,223],{"class":202},[196,2615,2060],{"class":316},[196,2617,249],{"class":202},[196,2619,2620,2622,2624,2626,2628],{"class":198,"line":392},[196,2621,1787],{"class":700},[196,2623,794],{"class":316},[196,2625,2125],{"class":202},[196,2627,938],{"class":202},[196,2629,213],{"class":202},[196,2631,2632,2635,2637,2639],{"class":198,"line":407},[196,2633,2634],{"class":700},"            return",[196,2636,887],{"class":316},[196,2638,243],{"class":202},[196,2640,1007],{"class":202},[196,2642,2643],{"class":198,"line":422},[196,2644,1837],{"class":202},[196,2646,2647,2650,2652],{"class":198,"line":447},[196,2648,2649],{"class":316},"        last ",[196,2651,1619],{"class":202},[196,2653,2216],{"class":316},[196,2655,2656],{"class":198,"line":855},[196,2657,741],{"class":202},[196,2659,2660,2662,2664],{"class":198,"line":874},[196,2661,976],{"class":700},[196,2663,718],{"class":202},[196,2665,2666],{"class":316}," last\n",[196,2668,2669],{"class":198,"line":896},[196,2670,285],{"class":202},[293,2672,2674],{"id":2673},"authenticate-in-middleware-instead","Authenticate in middleware instead",[178,2676,2677,2678,2681],{},"App-level auth runs before the middleware chain, which means rejections skip your logging and CORS middleware. When you need those on ",[182,2679,2680],{},"401"," responses, or when only part of the app is protected, use the middleware form:",[187,2683,2685],{"className":189,"code":2684,"language":191,"meta":192,"style":192},"protected := app.Group(\"\u002Fapi\").Use(auth.JWTMiddleware(jwt))\nopen := app.Group(\"\u002Fpublic\").Use(auth.OptionalJWTMiddleware(jwt))\n",[182,2686,2687,2731],{"__ignoreMap":192},[196,2688,2689,2692,2694,2697,2699,2702,2704,2706,2709,2711,2713,2716,2718,2720,2722,2725,2727,2729],{"class":198,"line":199},[196,2690,2691],{"class":316},"protected ",[196,2693,497],{"class":202},[196,2695,2696],{"class":316}," app",[196,2698,503],{"class":202},[196,2700,2701],{"class":219},"Group",[196,2703,223],{"class":202},[196,2705,521],{"class":202},[196,2707,2708],{"class":325},"\u002Fapi",[196,2710,521],{"class":202},[196,2712,2456],{"class":202},[196,2714,2715],{"class":219},"Use",[196,2717,223],{"class":202},[196,2719,564],{"class":316},[196,2721,503],{"class":202},[196,2723,2724],{"class":219},"JWTMiddleware",[196,2726,223],{"class":202},[196,2728,574],{"class":316},[196,2730,577],{"class":202},[196,2732,2733,2736,2738,2740,2742,2744,2746,2748,2751,2753,2755,2757,2759,2761,2763,2766,2768,2770],{"class":198,"line":216},[196,2734,2735],{"class":316},"open ",[196,2737,497],{"class":202},[196,2739,2696],{"class":316},[196,2741,503],{"class":202},[196,2743,2701],{"class":219},[196,2745,223],{"class":202},[196,2747,521],{"class":202},[196,2749,2750],{"class":325},"\u002Fpublic",[196,2752,521],{"class":202},[196,2754,2456],{"class":202},[196,2756,2715],{"class":219},[196,2758,223],{"class":202},[196,2760,564],{"class":316},[196,2762,503],{"class":202},[196,2764,2765],{"class":219},"OptionalJWTMiddleware",[196,2767,223],{"class":202},[196,2769,574],{"class":316},[196,2771,577],{"class":202},[2773,2774,2775,2788],"table",{},[2776,2777,2778],"thead",{},[2779,2780,2781,2785],"tr",{},[2782,2783,2784],"th",{},"Helper",[2782,2786,2787],{},"Behaviour",[2789,2790,2791,2804],"tbody",{},[2779,2792,2793,2799],{},[2794,2795,2796],"td",{},[182,2797,2798],{},"auth.JWTMiddleware(provider)",[2794,2800,2801,2802],{},"Rejects a missing or invalid token with ",[182,2803,2680],{},[2779,2805,2806,2811],{},[2794,2807,2808],{},[182,2809,2810],{},"auth.OptionalJWTMiddleware(provider)",[2794,2812,2813],{},"Continues without a user when the token is missing or invalid",[178,2815,2816,2817,2820,2821,1132,2824,1153,2827,2830,2831,2834],{},"Both put the claims and a ",[182,2818,2819],{},"*auth.BasicUser"," on the request context, readable with ",[182,2822,2823],{},"auth.GetClaims(ctx)",[182,2825,2826],{},"auth.GetUserID(ctx)",[182,2828,2829],{},"auth.UserFromContext(ctx)",". Note that these middlewares reply with plain text and do not consult route rules, so combine them with checks in your handlers, or set ",[182,2832,2833],{},"DefaultAuth(nil)"," and keep route rules for the app-level provider.",[293,2836,2838],{"id":2837},"next-steps","Next steps",[2840,2841,2842,2848],"ul",{},[2843,2844,2845,2847],"li",{},[1335,2846,1337],{"href":90}," to authorize from your own data.",[2843,2849,2850,2853],{},[1335,2851,2852],{"href":95},"Audit logging"," to record authentication failures.",[2855,2856,2857],"style",{},"html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}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 .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}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 .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 .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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}",{"title":192,"searchDepth":216,"depth":216,"links":2859},[2860,2861,2862,2863,2864,2865,2866],{"id":260,"depth":216,"text":240},{"id":477,"depth":216,"text":478},{"id":1039,"depth":216,"text":1040},{"id":1350,"depth":216,"text":1351},{"id":1993,"depth":216,"text":1994},{"id":2673,"depth":216,"text":2674},{"id":2837,"depth":216,"text":2838},"Issue and validate HS256 tokens, validate GoTrue tokens, or plug in your own credential scheme.","md",null,{},{"icon":87},{"title":84,"description":2867},"TQhLa7ILWeOKeUygKu7GQHe1mZDgX2Dlx20KUqz4Ens",[2875,2877],{"title":79,"path":80,"stem":81,"description":2876,"icon":82,"children":-1},"Require authentication, roles, permissions, or your own predicate, per route or per group.",{"title":89,"path":90,"stem":91,"description":2878,"icon":92,"children":-1},"Load a caller's roles and permissions from your own data with an authorization resolver, and cache the result.",1784970047938]