[{"data":1,"prerenderedAt":541},["ShallowReactive",2],{"navigation_docs":3,"-docs-configuration-local-openiddict-certificates":158,"-docs-configuration-local-openiddict-certificates-surround":536},[4,15,74,98,113],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":6},"Getting Started",false,"\u002Fdocs\u002Fgetting-started","docs\u002F1.getting-started",[10],{"title":11,"path":12,"stem":13,"icon":14},"Zeeq Introduction","\u002Fdocs\u002Fgetting-started\u002Fintroduction","docs\u002F1.getting-started\u002F1.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"children":19,"page":6},"Key Features","\u002Fdocs\u002Fkey-features","docs\u002F3.key-features",[20,25,30,35,40,45,50,55,59,64,69],{"title":21,"path":22,"stem":23,"icon":24},"Membership Invitations","\u002Fdocs\u002Fkey-features\u002Fmembership-invitations","docs\u002F3.key-features\u002F1.membership-invitations","i-hugeicons-cube",{"title":26,"path":27,"stem":28,"icon":29},"Command Palette","\u002Fdocs\u002Fkey-features\u002Fcommand-palette","docs\u002F3.key-features\u002F10.command-palette","i-hugeicons-search-01",{"title":31,"path":32,"stem":33,"icon":34},"Library Import and Export","\u002Fdocs\u002Fkey-features\u002Flibrary-import-export","docs\u002F3.key-features\u002F11.library-import-export","i-lucide-package-open",{"title":36,"path":37,"stem":38,"icon":39},"LLM Settings Configuration","\u002Fdocs\u002Fkey-features\u002Fllm-settings-configuration","docs\u002F3.key-features\u002F2.llm-settings-configuration","i-hugeicons-ai-magic",{"title":41,"path":42,"stem":43,"icon":44},"Agent Code Review Findings","\u002Fdocs\u002Fkey-features\u002Fagent-code-review-findings","docs\u002F3.key-features\u002F3.agent-code-review-findings","i-lucide-list-checks",{"title":46,"path":47,"stem":48,"icon":49},"Credentials & API Tokens","\u002Fdocs\u002Fkey-features\u002Fcredentials","docs\u002F3.key-features\u002F4.credentials","i-hugeicons-key-01",{"title":51,"path":52,"stem":53,"icon":54},"Manual Document Libraries","\u002Fdocs\u002Fkey-features\u002Fmanual-document-libraries","docs\u002F3.key-features\u002F5.manual-document-libraries","i-lucide-library-big",{"title":56,"path":57,"stem":58,"icon":29},"Snippet Search","\u002Fdocs\u002Fkey-features\u002Fsnippet-search","docs\u002F3.key-features\u002F6.snippet-search",{"title":60,"path":61,"stem":62,"icon":63},"Shared Prompt Fragment","\u002Fdocs\u002Fkey-features\u002Fshared-prompt-fragment","docs\u002F3.key-features\u002F7.shared-prompt-fragment","i-lucide-notebook-pen",{"title":65,"path":66,"stem":67,"icon":68},"Code Review Sources & Telemetry","\u002Fdocs\u002Fkey-features\u002Fcode-review-sources","docs\u002F3.key-features\u002F8.code-review-sources","i-hugeicons-book-01",{"title":70,"path":71,"stem":72,"icon":73},"Excluding Documents from Code Reviews","\u002Fdocs\u002Fkey-features\u002Fcode-review-document-exclusion","docs\u002F3.key-features\u002F9.code-review-document-exclusion","i-lucide-eye-off",{"title":75,"path":76,"stem":77,"children":78,"page":6},"Runtime Configuration","\u002Fdocs\u002Fconfiguration","docs\u002F5.configuration",[79,84,89,93],{"title":80,"path":81,"stem":82,"icon":83},"Google Cloud Configuration","\u002Fdocs\u002Fconfiguration\u002Fgcp-runtime","docs\u002F5.configuration\u002F1.gcp-runtime","i-hugeicons-google",{"title":85,"path":86,"stem":87,"icon":88},"GitHub Configuration","\u002Fdocs\u002Fconfiguration\u002Fgithub-configuration","docs\u002F5.configuration\u002F2.github-configuration","i-hugeicons-github",{"title":90,"path":91,"stem":92},"Local OpenIddict Certificates","\u002Fdocs\u002Fconfiguration\u002Flocal-openiddict-certificates","docs\u002F5.configuration\u002F3.local-openiddict-certificates",{"title":94,"path":95,"stem":96,"icon":97},"System Admin Access","\u002Fdocs\u002Fconfiguration\u002Fsystem-admin-access","docs\u002F5.configuration\u002F4.system-admin-access","i-hugeicons-shield-01",{"title":99,"path":100,"stem":101,"children":102,"page":6},"Metrics","\u002Fdocs\u002Fmetrics","docs\u002F6.metrics",[103,108],{"title":104,"path":105,"stem":106,"icon":107},"Metrics Dashboard","\u002Fdocs\u002Fmetrics\u002Fmetrics-dashboard","docs\u002F6.metrics\u002F1.metrics-dashboard","i-hugeicons-analytics-01",{"title":109,"path":110,"stem":111,"icon":112},"Metrics Pipeline","\u002Fdocs\u002Fmetrics\u002Fmetrics-pipeline","docs\u002F6.metrics\u002F2.metrics-pipeline","i-hugeicons-database-02",{"title":114,"path":115,"stem":116,"children":117,"page":6},"Design and Architecture","\u002Fdocs\u002Farchitecture","docs\u002F9.architecture",[118,123,128,133,137,141,145,150,154],{"title":119,"path":120,"stem":121,"icon":122},"Caching","\u002Fdocs\u002Farchitecture\u002Fcaching","docs\u002F9.architecture\u002F1.caching","i-lucide-database",{"title":124,"path":125,"stem":126,"icon":127},"Messaging and Queueing","\u002Fdocs\u002Farchitecture\u002Fmessaging-and-queueing","docs\u002F9.architecture\u002F2.messaging-and-queueing","i-lucide-message-square",{"title":129,"path":130,"stem":131,"icon":132},"GitHub Comment Rendering","\u002Fdocs\u002Farchitecture\u002Fgithub-comment-rendering","docs\u002F9.architecture\u002F3.github-comment-rendering","i-lucide-github",{"title":134,"path":135,"stem":136},"GitHub Integration","\u002Fdocs\u002Farchitecture\u002Fgithub-integration","docs\u002F9.architecture\u002F4.github-integration",{"title":138,"path":139,"stem":140},"LLM Settings and Secret Storage","\u002Fdocs\u002Farchitecture\u002Fllm-settings-and-secret-storage","docs\u002F9.architecture\u002F5.llm-settings-and-secret-storage",{"title":142,"path":143,"stem":144},"Organization Activation and Routes","\u002Fdocs\u002Farchitecture\u002Forganization-activation-and-routes","docs\u002F9.architecture\u002F6.organization-activation-and-routes",{"title":146,"path":147,"stem":148,"icon":149},"MCP Uploaded-Diff Code Reviews","\u002Fdocs\u002Farchitecture\u002Fmcp-uploaded-diff-code-reviews","docs\u002F9.architecture\u002F7.mcp-uploaded-diff-code-reviews","i-lucide-file-search",{"title":151,"path":152,"stem":153},"Repository Content Ingest","\u002Fdocs\u002Farchitecture\u002Frepository-content-ingest","docs\u002F9.architecture\u002F8.repository-content-ingest",{"title":155,"path":156,"stem":157},"Telemetry Ingest","\u002Fdocs\u002Farchitecture\u002Ftelemetry-ingest","docs\u002F9.architecture\u002F9.telemetry-ingest",{"id":159,"title":90,"body":160,"description":529,"extension":530,"links":531,"meta":532,"navigation":533,"path":91,"seo":534,"stem":92,"__hash__":535},"docs\u002Fdocs\u002F5.configuration\u002F3.local-openiddict-certificates.md",{"type":161,"value":162,"toc":520},"minimark",[163,167,172,181,205,212,216,219,229,240,251,255,301,305,308,331,334,338,341,429,433,450,454,457,516],[164,165,90],"h1",{"id":166},"local-openiddict-certificates",[168,169,171],"h2",{"id":170},"why-file-backed-certificates","Why file-backed certificates?",[173,174,175,176,180],"p",{},"In local development, OpenIddict uses self-signed certificates to sign and encrypt tokens (access tokens, refresh tokens, authorization codes). These certificates must remain ",[177,178,179],"strong",{},"stable across server restarts"," so that OAuth\u002FMCP clients registered through Dynamic Client Registration (DCR) — such as Cursor, VS Code, or the MCP Inspector — do not need to re-authenticate every time the server restarts.",[173,182,183,184,188,189,192,193,196,197,200,201,204],{},"OpenIddict's built-in ",[185,186,187],"code",{},"AddDevelopmentSigningCertificate()"," and ",[185,190,191],{},"AddDevelopmentEncryptionCertificate()"," helpers persist certificates to the X.509 ",[185,194,195],{},"CurrentUser\u002FMy"," store. On macOS, that store is the ",[177,198,199],{},"login keychain",", which cannot retain the RSA private key in a retrievable form. As a result, every process restart silently regenerates the key material, and tokens issued before the restart become invalid (causing ",[185,202,203],{},"invalid_grant"," errors and forcing a full re-authentication).",[173,206,207,208,211],{},"Zeeq's ",[185,209,210],{},"DevelopmentRuntimeSecretsProvider"," solves this by generating self-signed certificates once, persisting them as password-less PFX files on disk, and reloading them on every run.",[168,213,215],{"id":214},"where-the-certificates-live","Where the certificates live",[173,217,218],{},"By default, certificates are stored under:",[220,221,226],"pre",{"className":222,"code":224,"language":225},[223],"language-text",".secrets\u002Flocal-certs\u002F\n├── signing.pfx      # Used to sign tokens\n└── encryption.pfx   # Used to encrypt tokens\n","text",[185,227,224],{"__ignoreMap":228},"",[173,230,231,232,235,236,239],{},"This directory is relative to the server process working directory, which under Aspire is ",[185,233,234],{},"src\u002Fbackend\u002FZeeq.Runtime.Server\u002F",". It sits alongside the existing Data Protection key ring at ",[185,237,238],{},".secrets\u002Fdata-protection-keys\u002F",".",[173,241,242,243,246,247,250],{},"The entire ",[185,244,245],{},".secrets\u002F"," directory is ",[177,248,249],{},"gitignored"," — certificates are never committed.",[168,252,254],{"id":253},"how-they-work","How they work",[256,257,258,278,284],"ol",{},[259,260,261,264,265,267,268,188,271,274,275,239],"li",{},[177,262,263],{},"First run:"," The ",[185,266,210],{}," generates two 2048-bit RSA self-signed certificates with ",[185,269,270],{},"CN=Zeeq Development Signing Certificate",[185,272,273],{},"CN=Zeeq Development Encryption Certificate",", exports them as password-less PFX files, and atomically writes them (temp file + move) to ",[185,276,277],{},".secrets\u002Flocal-certs\u002F",[259,279,280,283],{},[177,281,282],{},"Every subsequent run:"," The provider loads the existing PFX files from disk. The private key is loaded from the file data — the macOS keychain is never involved, so the key remains usable across restarts.",[259,285,286,289,290,293,294,188,297,300],{},[177,287,288],{},"Split worker mode:"," When ",[185,291,292],{},"ZEEQ_ASPIRE_MODE=split"," starts both ",[185,295,296],{},"zeeq-server",[185,298,299],{},"zeeq-worker"," concurrently, both processes converge on the same certificate material thanks to the atomic first-run write.",[168,302,304],{"id":303},"rotating-certificates","Rotating certificates",[173,306,307],{},"To rotate development certificates (which invalidates all existing dev tokens and triggers one re-authentication):",[220,309,313],{"className":310,"code":311,"language":312,"meta":228,"style":228},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","rm -rf src\u002Fbackend\u002FZeeq.Runtime.Server\u002F.secrets\u002Flocal-certs\u002F\n","bash",[185,314,315],{"__ignoreMap":228},[316,317,320,324,328],"span",{"class":318,"line":319},"line",1,[316,321,323],{"class":322},"sBMFI","rm",[316,325,327],{"class":326},"sfazB"," -rf",[316,329,330],{"class":326}," src\u002Fbackend\u002FZeeq.Runtime.Server\u002F.secrets\u002Flocal-certs\u002F\n",[173,332,333],{},"The directory will be recreated with new certificates on the next server start.",[168,335,337],{"id":336},"configuration","Configuration",[173,339,340],{},"The certificate directory can be overridden via configuration:",[220,342,346],{"className":343,"code":344,"language":345,"meta":228,"style":228},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"Auth\": {\n    \"OpenIddict\": {\n      \"DevelopmentCertificatePath\": \"\u002Fpath\u002Fto\u002Fcustom\u002Fcert-dir\"\n    }\n  }\n}\n","json",[185,347,348,354,373,388,411,417,423],{"__ignoreMap":228},[316,349,350],{"class":318,"line":319},[316,351,353],{"class":352},"sMK4o","{\n",[316,355,357,360,364,367,370],{"class":318,"line":356},2,[316,358,359],{"class":352},"  \"",[316,361,363],{"class":362},"spNyl","Auth",[316,365,366],{"class":352},"\"",[316,368,369],{"class":352},":",[316,371,372],{"class":352}," {\n",[316,374,376,379,382,384,386],{"class":318,"line":375},3,[316,377,378],{"class":352},"    \"",[316,380,381],{"class":322},"OpenIddict",[316,383,366],{"class":352},[316,385,369],{"class":352},[316,387,372],{"class":352},[316,389,391,394,398,400,402,405,408],{"class":318,"line":390},4,[316,392,393],{"class":352},"      \"",[316,395,397],{"class":396},"sbssI","DevelopmentCertificatePath",[316,399,366],{"class":352},[316,401,369],{"class":352},[316,403,404],{"class":352}," \"",[316,406,407],{"class":326},"\u002Fpath\u002Fto\u002Fcustom\u002Fcert-dir",[316,409,410],{"class":352},"\"\n",[316,412,414],{"class":318,"line":413},5,[316,415,416],{"class":352},"    }\n",[316,418,420],{"class":318,"line":419},6,[316,421,422],{"class":352},"  }\n",[316,424,426],{"class":318,"line":425},7,[316,427,428],{"class":352},"}\n",[168,430,432],{"id":431},"production","Production",[173,434,435,436,439,440,443,444,188,447,239],{},"This is ",[177,437,438],{},"development-only",". Production deployments continue to use ",[185,441,442],{},"ConfiguredCertificateRuntimeSecretsProvider",", which loads managed PFX certificates from configured paths via ",[185,445,446],{},"Auth:OpenIddict:SigningCertificatePath",[185,448,449],{},"Auth:OpenIddict:EncryptionCertificatePath",[168,451,453],{"id":452},"optional-clean-up-orphaned-keychain-certificates","Optional: Clean up orphaned keychain certificates",[173,455,456],{},"If you previously ran the server with the old keychain-based development certificates, you may have orphaned entries in your login keychain. They are harmless but can be removed:",[220,458,460],{"className":310,"code":459,"language":312,"meta":228,"style":228},"security delete-certificate -c \"OpenIddict Server Signing Certificate\" 2>\u002Fdev\u002Fnull || true\nsecurity delete-certificate -c \"OpenIddict Server Encryption Certificate\" 2>\u002Fdev\u002Fnull || true\n",[185,461,462,493],{"__ignoreMap":228},[316,463,464,467,470,473,475,478,480,483,486,489],{"class":318,"line":319},[316,465,466],{"class":322},"security",[316,468,469],{"class":326}," delete-certificate",[316,471,472],{"class":326}," -c",[316,474,404],{"class":352},[316,476,477],{"class":326},"OpenIddict Server Signing Certificate",[316,479,366],{"class":352},[316,481,482],{"class":352}," 2>",[316,484,485],{"class":326},"\u002Fdev\u002Fnull",[316,487,488],{"class":352}," ||",[316,490,492],{"class":491},"s2Zo4"," true\n",[316,494,495,497,499,501,503,506,508,510,512,514],{"class":318,"line":356},[316,496,466],{"class":322},[316,498,469],{"class":326},[316,500,472],{"class":326},[316,502,404],{"class":352},[316,504,505],{"class":326},"OpenIddict Server Encryption Certificate",[316,507,366],{"class":352},[316,509,482],{"class":352},[316,511,485],{"class":326},[316,513,488],{"class":352},[316,515,492],{"class":491},[517,518,519],"style",{},"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 .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 .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}",{"title":228,"searchDepth":356,"depth":356,"links":521},[522,523,524,525,526,527,528],{"id":170,"depth":356,"text":171},{"id":214,"depth":356,"text":215},{"id":253,"depth":356,"text":254},{"id":303,"depth":356,"text":304},{"id":336,"depth":356,"text":337},{"id":431,"depth":356,"text":432},{"id":452,"depth":356,"text":453},"How development OpenIddict certificates are persisted locally so DCR\u002FMCP client tokens survive server restarts.","md",null,{},true,{"title":90,"description":529},"o2CCoUkZ5O_8McNDlkhvoSmdNgLmjGQQqMYAO_vtjxU",[537,539],{"title":85,"path":86,"stem":87,"description":538,"icon":88,"children":-1},"How to configure Zeeq to run on GitHub.",{"title":94,"path":95,"stem":96,"description":540,"icon":97,"children":-1},"Configure system-admin operators and use the admin diagnostics surface.",1784297365800]