[{"data":1,"prerenderedAt":443},["ShallowReactive",2],{"navigation_docs":3,"-guide-authentication-overview":168,"-guide-authentication-overview-surround":438},[4,146],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":36},"Guide","i-lucide-book-open","\u002Fguide","1.guide",[10,14,37,55,59,63,67,71,75,79,83,87,109,134,138,142],{"title":11,"path":12,"stem":13},"What is Agent Zero?","\u002Fguide\u002Fintroduction","1.guide\u002F1.introduction",{"title":15,"icon":16,"path":17,"stem":18,"children":19,"page":36},"API","i-lucide-plug","\u002Fguide\u002Fapi","1.guide\u002F10.api",[20,24,28,32],{"title":21,"path":22,"stem":23},"API overview","\u002Fguide\u002Fapi\u002Foverview","1.guide\u002F10.api\u002F1.overview",{"title":25,"path":26,"stem":27},"Define endpoints","\u002Fguide\u002Fapi\u002Fdefine-endpoints","1.guide\u002F10.api\u002F2.define-endpoints",{"title":29,"path":30,"stem":31},"Use the API from a client","\u002Fguide\u002Fapi\u002Fuse-from-client","1.guide\u002F10.api\u002F3.use-from-client",{"title":33,"path":34,"stem":35},"Protect endpoints","\u002Fguide\u002Fapi\u002Fprotect-endpoints","1.guide\u002F10.api\u002F4.protect-endpoints",false,{"title":38,"icon":39,"path":40,"stem":41,"children":42,"page":36},"Authentication","i-lucide-lock","\u002Fguide\u002Fauthentication","1.guide\u002F11.authentication",[43,47,51],{"title":44,"path":45,"stem":46},"Authentication overview","\u002Fguide\u002Fauthentication\u002Foverview","1.guide\u002F11.authentication\u002F1.overview",{"title":48,"path":49,"stem":50},"GitHub OAuth","\u002Fguide\u002Fauthentication\u002Foauth","1.guide\u002F11.authentication\u002F2.oauth",{"title":52,"path":53,"stem":54},"Permissions","\u002Fguide\u002Fauthentication\u002Fpermissions","1.guide\u002F11.authentication\u002F3.permissions",{"title":56,"path":57,"stem":58},"Organizations","\u002Fguide\u002Forganizations","1.guide\u002F12.organizations",{"title":60,"path":61,"stem":62},"Frontend","\u002Fguide\u002Ffrontend","1.guide\u002F13.frontend",{"title":64,"path":65,"stem":66},"Mails","\u002Fguide\u002Fmails","1.guide\u002F14.mails",{"title":68,"path":69,"stem":70},"Internationalization","\u002Fguide\u002Finternationalization","1.guide\u002F15.internationalization",{"title":72,"path":73,"stem":74},"Deployment","\u002Fguide\u002Fdeployment","1.guide\u002F16.deployment",{"title":76,"path":77,"stem":78},"Tech stack","\u002Fguide\u002Ftech-stack","1.guide\u002F2.tech-stack",{"title":80,"path":81,"stem":82},"Installation","\u002Fguide\u002Finstallation","1.guide\u002F3.installation",{"title":84,"path":85,"stem":86},"Environment variables","\u002Fguide\u002Fenvironment-variables","1.guide\u002F4.environment-variables",{"title":88,"icon":89,"path":90,"stem":91,"children":92,"page":36},"Codebase","i-lucide-folder-tree","\u002Fguide\u002Fcodebase","1.guide\u002F5.codebase",[93,97,101,105],{"title":94,"path":95,"stem":96},"Codebase structure","\u002Fguide\u002Fcodebase\u002Fstructure","1.guide\u002F5.codebase\u002F1.structure",{"title":98,"path":99,"stem":100},"Dependencies","\u002Fguide\u002Fcodebase\u002Fdependencies","1.guide\u002F5.codebase\u002F2.dependencies",{"title":102,"path":103,"stem":104},"Formatting and linting","\u002Fguide\u002Fcodebase\u002Fformatting-linting","1.guide\u002F5.codebase\u002F3.formatting-linting",{"title":106,"path":107,"stem":108},"Agent Skills","\u002Fguide\u002Fcodebase\u002Fagent-skills","1.guide\u002F5.codebase\u002F4.agent-skills",{"title":110,"icon":111,"path":112,"stem":113,"children":114,"page":36},"Architecture","i-lucide-layers","\u002Fguide\u002Farchitecture","1.guide\u002F6.architecture",[115,118,122,126,130],{"title":110,"path":116,"stem":117},"\u002Fguide\u002Farchitecture\u002Foverview","1.guide\u002F6.architecture\u002F1.overview",{"title":119,"path":120,"stem":121},"State machine","\u002Fguide\u002Farchitecture\u002Fstate-machine","1.guide\u002F6.architecture\u002F2.state-machine",{"title":123,"path":124,"stem":125},"Execution boundary","\u002Fguide\u002Farchitecture\u002Fexecution-boundary","1.guide\u002F6.architecture\u002F3.execution-boundary",{"title":127,"path":128,"stem":129},"Issue-to-PR workflow","\u002Fguide\u002Farchitecture\u002Fissue-to-pr","1.guide\u002F6.architecture\u002F4.issue-to-pr",{"title":131,"path":132,"stem":133},"Adding a capability","\u002Fguide\u002Farchitecture\u002Fadding-a-capability","1.guide\u002F6.architecture\u002F5.adding-a-capability",{"title":135,"path":136,"stem":137},"Repository policy","\u002Fguide\u002Fconfiguration","1.guide\u002F7.configuration",{"title":139,"path":140,"stem":141},"Safety model","\u002Fguide\u002Fsafety","1.guide\u002F8.safety",{"title":143,"path":144,"stem":145},"Database","\u002Fguide\u002Fdatabase","1.guide\u002F9.database",{"title":147,"icon":148,"path":149,"stem":150,"children":151,"page":36},"Reference","i-lucide-book-marked","\u002Freference","2.reference",[152,156,160,164],{"title":153,"path":154,"stem":155},"CLI","\u002Freference\u002Fcli","2.reference\u002F1.cli",{"title":157,"path":158,"stem":159},"Model providers","\u002Freference\u002Fmodel-providers","2.reference\u002F2.model-providers",{"title":161,"path":162,"stem":163},"Source-control providers","\u002Freference\u002Fsource-control-providers","2.reference\u002F3.source-control-providers",{"title":165,"path":166,"stem":167},"Sandbox providers","\u002Freference\u002Fsandbox-providers","2.reference\u002F4.sandbox-providers",{"id":169,"title":44,"body":170,"description":431,"extension":432,"links":433,"meta":434,"navigation":435,"path":45,"seo":436,"stem":46,"__hash__":437},"docs\u002F1.guide\u002F11.authentication\u002F1.overview.md",{"type":171,"value":172,"toc":422},"minimark",[173,202,207,210,254,275,279,340,344,347,379,399,403,406,410],[174,175,176,177,184,185,189,190,197,198,201],"p",{},"The dashboard UI is protected by ",[178,179,183],"a",{"href":180,"rel":181},"https:\u002F\u002Fbetter-auth.com",[182],"nofollow","Better Auth",", mounted in-process at ",[186,187,188],"code",{},"\u002Fapi\u002Fauth\u002F**"," by ",[178,191,194],{"href":192,"rel":193},"https:\u002F\u002Fgithub.com\u002Fonmax\u002Fnuxt-better-auth",[182],[186,195,196],{},"@onmax\u002Fnuxt-better-auth"," from ",[186,199,200],{},"apps\u002Fdashboard\u002Fserver\u002Fauth.config.ts",".",[203,204,206],"h2",{"id":205},"the-boundary","The boundary",[174,208,209],{},"Authentication follows the adapter rule at the package level:",[211,212,213,231,244],"ul",{},[214,215,216,222,223,226,227,230],"li",{},[217,218,219],"strong",{},[186,220,221],{},"packages\u002Fauth"," holds the policy: ",[186,224,225],{},"authBetterAuthOptions"," builds the database, policy, and provider options Better Auth needs. It has no HTTP server and no runtime imports, and its ",[186,228,229],{},".\u002Fconfig"," subpath stays free of database dependencies so the login page can read feature flags without bundling one.",[214,232,233,238,239,241,242,201],{},[217,234,235],{},[186,236,237],{},"packages\u002Fdatabase"," owns the store: the Drizzle schema, the connection factory, and the checked-in migrations. It knows nothing about sign-in and must never import ",[186,240,221],{}," — see ",[178,243,143],{"href":144},[214,245,246,250,251,253],{},[217,247,248],{},[186,249,200],{}," composes that policy into the running instance. It is the only route in the app that resolves the connection string (through ",[186,252,237],{},") and the signing secret, and therefore the only process that opens a connection to Postgres.",[174,255,256,258,259,262,263,266,267,270,271,274],{},[186,257,225],{}," deliberately omits ",[186,260,261],{},"secret",", ",[186,264,265],{},"baseURL",", and ",[186,268,269],{},"trustedOrigins"," — the Nuxt module resolves those itself and constructs the actual instance, so the two cannot diverge. ",[186,272,273],{},"createAuth",", which does build a full standalone instance, remains for callers that own their own secret and origin, such as the Better Auth CLI's schema-generation entry point.",[203,276,278],{"id":277},"secrets","Secrets",[280,281,282,295],"table",{},[283,284,285],"thead",{},[286,287,288,292],"tr",{},[289,290,291],"th",{},"Variable",[289,293,294],{},"Rule",[296,297,298,312,322],"tbody",{},[286,299,300,306],{},[301,302,303],"td",{},[186,304,305],{},"NUXT_BETTER_AUTH_SECRET",[301,307,308,309],{},"Required under this name in production; generate with ",[186,310,311],{},"openssl rand -base64 32",[286,313,314,319],{},[301,315,316],{},[186,317,318],{},"BETTER_AUTH_SECRET",[301,320,321],{},"Development-only fallback",[286,323,324,329],{},[301,325,326],{},[186,327,328],{},"DATABASE_URL",[301,330,331,332,335,336,339],{},"Postgres connection string, resolved only by ",[186,333,334],{},"server\u002Fauth.config.ts"," (the pre-split ",[186,337,338],{},"AUTH_DATABASE_URL"," is still read when unset)",[203,341,343],{"id":342},"closed-by-default","Closed by default",[174,345,346],{},"Registration and GitHub OAuth are off until you turn them on, so a fresh deployment cannot be signed up for by a stranger:",[211,348,349,367],{},[214,350,351,354,355,358,359,362,363,366],{},[186,352,353],{},"AUTH_ENABLE_SIGNUP=true"," enables self-registration at ",[186,356,357],{},"\u002Fsignup"," (default ",[186,360,361],{},"false","); with it off, that page shows a closed state and ",[186,364,365],{},"\u002Flogin"," hides the link to it;",[214,368,369,370,373,374,241,377,201],{},"GitHub OAuth requires both ",[186,371,372],{},"GITHUB_CLIENT_ID"," and ",[186,375,376],{},"GITHUB_CLIENT_SECRET",[178,378,48],{"href":49},[380,381,382,387],"warning",{},[174,383,384],{},[217,385,386],{},"Rebuild after policy changes",[174,388,389,390,393,394,373,396,398],{},"The methods the auth pages offer are derived ",[217,391,392],{},"at build time"," from the same policy variables the server reads at runtime, and no runtime override can change them. Whenever you change those variables, rebuild the app — the server still enforces its own policy either way, but ",[186,395,365],{},[186,397,357],{}," will keep advertising the old capabilities until rebuilt.",[203,400,402],{"id":401},"ssr-and-sessions","SSR and sessions",[174,404,405],{},"The dashboard renders with SSR. The session cookie is scoped to the app's own origin, so the server resolves it directly from the incoming request before the first paint — a signed-out visitor never flashes protected content before redirecting.",[203,407,409],{"id":408},"sessions-are-not-control-plane-authority","Sessions are not control-plane authority",[174,411,412,413,262,416,419,420,201],{},"The Better Auth session protects the dashboard UI. The control-plane API (",[186,414,415],{},"\u002Frpc\u002F**",[186,417,418],{},"\u002Fapi\u002Fv1\u002F**",") uses an independent bearer-token scheme — see ",[178,421,33],{"href":34},{"title":423,"searchDepth":424,"depth":424,"links":425},"",2,[426,427,428,429,430],{"id":205,"depth":424,"text":206},{"id":277,"depth":424,"text":278},{"id":342,"depth":424,"text":343},{"id":401,"depth":424,"text":402},{"id":408,"depth":424,"text":409},"The dashboard UI is protected by Better Auth, mounted in-process at \u002Fapi\u002Fauth\u002F** by @onmax\u002Fnuxt-better-auth from apps\u002Fdashboard\u002Fserver\u002Fauth.config.ts.","md",null,{},true,{"title":44,"description":431},"ysK2EQc_027XpUGNe2wXydTlQHv6_FyW3ij9_4znVME",[439,441],{"title":33,"path":34,"stem":35,"description":440,"children":-1},"The control plane fails closed. Reads (tasks.list, tasks.get, health) stay open for the dashboard; every mutation requires an operator-issued bearer credential, and without configuration every mutation is rejected.",{"title":48,"path":49,"stem":50,"description":442,"children":-1},"The login page offers a GitHub button only when both halves of the credential are set:",1787482151736]