[{"data":1,"prerenderedAt":1467},["ShallowReactive",2],{"navigation_docs":3,"-gotrue-proxy":172,"-gotrue-proxy-surround":1462},[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":105,"body":174,"description":1455,"extension":1456,"links":1457,"meta":1458,"navigation":1459,"path":106,"seo":1460,"stem":107,"__hash__":1461},"docs\u002F4.gotrue\u002F1.proxy.md",{"type":175,"value":176,"toc":1443},"minimark",[177,181,184,189,385,396,400,524,535,539,553,641,653,657,662,747,750,754,760,887,901,904,961,965,975,1071,1075,1081,1192,1195,1199,1202,1373,1377,1380,1408,1417,1421,1439],[178,179,180],"p",{},"GoTrue (the auth server behind Supabase Auth) is normally exposed directly to browsers. ezz can front it instead: GoTrue stays on an internal address, your service is the only public door, and the auth endpoints become typed routes that appear in your OpenAPI document alongside everything else.",[178,182,183],{},"You get one object that does both jobs. It validates the tokens GoTrue issues, and it proxies the endpoints clients need.",[185,186,188],"h2",{"id":187},"set-it-up","Set it up",[190,191,196],"pre",{"className":192,"code":193,"language":194,"meta":195,"style":195},"language-go shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","gt := auth.NewGoTrue(auth.GoTrueConfig{\n    InternalURL: \"http:\u002F\u002Fgotrue:9999\",              \u002F\u002F never publicly routable\n    JWTSecret:   os.Getenv(\"GOTRUE_JWT_SECRET\"),    \u002F\u002F the same secret GoTrue signs with\n    AuditLogger: auth.NewSlogAuditLogger(nil),\n})\n\napp := ezz.New().Auth(gt.AuthProvider())\ngt.Mount(app, \"\u002Fauth\")\n","go","",[197,198,199,237,263,294,312,318,325,359],"code",{"__ignoreMap":195},[200,201,204,208,212,215,218,222,225,229,231,234],"span",{"class":202,"line":203},"line",1,[200,205,207],{"class":206},"sTEyZ","gt ",[200,209,211],{"class":210},"sMK4o",":=",[200,213,214],{"class":206}," auth",[200,216,217],{"class":210},".",[200,219,221],{"class":220},"s2Zo4","NewGoTrue",[200,223,224],{"class":210},"(",[200,226,228],{"class":227},"sBMFI","auth",[200,230,217],{"class":210},[200,232,233],{"class":227},"GoTrueConfig",[200,235,236],{"class":210},"{\n",[200,238,240,243,246,249,253,256,259],{"class":202,"line":239},2,[200,241,242],{"class":206},"    InternalURL",[200,244,245],{"class":210},":",[200,247,248],{"class":210}," \"",[200,250,252],{"class":251},"sfazB","http:\u002F\u002Fgotrue:9999",[200,254,255],{"class":210},"\"",[200,257,258],{"class":210},",",[200,260,262],{"class":261},"sHwdD","              \u002F\u002F never publicly routable\n",[200,264,266,269,271,274,276,279,281,283,286,288,291],{"class":202,"line":265},3,[200,267,268],{"class":206},"    JWTSecret",[200,270,245],{"class":210},[200,272,273],{"class":206},"   os",[200,275,217],{"class":210},[200,277,278],{"class":220},"Getenv",[200,280,224],{"class":210},[200,282,255],{"class":210},[200,284,285],{"class":251},"GOTRUE_JWT_SECRET",[200,287,255],{"class":210},[200,289,290],{"class":210},"),",[200,292,293],{"class":261},"    \u002F\u002F the same secret GoTrue signs with\n",[200,295,297,300,302,304,306,309],{"class":202,"line":296},4,[200,298,299],{"class":206},"    AuditLogger",[200,301,245],{"class":210},[200,303,214],{"class":206},[200,305,217],{"class":210},[200,307,308],{"class":220},"NewSlogAuditLogger",[200,310,311],{"class":210},"(nil),\n",[200,313,315],{"class":202,"line":314},5,[200,316,317],{"class":210},"})\n",[200,319,321],{"class":202,"line":320},6,[200,322,324],{"emptyLinePlaceholder":323},true,"\n",[200,326,328,331,333,336,338,341,344,346,348,351,353,356],{"class":202,"line":327},7,[200,329,330],{"class":206},"app ",[200,332,211],{"class":210},[200,334,335],{"class":206}," ezz",[200,337,217],{"class":210},[200,339,340],{"class":220},"New",[200,342,343],{"class":210},"().",[200,345,68],{"class":220},[200,347,224],{"class":210},[200,349,350],{"class":206},"gt",[200,352,217],{"class":210},[200,354,355],{"class":220},"AuthProvider",[200,357,358],{"class":210},"())\n",[200,360,362,364,366,369,371,374,376,378,380,382],{"class":202,"line":361},8,[200,363,350],{"class":206},[200,365,217],{"class":210},[200,367,368],{"class":220},"Mount",[200,370,224],{"class":210},[200,372,373],{"class":206},"app",[200,375,258],{"class":210},[200,377,248],{"class":210},[200,379,70],{"class":251},[200,381,255],{"class":210},[200,383,384],{"class":210},")\n",[178,386,387,388,391,392,395],{},"That is the whole integration. Clients now call ",[197,389,390],{},"POST \u002Fauth\u002Ftoken"," instead of GoTrue's ",[197,393,394],{},"POST \u002Ftoken",", and your protected routes accept the resulting bearer token.",[185,397,399],{"id":398},"configuration","Configuration",[401,402,403,419],"table",{},[404,405,406],"thead",{},[407,408,409,413,416],"tr",{},[410,411,412],"th",{},"Field",[410,414,415],{},"Required",[410,417,418],{},"Purpose",[420,421,422,444,456,473,485,500,512],"tbody",{},[407,423,424,430,433],{},[425,426,427],"td",{},[197,428,429],{},"InternalURL",[425,431,432],{},"yes",[425,434,435,436,439,440,443],{},"Absolute ",[197,437,438],{},"http"," or ",[197,441,442],{},"https"," URL of the GoTrue server",[407,445,446,451,453],{},[425,447,448],{},[197,449,450],{},"JWTSecret",[425,452,432],{},[425,454,455],{},"Shared with GoTrue, used to validate incoming tokens",[407,457,458,463,466],{},[425,459,460],{},[197,461,462],{},"AuditLogger",[425,464,465],{},"no",[425,467,468,469],{},"Records proxied calls; see ",[470,471,472],"a",{"href":95},"Audit logging",[407,474,475,480,482],{},[425,476,477],{},[197,478,479],{},"RateLimiter",[425,481,465],{},[425,483,484],{},"Throttles sensitive endpoints; nil disables it",[407,486,487,492,494],{},[425,488,489],{},[197,490,491],{},"ServerHeaders",[425,493,465],{},[425,495,496,497],{},"Headers added to every outbound request, such as ",[197,498,499],{},"apikey",[407,501,502,507,509],{},[425,503,504],{},[197,505,506],{},"HTTPClient",[425,508,465],{},[425,510,511],{},"Custom client; defaults to a 30 second timeout",[407,513,514,519,521],{},[425,515,516],{},[197,517,518],{},"TrustedProxies",[425,520,465],{},[425,522,523],{},"CIDRs or IPs of proxies in front of you; empty means edge mode",[178,525,526,528,529,531,532,534],{},[197,527,221],{}," panics on an invalid ",[197,530,429],{}," or a malformed ",[197,533,518],{}," entry, so a wiring mistake fails at startup rather than on the first login.",[185,536,538],{"id":537},"what-the-two-halves-do","What the two halves do",[178,540,541,544,545,548,549,552],{},[197,542,543],{},"gt.AuthProvider()"," returns a ",[197,546,547],{},"*auth.JWTAuthProvider"," backed by GoTrue's claim layout. It is the value you hand to ",[197,550,551],{},"app.Auth(...)",", and it takes the same options as any other JWT provider:",[190,554,556],{"className":192,"code":555,"language":194,"meta":195,"style":195},"app := ezz.New().Auth(\n    gt.AuthProvider().WithResolver(auth.Cached(myResolver{db: db}, 5*time.Minute)),\n)\n",[197,557,558,577,637],{"__ignoreMap":195},[200,559,560,562,564,566,568,570,572,574],{"class":202,"line":203},[200,561,330],{"class":206},[200,563,211],{"class":210},[200,565,335],{"class":206},[200,567,217],{"class":210},[200,569,340],{"class":220},[200,571,343],{"class":210},[200,573,68],{"class":220},[200,575,576],{"class":210},"(\n",[200,578,579,582,584,586,588,591,593,595,597,600,602,605,608,611,613,616,619,623,626,629,631,634],{"class":202,"line":239},[200,580,581],{"class":206},"    gt",[200,583,217],{"class":210},[200,585,355],{"class":220},[200,587,343],{"class":210},[200,589,590],{"class":220},"WithResolver",[200,592,224],{"class":210},[200,594,228],{"class":206},[200,596,217],{"class":210},[200,598,599],{"class":220},"Cached",[200,601,224],{"class":210},[200,603,604],{"class":227},"myResolver",[200,606,607],{"class":210},"{",[200,609,610],{"class":206},"db",[200,612,245],{"class":210},[200,614,615],{"class":206}," db",[200,617,618],{"class":210},"},",[200,620,622],{"class":621},"sbssI"," 5",[200,624,625],{"class":210},"*",[200,627,628],{"class":206},"time",[200,630,217],{"class":210},[200,632,633],{"class":206},"Minute",[200,635,636],{"class":210},")),\n",[200,638,639],{"class":202,"line":265},[200,640,384],{"class":210},[178,642,643,646,647,650,651,217],{},[197,644,645],{},"gt.Mount(app, prefix)"," registers the proxied routes under the prefix. Every route is ",[197,648,649],{},"Public()"," at the ezz layer, because GoTrue does its own bearer-token checking on the endpoints that need it. The full list is on ",[470,652,110],{"href":111},[185,654,656],{"id":655},"what-happens-on-a-proxied-request","What happens on a proxied request",[178,658,659,660,245],{},"For a typed JSON route such as ",[197,661,390],{},[663,664,665,681,690,718,728,741],"ol",{},[666,667,668,672,673,676,677,680],"li",{},[669,670,671],"strong",{},"Bind and validate."," The request struct is bound and validated like any other ezz route, so a body missing ",[197,674,675],{},"email"," fails with ",[197,678,679],{},"400"," before GoTrue is contacted.",[666,682,683,686,687,217],{},[669,684,685],{},"Rate limit."," On sensitive routes, the configured limiter is consulted, keyed by client IP and route. Over the limit means ",[197,688,689],{},"429",[666,691,692,695,696,698,699,702,703,706,707,706,710,713,714,717],{},[669,693,694],{},"Build the outbound request."," The validated request is re-marshalled as JSON, the query string is carried over, ",[197,697,491],{}," are applied, the client's ",[197,700,701],{},"Authorization"," header is forwarded verbatim, and ",[197,704,705],{},"X-Forwarded-For",", ",[197,708,709],{},"X-Real-IP",[197,711,712],{},"X-Forwarded-Proto",", and ",[197,715,716],{},"X-Forwarded-Host"," are set from the resolved client IP.",[666,719,720,723,724,727],{},[669,721,722],{},"Forward and pass through."," On success, GoTrue's status, ",[197,725,726],{},"Content-Type",", and body are returned byte for byte.",[666,729,730,733,734,439,737,740],{},[669,731,732],{},"Normalize errors."," A ",[197,735,736],{},"4xx",[197,738,739],{},"5xx"," from GoTrue is rewritten into ezz's error shape.",[666,742,743,746],{},[669,744,745],{},"Audit."," Success or failure is recorded, when an audit logger is configured.",[178,748,749],{},"The response types exist for documentation, not for filtering. Because the body is passed through unchanged, fields ezz does not model still reach the client, so a GoTrue upgrade that adds a field does not require a change here.",[185,751,753],{"id":752},"error-responses","Error responses",[178,755,756,757,245],{},"GoTrue error bodies are folded into the standard shape, keeping the original as ",[197,758,759],{},"details",[190,761,765],{"className":762,"code":763,"language":764,"meta":195,"style":195},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"error\": true,\n  \"message\": \"Invalid login credentials\",\n  \"status\": 400,\n  \"details\": {\n    \"error_code\": \"invalid_credentials\",\n    \"msg\": \"Invalid login credentials\"\n  }\n}\n","json",[197,766,767,771,787,808,824,837,858,876,881],{"__ignoreMap":195},[200,768,769],{"class":202,"line":203},[200,770,236],{"class":210},[200,772,773,776,780,782,784],{"class":202,"line":239},[200,774,775],{"class":210},"  \"",[200,777,779],{"class":778},"spNyl","error",[200,781,255],{"class":210},[200,783,245],{"class":210},[200,785,786],{"class":210}," true,\n",[200,788,789,791,794,796,798,800,803,805],{"class":202,"line":265},[200,790,775],{"class":210},[200,792,793],{"class":778},"message",[200,795,255],{"class":210},[200,797,245],{"class":210},[200,799,248],{"class":210},[200,801,802],{"class":251},"Invalid login credentials",[200,804,255],{"class":210},[200,806,807],{"class":210},",\n",[200,809,810,812,815,817,819,822],{"class":202,"line":296},[200,811,775],{"class":210},[200,813,814],{"class":778},"status",[200,816,255],{"class":210},[200,818,245],{"class":210},[200,820,821],{"class":621}," 400",[200,823,807],{"class":210},[200,825,826,828,830,832,834],{"class":202,"line":314},[200,827,775],{"class":210},[200,829,759],{"class":778},[200,831,255],{"class":210},[200,833,245],{"class":210},[200,835,836],{"class":210}," {\n",[200,838,839,842,845,847,849,851,854,856],{"class":202,"line":320},[200,840,841],{"class":210},"    \"",[200,843,844],{"class":227},"error_code",[200,846,255],{"class":210},[200,848,245],{"class":210},[200,850,248],{"class":210},[200,852,853],{"class":251},"invalid_credentials",[200,855,255],{"class":210},[200,857,807],{"class":210},[200,859,860,862,865,867,869,871,873],{"class":202,"line":327},[200,861,841],{"class":210},[200,863,864],{"class":227},"msg",[200,866,255],{"class":210},[200,868,245],{"class":210},[200,870,248],{"class":210},[200,872,802],{"class":251},[200,874,875],{"class":210},"\"\n",[200,877,878],{"class":202,"line":361},[200,879,880],{"class":210},"  }\n",[200,882,884],{"class":202,"line":883},9,[200,885,886],{"class":210},"}\n",[178,888,889,890,706,892,706,895,897,898,900],{},"The message is taken from the first of ",[197,891,864],{},[197,893,894],{},"error_description",[197,896,779],{},", or ",[197,899,793],{}," present in GoTrue's body, falling back to the standard status text.",[178,902,903],{},"If GoTrue cannot be reached at all, the response is:",[190,905,907],{"className":762,"code":906,"language":764,"meta":195,"style":195},"{\n  \"error\": true,\n  \"message\": \"auth service unavailable\",\n  \"status\": 502\n}\n",[197,908,909,913,925,944,957],{"__ignoreMap":195},[200,910,911],{"class":202,"line":203},[200,912,236],{"class":210},[200,914,915,917,919,921,923],{"class":202,"line":239},[200,916,775],{"class":210},[200,918,779],{"class":778},[200,920,255],{"class":210},[200,922,245],{"class":210},[200,924,786],{"class":210},[200,926,927,929,931,933,935,937,940,942],{"class":202,"line":265},[200,928,775],{"class":210},[200,930,793],{"class":778},[200,932,255],{"class":210},[200,934,245],{"class":210},[200,936,248],{"class":210},[200,938,939],{"class":251},"auth service unavailable",[200,941,255],{"class":210},[200,943,807],{"class":210},[200,945,946,948,950,952,954],{"class":202,"line":296},[200,947,775],{"class":210},[200,949,814],{"class":778},[200,951,255],{"class":210},[200,953,245],{"class":210},[200,955,956],{"class":621}," 502\n",[200,958,959],{"class":202,"line":314},[200,960,886],{"class":210},[185,962,964],{"id":963},"reach-gotrues-protected-endpoints","Reach GoTrue's protected endpoints",[178,966,967,968,971,972,974],{},"Endpoints like ",[197,969,970],{},"GET \u002Fauth\u002Fuser"," need the caller's token. Because the ",[197,973,701],{}," header is forwarded verbatim, the client just sends it as usual:",[190,976,981],{"className":977,"code":978,"filename":979,"language":980,"meta":195,"style":195},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","TOKEN=$(curl -s localhost:8080\u002Fauth\u002Ftoken?grant_type=password \\\n  -H 'Content-Type: application\u002Fjson' \\\n  -d '{\"email\":\"ada@example.com\",\"password\":\"password123\"}' | jq -r .access_token)\n\ncurl -s localhost:8080\u002Fauth\u002Fuser -H \"Authorization: Bearer $TOKEN\"\n","Terminal","bash",[197,982,983,1003,1019,1045,1049],{"__ignoreMap":195},[200,984,985,988,991,994,997,1000],{"class":202,"line":203},[200,986,987],{"class":206},"TOKEN",[200,989,990],{"class":210},"=$(",[200,992,993],{"class":227},"curl",[200,995,996],{"class":251}," -s",[200,998,999],{"class":251}," localhost:8080\u002Fauth\u002Ftoken?grant_type=password",[200,1001,1002],{"class":206}," \\\n",[200,1004,1005,1008,1011,1014,1017],{"class":202,"line":239},[200,1006,1007],{"class":251},"  -H",[200,1009,1010],{"class":210}," '",[200,1012,1013],{"class":251},"Content-Type: application\u002Fjson",[200,1015,1016],{"class":210},"'",[200,1018,1002],{"class":206},[200,1020,1021,1024,1026,1029,1031,1034,1037,1040,1043],{"class":202,"line":265},[200,1022,1023],{"class":251},"  -d",[200,1025,1010],{"class":210},[200,1027,1028],{"class":251},"{\"email\":\"ada@example.com\",\"password\":\"password123\"}",[200,1030,1016],{"class":210},[200,1032,1033],{"class":210}," |",[200,1035,1036],{"class":227}," jq",[200,1038,1039],{"class":251}," -r",[200,1041,1042],{"class":251}," .access_token",[200,1044,384],{"class":210},[200,1046,1047],{"class":202,"line":296},[200,1048,324],{"emptyLinePlaceholder":323},[200,1050,1051,1053,1055,1058,1061,1063,1066,1069],{"class":202,"line":314},[200,1052,993],{"class":227},[200,1054,996],{"class":251},[200,1056,1057],{"class":251}," localhost:8080\u002Fauth\u002Fuser",[200,1059,1060],{"class":251}," -H",[200,1062,248],{"class":210},[200,1064,1065],{"class":251},"Authorization: Bearer ",[200,1067,1068],{"class":206},"$TOKEN",[200,1070,875],{"class":210},[185,1072,1074],{"id":1073},"add-a-service-key","Add a service key",[178,1076,1077,1078,1080],{},"If your GoTrue deployment expects an ",[197,1079,499],{}," header or another shared header, set it once:",[190,1082,1084],{"className":192,"code":1083,"language":194,"meta":195,"style":195},"gt := auth.NewGoTrue(auth.GoTrueConfig{\n    InternalURL: \"http:\u002F\u002Fgotrue:9999\",\n    JWTSecret:   secret,\n    ServerHeaders: map[string]string{\n        \"apikey\": os.Getenv(\"SUPABASE_ANON_KEY\"),\n    },\n})\n",[197,1085,1086,1108,1122,1133,1153,1183,1188],{"__ignoreMap":195},[200,1087,1088,1090,1092,1094,1096,1098,1100,1102,1104,1106],{"class":202,"line":203},[200,1089,207],{"class":206},[200,1091,211],{"class":210},[200,1093,214],{"class":206},[200,1095,217],{"class":210},[200,1097,221],{"class":220},[200,1099,224],{"class":210},[200,1101,228],{"class":227},[200,1103,217],{"class":210},[200,1105,233],{"class":227},[200,1107,236],{"class":210},[200,1109,1110,1112,1114,1116,1118,1120],{"class":202,"line":239},[200,1111,242],{"class":206},[200,1113,245],{"class":210},[200,1115,248],{"class":210},[200,1117,252],{"class":251},[200,1119,255],{"class":210},[200,1121,807],{"class":210},[200,1123,1124,1126,1128,1131],{"class":202,"line":265},[200,1125,268],{"class":206},[200,1127,245],{"class":210},[200,1129,1130],{"class":206},"   secret",[200,1132,807],{"class":210},[200,1134,1135,1138,1140,1143,1146,1149,1151],{"class":202,"line":296},[200,1136,1137],{"class":206},"    ServerHeaders",[200,1139,245],{"class":210},[200,1141,1142],{"class":210}," map[",[200,1144,1145],{"class":778},"string",[200,1147,1148],{"class":210},"]",[200,1150,1145],{"class":778},[200,1152,236],{"class":210},[200,1154,1155,1158,1160,1162,1164,1167,1169,1171,1173,1175,1178,1180],{"class":202,"line":314},[200,1156,1157],{"class":210},"        \"",[200,1159,499],{"class":251},[200,1161,255],{"class":210},[200,1163,245],{"class":210},[200,1165,1166],{"class":206}," os",[200,1168,217],{"class":210},[200,1170,278],{"class":220},[200,1172,224],{"class":210},[200,1174,255],{"class":210},[200,1176,1177],{"class":251},"SUPABASE_ANON_KEY",[200,1179,255],{"class":210},[200,1181,1182],{"class":210},"),\n",[200,1184,1185],{"class":202,"line":320},[200,1186,1187],{"class":210},"    },\n",[200,1189,1190],{"class":202,"line":327},[200,1191,317],{"class":210},[178,1193,1194],{},"These headers are added to typed forwards and to the raw redirect routes, and they never appear in responses.",[185,1196,1198],{"id":1197},"tune-the-http-client","Tune the HTTP client",[178,1200,1201],{},"The default client has a 30 second timeout and the standard transport. For a busy service, give it a connection pool sized for your traffic:",[190,1203,1205],{"className":192,"code":1204,"language":194,"meta":195,"style":195},"gt := auth.NewGoTrue(auth.GoTrueConfig{\n    InternalURL: \"http:\u002F\u002Fgotrue:9999\",\n    JWTSecret:   secret,\n    HTTPClient: &http.Client{\n        Timeout: 10 * time.Second,\n        Transport: &http.Transport{\n            MaxIdleConns:        100,\n            MaxIdleConnsPerHost: 100,\n            IdleConnTimeout:     90 * time.Second,\n        },\n    },\n})\n",[197,1206,1207,1229,1243,1253,1272,1295,1313,1325,1337,1357,1363,1368],{"__ignoreMap":195},[200,1208,1209,1211,1213,1215,1217,1219,1221,1223,1225,1227],{"class":202,"line":203},[200,1210,207],{"class":206},[200,1212,211],{"class":210},[200,1214,214],{"class":206},[200,1216,217],{"class":210},[200,1218,221],{"class":220},[200,1220,224],{"class":210},[200,1222,228],{"class":227},[200,1224,217],{"class":210},[200,1226,233],{"class":227},[200,1228,236],{"class":210},[200,1230,1231,1233,1235,1237,1239,1241],{"class":202,"line":239},[200,1232,242],{"class":206},[200,1234,245],{"class":210},[200,1236,248],{"class":210},[200,1238,252],{"class":251},[200,1240,255],{"class":210},[200,1242,807],{"class":210},[200,1244,1245,1247,1249,1251],{"class":202,"line":265},[200,1246,268],{"class":206},[200,1248,245],{"class":210},[200,1250,1130],{"class":206},[200,1252,807],{"class":210},[200,1254,1255,1258,1260,1263,1265,1267,1270],{"class":202,"line":296},[200,1256,1257],{"class":206},"    HTTPClient",[200,1259,245],{"class":210},[200,1261,1262],{"class":210}," &",[200,1264,438],{"class":227},[200,1266,217],{"class":210},[200,1268,1269],{"class":227},"Client",[200,1271,236],{"class":210},[200,1273,1274,1277,1279,1282,1285,1288,1290,1293],{"class":202,"line":314},[200,1275,1276],{"class":206},"        Timeout",[200,1278,245],{"class":210},[200,1280,1281],{"class":621}," 10",[200,1283,1284],{"class":210}," *",[200,1286,1287],{"class":206}," time",[200,1289,217],{"class":210},[200,1291,1292],{"class":206},"Second",[200,1294,807],{"class":210},[200,1296,1297,1300,1302,1304,1306,1308,1311],{"class":202,"line":320},[200,1298,1299],{"class":206},"        Transport",[200,1301,245],{"class":210},[200,1303,1262],{"class":210},[200,1305,438],{"class":227},[200,1307,217],{"class":210},[200,1309,1310],{"class":227},"Transport",[200,1312,236],{"class":210},[200,1314,1315,1318,1320,1323],{"class":202,"line":327},[200,1316,1317],{"class":206},"            MaxIdleConns",[200,1319,245],{"class":210},[200,1321,1322],{"class":621},"        100",[200,1324,807],{"class":210},[200,1326,1327,1330,1332,1335],{"class":202,"line":361},[200,1328,1329],{"class":206},"            MaxIdleConnsPerHost",[200,1331,245],{"class":210},[200,1333,1334],{"class":621}," 100",[200,1336,807],{"class":210},[200,1338,1339,1342,1344,1347,1349,1351,1353,1355],{"class":202,"line":883},[200,1340,1341],{"class":206},"            IdleConnTimeout",[200,1343,245],{"class":210},[200,1345,1346],{"class":621},"     90",[200,1348,1284],{"class":210},[200,1350,1287],{"class":206},[200,1352,217],{"class":210},[200,1354,1292],{"class":206},[200,1356,807],{"class":210},[200,1358,1360],{"class":202,"line":1359},10,[200,1361,1362],{"class":210},"        },\n",[200,1364,1366],{"class":202,"line":1365},11,[200,1367,1187],{"class":210},[200,1369,1371],{"class":202,"line":1370},12,[200,1372,317],{"class":210},[185,1374,1376],{"id":1375},"mount-under-a-different-prefix","Mount under a different prefix",[178,1378,1379],{},"The prefix is yours to choose, and a trailing slash is trimmed:",[190,1381,1383],{"className":192,"code":1382,"language":194,"meta":195,"style":195},"gt.Mount(app, \"\u002Fapi\u002Fauth\")\n",[197,1384,1385],{"__ignoreMap":195},[200,1386,1387,1389,1391,1393,1395,1397,1399,1401,1404,1406],{"class":202,"line":203},[200,1388,350],{"class":206},[200,1390,217],{"class":210},[200,1392,368],{"class":220},[200,1394,224],{"class":210},[200,1396,373],{"class":206},[200,1398,258],{"class":210},[200,1400,248],{"class":210},[200,1402,1403],{"class":251},"\u002Fapi\u002Fauth",[200,1405,255],{"class":210},[200,1407,384],{"class":210},[178,1409,1410,1411,1414,1415,217],{},"Whatever you choose has to match GoTrue's ",[197,1412,1413],{},"API_EXTERNAL_URL",", because GoTrue builds email links and OAuth metadata from it. See ",[470,1416,120],{"href":121},[185,1418,1420],{"id":1419},"next-steps","Next steps",[1422,1423,1424,1428,1432,1435],"card-group",{},[1425,1426,1427],"card",{"icon":113,"title":110,"to":111},"Every proxied route, its types, and which ones are rate limited.",[1425,1429,1431],{"icon":118,"title":1430,"to":116},"Client IP and rate limits","Trusted proxies, real client IPs, and the Redis limiter.",[1425,1433,1434],{"icon":123,"title":120,"to":121},"GoTrue settings that have to match, and the fixture harness.",[1425,1436,1438],{"icon":92,"title":1437,"to":90},"Roles and permissions","Why GoTrue's role claim is not an application role.",[1440,1441,1442],"style",{},"html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html 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 .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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}",{"title":195,"searchDepth":239,"depth":239,"links":1444},[1445,1446,1447,1448,1449,1450,1451,1452,1453,1454],{"id":187,"depth":239,"text":188},{"id":398,"depth":239,"text":399},{"id":537,"depth":239,"text":538},{"id":655,"depth":239,"text":656},{"id":752,"depth":239,"text":753},{"id":963,"depth":239,"text":964},{"id":1073,"depth":239,"text":1074},{"id":1197,"depth":239,"text":1198},{"id":1375,"depth":239,"text":1376},{"id":1419,"depth":239,"text":1420},"Keep GoTrue on a private network and expose typed, documented \u002Fauth\u002F* routes through your own service.","md",null,{},{"icon":108},{"title":105,"description":1455},"JlhHVQsPRNsQdL4ofvSe7Epj4hIhsdfSq2aUiADyR-g",[1463,1465],{"title":94,"path":95,"stem":96,"description":1464,"icon":97,"children":-1},"Record authentication and authorization events through a pluggable audit logger.",{"title":110,"path":111,"stem":112,"description":1466,"icon":113,"children":-1},"Every route gt.Mount registers, with its request and response types.",1784970045269]