[{"data":1,"prerenderedAt":859},["ShallowReactive",2],{"navigation_docs":3,"-guide-auth":80,"-guide-auth-surround":854},[4,56],{"title":5,"path":6,"stem":7,"children":8,"icon":55},"Guide","\u002Fguide","1.guide\u002F01.index",[9,11,15,19,23,27,31,35,39,43,47,51],{"title":10,"path":6,"stem":7},"Getting Started",{"title":12,"path":13,"stem":14},"Authentication","\u002Fguide\u002Fauth","1.guide\u002F02.auth",{"title":16,"path":17,"stem":18},"Repositories","\u002Fguide\u002Frepositories","1.guide\u002F03.repositories",{"title":20,"path":21,"stem":22},"Issues","\u002Fguide\u002Fissues","1.guide\u002F04.issues",{"title":24,"path":25,"stem":26},"Pull requests","\u002Fguide\u002Fpull-requests","1.guide\u002F05.pull-requests",{"title":28,"path":29,"stem":30},"Review threads","\u002Fguide\u002Fthreads","1.guide\u002F06.threads",{"title":32,"path":33,"stem":34},"Commits and CI","\u002Fguide\u002Fcommits","1.guide\u002F07.commits",{"title":36,"path":37,"stem":38},"Contribution templates","\u002Fguide\u002Ftemplates","1.guide\u002F08.templates",{"title":40,"path":41,"stem":42},"Code search","\u002Fguide\u002Fcode-search","1.guide\u002F09.code-search",{"title":44,"path":45,"stem":46},"Agents","\u002Fguide\u002Fagents","1.guide\u002F10.agents",{"title":48,"path":49,"stem":50},"Custom providers","\u002Fguide\u002Fcustom","1.guide\u002F11.custom",{"title":52,"path":53,"stem":54},"Explorer","\u002Fguide\u002Fexplorer","1.guide\u002F12.explorer","i-lucide-book-open",{"title":57,"path":58,"stem":59,"children":60,"icon":79},"Platforms","\u002Fplatforms","2.platforms\u002F0.index",[61,63,67,71,75],{"title":62,"path":58,"stem":59},"Overview",{"title":64,"path":65,"stem":66},"GitHub","\u002Fplatforms\u002Fgithub","2.platforms\u002F01.github",{"title":68,"path":69,"stem":70},"GitLab","\u002Fplatforms\u002Fgitlab","2.platforms\u002F02.gitlab",{"title":72,"path":73,"stem":74},"Gitea","\u002Fplatforms\u002Fgitea","2.platforms\u002F03.gitea",{"title":76,"path":77,"stem":78},"GitBucket","\u002Fplatforms\u002Fgitbucket","2.platforms\u002F04.gitbucket","i-lucide-library",{"id":81,"title":12,"body":82,"description":847,"extension":848,"links":849,"meta":850,"navigation":284,"path":13,"seo":852,"stem":14,"__hash__":853},"docs\u002F1.guide\u002F02.auth.md",{"type":83,"value":84,"toc":839},"minimark",[85,90,98,207,221,232,320,326,330,338,420,438,442,674,681,685,744,747,751,754,794,797,801,835],[86,87,89],"h2",{"id":88},"the-chain","The chain",[91,92,93,97],"p",{},[94,95,96],"code",{},"createProvider(platform, config?)"," looks for a token in four places and stops at the first hit:",[99,100,101,117],"table",{},[102,103,104],"thead",{},[105,106,107,111,113,115],"tr",{},[108,109,110],"th",{},"Step",[108,112,64],{},[108,114,68],{},[108,116,72],{},[118,119,120,139,169,187],"tbody",{},[105,121,122,126,131,135],{},[123,124,125],"td",{},"1. explicit",[123,127,128],{},[94,129,130],{},"{ token }",[123,132,133],{},[94,134,130],{},[123,136,137],{},[94,138,130],{},[105,140,141,144,153,164],{},[123,142,143],{},"2. env",[123,145,146,149,150],{},[94,147,148],{},"GH_TOKEN",", ",[94,151,152],{},"GITHUB_TOKEN",[123,154,155,149,158,149,161],{},[94,156,157],{},"GITLAB_TOKEN",[94,159,160],{},"GL_TOKEN",[94,162,163],{},"GITLAB_PAT",[123,165,166],{},[94,167,168],{},"GITEA_TOKEN",[105,170,171,174,179,184],{},[123,172,173],{},"3. CLI",[123,175,176],{},[94,177,178],{},"gh auth token --hostname \u003Chost>",[123,180,181],{},[94,182,183],{},"glab config get token --host \u003Chost>",[123,185,186],{},"none",[105,188,189,192,197,202],{},[123,190,191],{},"4. config file",[123,193,194],{},[94,195,196],{},"~\u002F.config\u002Fgh\u002Fhosts.yml",[123,198,199],{},[94,200,201],{},"~\u002F.config\u002Fglab-cli\u002Fconfig.yml",[123,203,204],{},[94,205,206],{},"~\u002F.config\u002Ftea\u002Fconfig.yml",[91,208,209,210,213,214,216,217,220],{},"Steps 3 and 4 use the hostname from ",[94,211,212],{},"baseURL",", or the platform default. So a GitHub Enterprise ",[94,215,212],{}," asks ",[94,218,219],{},"gh"," for that host's token, not for github.com's. Small thing, saves a confusing 401.",[91,222,223,224,227,228,231],{},"When nothing matches, ",[94,225,226],{},"createProvider"," throws ",[94,229,230],{},"AuthenticationError"," and tells you which env var to set and which login to run. It never goes anonymous behind your back.",[233,234,239],"pre",{"className":235,"code":236,"language":237,"meta":238,"style":238},"language-ts shiki shiki-themes github-light github-light poimandres","import { resolveToken } from \"@agntn\u002Fforges\";\n\nconst found = resolveToken(\"github\"); \u002F\u002F { token, source: \"env\" | \"cli\" | \"config\" | \"explicit\" } or null\n","ts","",[94,240,241,279,286],{"__ignoreMap":238},[242,243,246,250,254,258,261,265,269,273,276],"span",{"class":244,"line":245},"line",1,[242,247,249],{"class":248},"sP0CR","import",[242,251,253],{"class":252},"sKlNE"," {",[242,255,257],{"class":256},"snHMy"," resolveToken",[242,259,260],{"class":252}," }",[242,262,264],{"class":263},"stCPd"," from",[242,266,268],{"class":267},"scVjq"," \"",[242,270,272],{"class":271},"sQ7BG","@agntn\u002Fforges",[242,274,275],{"class":267},"\"",[242,277,278],{"class":252},";\n",[242,280,282],{"class":244,"line":281},2,[242,283,285],{"emptyLinePlaceholder":284},true,"\n",[242,287,289,293,297,300,303,306,308,311,313,316],{"class":244,"line":288},3,[242,290,292],{"class":291},"s1TYA","const",[242,294,296],{"class":295},"saoiD"," found",[242,298,299],{"class":291}," =",[242,301,257],{"class":302},"sULi6",[242,304,305],{"class":252},"(",[242,307,275],{"class":267},[242,309,310],{"class":271},"github",[242,312,275],{"class":267},[242,314,315],{"class":252},"); ",[242,317,319],{"class":318},"sjhu3","\u002F\u002F { token, source: \"env\" | \"cli\" | \"config\" | \"explicit\" } or null\n",[91,321,322,325],{},[94,323,324],{},"resolveToken"," is the same chain without a provider. Handy as a preflight check.",[86,327,329],{"id":328},"anonymous-on-purpose","Anonymous on purpose",[91,331,332,333,337],{},"An empty string is a real token here. It means ",[334,335,336],"em",{},"make unauthenticated calls",":",[233,339,341],{"className":235,"code":340,"language":237,"meta":238,"style":238},"const anonymous = createProvider(\"github\", { token: \"\" });\nawait anonymous.repos.get(\"nitrojs\", \"nitro\"); \u002F\u002F public data, 60 requests an hour per address\n",[94,342,343,377],{"__ignoreMap":238},[242,344,345,347,350,352,355,357,359,361,363,366,369,371,374],{"class":244,"line":245},[242,346,292],{"class":291},[242,348,349],{"class":295}," anonymous",[242,351,299],{"class":291},[242,353,354],{"class":302}," createProvider",[242,356,305],{"class":252},[242,358,275],{"class":267},[242,360,310],{"class":271},[242,362,275],{"class":267},[242,364,365],{"class":252},", {",[242,367,368],{"class":256}," token",[242,370,337],{"class":252},[242,372,373],{"class":267}," \"\"",[242,375,376],{"class":252}," });\n",[242,378,379,383,386,389,392,394,397,399,401,404,406,408,410,413,415,417],{"class":244,"line":281},[242,380,382],{"class":381},"sZW6a","await",[242,384,349],{"class":385},"spVlQ",[242,387,388],{"class":252},".",[242,390,391],{"class":385},"repos",[242,393,388],{"class":252},[242,395,396],{"class":302},"get",[242,398,305],{"class":252},[242,400,275],{"class":267},[242,402,403],{"class":271},"nitrojs",[242,405,275],{"class":267},[242,407,149],{"class":252},[242,409,275],{"class":267},[242,411,412],{"class":271},"nitro",[242,414,275],{"class":267},[242,416,315],{"class":252},[242,418,419],{"class":318},"\u002F\u002F public data, 60 requests an hour per address\n",[91,421,422,423,426,427,430,431,434,435,388],{},"The check inside is ",[94,424,425],{},"token !== undefined",", not a falsy check. ",[94,428,429],{},"\"\""," is a decision, ",[94,432,433],{},"undefined"," means go look. The agent tools use exactly this for reads when no credential exists, see ",[436,437,44],"a",{"href":45},[86,439,441],{"id":440},"explicit-token-and-host","Explicit token and host",[233,443,445],{"className":235,"code":444,"language":237,"meta":238,"style":238},"const github = createProvider(\"github\", { token: process.env.GITHUB_TOKEN });\n\nconst gitlab = createProvider(\"gitlab\", {\n  token: \"glpat-…\",\n  baseURL: \"https:\u002F\u002Fgitlab.example.com\", \u002F\u002F \u002Fapi\u002Fv4 is added when missing\n});\n\nconst gitea = createProvider(\"gitea\", {\n  baseURL: \"https:\u002F\u002Fcodeberg.org\", \u002F\u002F \u002Fapi\u002Fv1 is added when missing\n});\n\nconst gitbucket = createProvider(\"github\", {\n  token: \"…\",\n  baseURL: \"https:\u002F\u002Fgitbucket.example.com\u002Fapi\u002Fv3\",\n});\n",[94,446,447,486,490,513,531,552,558,563,586,605,610,615,637,653,669],{"__ignoreMap":238},[242,448,449,451,454,456,458,460,462,464,466,468,470,472,475,477,480,482,484],{"class":244,"line":245},[242,450,292],{"class":291},[242,452,453],{"class":295}," github",[242,455,299],{"class":291},[242,457,354],{"class":302},[242,459,305],{"class":252},[242,461,275],{"class":267},[242,463,310],{"class":271},[242,465,275],{"class":267},[242,467,365],{"class":252},[242,469,368],{"class":256},[242,471,337],{"class":252},[242,473,474],{"class":385}," process",[242,476,388],{"class":252},[242,478,479],{"class":385},"env",[242,481,388],{"class":252},[242,483,152],{"class":295},[242,485,376],{"class":252},[242,487,488],{"class":244,"line":281},[242,489,285],{"emptyLinePlaceholder":284},[242,491,492,494,497,499,501,503,505,508,510],{"class":244,"line":288},[242,493,292],{"class":291},[242,495,496],{"class":295}," gitlab",[242,498,299],{"class":291},[242,500,354],{"class":302},[242,502,305],{"class":252},[242,504,275],{"class":267},[242,506,507],{"class":271},"gitlab",[242,509,275],{"class":267},[242,511,512],{"class":252},", {\n",[242,514,516,519,521,523,526,528],{"class":244,"line":515},4,[242,517,518],{"class":256},"  token",[242,520,337],{"class":252},[242,522,268],{"class":267},[242,524,525],{"class":271},"glpat-…",[242,527,275],{"class":267},[242,529,530],{"class":252},",\n",[242,532,534,537,539,541,544,546,549],{"class":244,"line":533},5,[242,535,536],{"class":256},"  baseURL",[242,538,337],{"class":252},[242,540,268],{"class":267},[242,542,543],{"class":271},"https:\u002F\u002Fgitlab.example.com",[242,545,275],{"class":267},[242,547,548],{"class":252},",",[242,550,551],{"class":318}," \u002F\u002F \u002Fapi\u002Fv4 is added when missing\n",[242,553,555],{"class":244,"line":554},6,[242,556,557],{"class":252},"});\n",[242,559,561],{"class":244,"line":560},7,[242,562,285],{"emptyLinePlaceholder":284},[242,564,566,568,571,573,575,577,579,582,584],{"class":244,"line":565},8,[242,567,292],{"class":291},[242,569,570],{"class":295}," gitea",[242,572,299],{"class":291},[242,574,354],{"class":302},[242,576,305],{"class":252},[242,578,275],{"class":267},[242,580,581],{"class":271},"gitea",[242,583,275],{"class":267},[242,585,512],{"class":252},[242,587,589,591,593,595,598,600,602],{"class":244,"line":588},9,[242,590,536],{"class":256},[242,592,337],{"class":252},[242,594,268],{"class":267},[242,596,597],{"class":271},"https:\u002F\u002Fcodeberg.org",[242,599,275],{"class":267},[242,601,548],{"class":252},[242,603,604],{"class":318}," \u002F\u002F \u002Fapi\u002Fv1 is added when missing\n",[242,606,608],{"class":244,"line":607},10,[242,609,557],{"class":252},[242,611,613],{"class":244,"line":612},11,[242,614,285],{"emptyLinePlaceholder":284},[242,616,618,620,623,625,627,629,631,633,635],{"class":244,"line":617},12,[242,619,292],{"class":291},[242,621,622],{"class":295}," gitbucket",[242,624,299],{"class":291},[242,626,354],{"class":302},[242,628,305],{"class":252},[242,630,275],{"class":267},[242,632,310],{"class":271},[242,634,275],{"class":267},[242,636,512],{"class":252},[242,638,640,642,644,646,649,651],{"class":244,"line":639},13,[242,641,518],{"class":256},[242,643,337],{"class":252},[242,645,268],{"class":267},[242,647,648],{"class":271},"…",[242,650,275],{"class":267},[242,652,530],{"class":252},[242,654,656,658,660,662,665,667],{"class":244,"line":655},14,[242,657,536],{"class":256},[242,659,337],{"class":252},[242,661,268],{"class":267},[242,663,664],{"class":271},"https:\u002F\u002Fgitbucket.example.com\u002Fapi\u002Fv3",[242,666,275],{"class":267},[242,668,530],{"class":252},[242,670,672],{"class":244,"line":671},15,[242,673,557],{"class":252},[91,675,676,677,680],{},"GitLab and Gitea normalize the base URL, so the bare host works. GitHub takes the URL as given, so GitBucket and GitHub Enterprise need ",[94,678,679],{},"\u002Fapi\u002Fv3"," spelled out.",[86,682,684],{"id":683},"headers","Headers",[99,686,687,700],{},[102,688,689],{},[105,690,691,694,697],{},[108,692,693],{},"Platform",[108,695,696],{},"Header",[108,698,699],{},"Value",[118,701,702,717,731],{},[105,703,704,707,712],{},[123,705,706],{},"GitHub, GitBucket",[123,708,709],{},[94,710,711],{},"Authorization",[123,713,714],{},[94,715,716],{},"token \u003Ctoken>",[105,718,719,721,726],{},[123,720,68],{},[123,722,723],{},[94,724,725],{},"Private-Token",[123,727,728],{},[94,729,730],{},"\u003Ctoken>",[105,732,733,736,740],{},[123,734,735],{},"Gitea, Forgejo",[123,737,738],{},[94,739,711],{},[123,741,742],{},[94,743,716],{},[91,745,746],{},"You never set these. They are here so a proxy log makes sense.",[86,748,750],{"id":749},"self-hosted-endpoints-for-agents","Self hosted endpoints for agents",[91,752,753],{},"The MCP server and the extensions read one more variable per platform from the process environment:",[99,755,756,765],{},[102,757,758],{},[105,759,760,762],{},[108,761,693],{},[108,763,764],{},"Variable",[118,766,767,776,785],{},[105,768,769,771],{},[123,770,706],{},[123,772,773],{},[94,774,775],{},"FORGES_GITHUB_BASE_URL",[105,777,778,780],{},[123,779,68],{},[123,781,782],{},[94,783,784],{},"FORGES_GITLAB_BASE_URL",[105,786,787,789],{},[123,788,735],{},[123,790,791],{},[94,792,793],{},"FORGES_GITEA_BASE_URL",[91,795,796],{},"The value is the full API base URL. It is never a tool argument, so a model cannot point a call at another host. And a failure message never repeats the endpoint, so the host stays out of the model's context even when the platform answers with an error.",[86,798,800],{"id":799},"what-a-token-buys","What a token buys",[802,803,804,808,814,832],"ul",{},[805,806,807],"li",{},"The cache is keyed by base URL and a hash of the token. Two providers in one process never read each other's answers.",[805,809,810,813],{},[94,811,812],{},"users.authenticated()"," says who the token is.",[805,815,816,817,149,820,149,823,149,826,149,829,388],{},"Writes need one on every platform: ",[94,818,819],{},"issues.create",[94,821,822],{},"pullRequests.create",[94,824,825],{},"threads.reply",[94,827,828],{},"threads.resolve",[94,830,831],{},"threads.unresolve",[805,833,834],{},"GitHub review threads go through GraphQL and GraphQL has no anonymous access. GitLab discussions answer 401 without a token, even on a public project, which surprised me. Gitea review comments read fine anonymously on public repos.",[836,837,838],"style",{},"html pre.shiki code .sP0CR, html code.shiki .sP0CR{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#5DE4C7}html pre.shiki code .sKlNE, html code.shiki .sKlNE{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#A6ACCD}html pre.shiki code .snHMy, html code.shiki .snHMy{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#ADD7FF}html pre.shiki code .stCPd, html code.shiki .stCPd{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#A6ACCD}html pre.shiki code .scVjq, html code.shiki .scVjq{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#A6ACCD}html pre.shiki code .sQ7BG, html code.shiki .sQ7BG{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#5DE4C7}html pre.shiki code .s1TYA, html code.shiki .s1TYA{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#91B4D5}html pre.shiki code .saoiD, html code.shiki .saoiD{--shiki-light:#005CC5;--shiki-default:#005CC5;--shiki-dark:#E4F0FB}html pre.shiki code .sULi6, html code.shiki .sULi6{--shiki-light:#6F42C1;--shiki-default:#6F42C1;--shiki-dark:#E4F0FBD0}html pre.shiki code .sjhu3, html code.shiki .sjhu3{--shiki-light:#6A737D;--shiki-light-font-style:inherit;--shiki-default:#6A737D;--shiki-default-font-style:inherit;--shiki-dark:#767C9DB0;--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 .sZW6a, html code.shiki .sZW6a{--shiki-light:#D73A49;--shiki-default:#D73A49;--shiki-dark:#5DE4C7C0}html pre.shiki code .spVlQ, html code.shiki .spVlQ{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#E4F0FB}",{"title":238,"searchDepth":281,"depth":281,"links":840},[841,842,843,844,845,846],{"id":88,"depth":281,"text":89},{"id":328,"depth":281,"text":329},{"id":440,"depth":281,"text":441},{"id":683,"depth":281,"text":684},{"id":749,"depth":281,"text":750},{"id":799,"depth":281,"text":800},"Where the token comes from, in which order, and how to point a provider at a self hosted instance.","md",null,{"icon":851},"i-lucide-key-round",{"title":12,"description":847},"u_roxF4xTzC8taaOyuvWEI7R44k7Jv1HJSFOL5AwrVM",[855,857],{"title":10,"path":6,"stem":7,"description":856,"children":-1},"Install the package, read one repository, and get the same shape back from GitHub, GitLab, Gitea and GitBucket.",{"title":16,"path":17,"stem":18,"description":858,"children":-1},"One Repository shape from every platform, with fork state, the immediate parent and the viewer's role when the platform says.",1788525967449]