[{"data":1,"prerenderedAt":801},["ShallowReactive",2],{"navigation_docs":3,"-auth-security-best-practices":155,"-auth-security-best-practices-surround":796},[4,26,47,68,93,106,127],{"title":5,"path":6,"stem":7,"children":8,"page":25},"Getting Started","\u002Fgetting-started","1.getting-started",[9,13,17,21],{"title":10,"path":11,"stem":12},"Introduction","\u002Fgetting-started\u002Fintroduction","1.getting-started\u002F1.introduction",{"title":14,"path":15,"stem":16},"Quick Start","\u002Fgetting-started\u002Fquick-start","1.getting-started\u002F2.quick-start",{"title":18,"path":19,"stem":20},"Authentication","\u002Fgetting-started\u002Fauthentication","1.getting-started\u002F3.authentication",{"title":22,"path":23,"stem":24},"Rate Limits","\u002Fgetting-started\u002Frate-limits","1.getting-started\u002F4.rate-limits",false,{"title":27,"path":28,"stem":29,"children":30,"page":25},"API Reference","\u002Fapi-reference","2.api-reference",[31,35,39,43],{"title":32,"path":33,"stem":34},"Overview","\u002Fapi-reference\u002Foverview","2.api-reference\u002F1.overview",{"title":36,"path":37,"stem":38},"REST API","\u002Fapi-reference\u002Frest-api","2.api-reference\u002F2.rest-api",{"title":40,"path":41,"stem":42},"Error Codes","\u002Fapi-reference\u002Ferror-codes","2.api-reference\u002F3.error-codes",{"title":44,"path":45,"stem":46},"Pagination","\u002Fapi-reference\u002Fpagination","2.api-reference\u002F4.pagination",{"title":48,"path":49,"stem":50,"children":51,"page":25},"Map Integration","\u002Fmap-integration","3.map-integration",[52,56,60,64],{"title":53,"path":54,"stem":55},"Embed Maps","\u002Fmap-integration\u002Fembed-maps","3.map-integration\u002F1.embed-maps",{"title":57,"path":58,"stem":59},"Custom Styles","\u002Fmap-integration\u002Fcustom-styles","3.map-integration\u002F2.custom-styles",{"title":61,"path":62,"stem":63},"Tile Rendering","\u002Fmap-integration\u002Ftile-rendering","3.map-integration\u002F3.tile-rendering",{"title":65,"path":66,"stem":67},"Static Maps","\u002Fmap-integration\u002Fstatic-maps","3.map-integration\u002F4.static-maps",{"title":69,"path":70,"stem":71,"children":72,"page":25},"Geocoding","\u002Fgeocoding","4.geocoding",[73,77,81,85,89],{"title":74,"path":75,"stem":76},"Forward Geocoding (Search)","\u002Fgeocoding\u002Fforward-geocoding","4.geocoding\u002F1.forward-geocoding",{"title":78,"path":79,"stem":80},"Reverse Geocoding","\u002Fgeocoding\u002Freverse-geocoding","4.geocoding\u002F2.reverse-geocoding",{"title":82,"path":83,"stem":84},"Autocomplete","\u002Fgeocoding\u002Fautocomplete","4.geocoding\u002F3.autocomplete",{"title":86,"path":87,"stem":88},"Place Lookup","\u002Fgeocoding\u002Fplace-lookup","4.geocoding\u002F4.place-lookup",{"title":90,"path":91,"stem":92},"Nearby Search","\u002Fgeocoding\u002Fnearby","4.geocoding\u002F5.nearby",{"title":94,"path":95,"stem":96,"children":97,"page":25},"Routing","\u002Frouting","5.routing",[98,102],{"title":99,"path":100,"stem":101},"Directions","\u002Frouting\u002Fdirections","5.routing\u002F1.directions",{"title":103,"path":104,"stem":105},"Isochrones","\u002Frouting\u002Fisochrones","5.routing\u002F2.isochrones",{"title":107,"path":108,"stem":109,"children":110,"page":25},"Auth & Security","\u002Fauth-security","6.auth-security",[111,115,119,123],{"title":112,"path":113,"stem":114},"API Keys","\u002Fauth-security\u002Fapi-keys","6.auth-security\u002F1.api-keys",{"title":116,"path":117,"stem":118},"Scopes & Permissions","\u002Fauth-security\u002Fscopes-permissions","6.auth-security\u002F2.scopes-permissions",{"title":120,"path":121,"stem":122},"Rate Limiting","\u002Fauth-security\u002Frate-limiting","6.auth-security\u002F3.rate-limiting",{"title":124,"path":125,"stem":126},"Best Practices","\u002Fauth-security\u002Fbest-practices","6.auth-security\u002F4.best-practices",{"title":128,"path":129,"stem":130,"children":131,"page":25},"Mcp","\u002Fmcp","7.mcp",[132,135,139,143,147,151],{"title":32,"path":133,"stem":134},"\u002Fmcp\u002Foverview","7.mcp\u002F1.overview",{"title":136,"path":137,"stem":138},"Setup","\u002Fmcp\u002Fsetup","7.mcp\u002F2.setup",{"title":140,"path":141,"stem":142},"Available Tools","\u002Fmcp\u002Favailable-tools","7.mcp\u002F3.available-tools",{"title":144,"path":145,"stem":146},"GIS Integration","\u002Fmcp\u002Fgis-integration","7.mcp\u002F4.gis-integration",{"title":148,"path":149,"stem":150},"Examples","\u002Fmcp\u002Fexamples","7.mcp\u002F5.examples",{"title":152,"path":153,"stem":154},"Troubleshooting","\u002Fmcp\u002Ftroubleshooting","7.mcp\u002F6.troubleshooting",{"id":156,"title":124,"body":157,"description":789,"extension":790,"links":791,"meta":792,"navigation":793,"path":125,"seo":794,"stem":126,"__hash__":795},"docs\u002F6.auth-security\u002F4.best-practices.md",{"type":158,"value":159,"toc":772},"minimark",[160,164,169,174,259,262,318,322,344,377,381,446,450,453,457,460,479,483,486,508,512,515,532,536,539,570,574,578,585,613,617,620,648,651,655,668,679,682,686,763,768],[161,162,163],"p",{},"Follow these guidelines to keep your maps.guru integration secure in production.",[165,166,168],"h2",{"id":167},"api-key-security","API Key Security",[170,171,173],"h3",{"id":172},"never-expose-keys-in-client-side-code","Never Expose Keys in Client-Side Code",[175,176,181],"pre",{"className":177,"code":178,"language":179,"meta":180,"style":180},"language-javascript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F BAD — key visible in browser source\nconst map = new maplibregl.Map({\n  style: `https:\u002F\u002Fmaps.guru\u002Fapi\u002Fv1\u002Fstyles\u002Fstandard\u002Flight\u002Fstyle.json?key=mapx_secret_key`\n});\n","javascript","",[182,183,184,193,227,247],"code",{"__ignoreMap":180},[185,186,189],"span",{"class":187,"line":188},"line",1,[185,190,192],{"class":191},"sHwdD","\u002F\u002F BAD — key visible in browser source\n",[185,194,196,200,204,208,211,214,217,221,224],{"class":187,"line":195},2,[185,197,199],{"class":198},"spNyl","const",[185,201,203],{"class":202},"sTEyZ"," map ",[185,205,207],{"class":206},"sMK4o","=",[185,209,210],{"class":206}," new",[185,212,213],{"class":202}," maplibregl",[185,215,216],{"class":206},".",[185,218,220],{"class":219},"s2Zo4","Map",[185,222,223],{"class":202},"(",[185,225,226],{"class":206},"{\n",[185,228,230,234,237,240,244],{"class":187,"line":229},3,[185,231,233],{"class":232},"swJcz","  style",[185,235,236],{"class":206},":",[185,238,239],{"class":206}," `",[185,241,243],{"class":242},"sfazB","https:\u002F\u002Fmaps.guru\u002Fapi\u002Fv1\u002Fstyles\u002Fstandard\u002Flight\u002Fstyle.json?key=mapx_secret_key",[185,245,246],{"class":206},"`\n",[185,248,250,253,256],{"class":187,"line":249},4,[185,251,252],{"class":206},"}",[185,254,255],{"class":202},")",[185,257,258],{"class":206},";\n",[161,260,261],{},"Instead, proxy through your backend:",[175,263,265],{"className":177,"code":264,"language":179,"meta":180,"style":180},"\u002F\u002F GOOD — key stays on your server\nconst map = new maplibregl.Map({\n  style: '\u002Fapi\u002Fmap-style' \u002F\u002F Your backend fetches with the API key\n});\n",[182,266,267,272,292,310],{"__ignoreMap":180},[185,268,269],{"class":187,"line":188},[185,270,271],{"class":191},"\u002F\u002F GOOD — key stays on your server\n",[185,273,274,276,278,280,282,284,286,288,290],{"class":187,"line":195},[185,275,199],{"class":198},[185,277,203],{"class":202},[185,279,207],{"class":206},[185,281,210],{"class":206},[185,283,213],{"class":202},[185,285,216],{"class":206},[185,287,220],{"class":219},[185,289,223],{"class":202},[185,291,226],{"class":206},[185,293,294,296,298,301,304,307],{"class":187,"line":229},[185,295,233],{"class":232},[185,297,236],{"class":206},[185,299,300],{"class":206}," '",[185,302,303],{"class":242},"\u002Fapi\u002Fmap-style",[185,305,306],{"class":206},"'",[185,308,309],{"class":191}," \u002F\u002F Your backend fetches with the API key\n",[185,311,312,314,316],{"class":187,"line":249},[185,313,252],{"class":206},[185,315,255],{"class":202},[185,317,258],{"class":206},[170,319,321],{"id":320},"use-environment-variables","Use Environment Variables",[175,323,327],{"className":324,"code":325,"language":326,"meta":180,"style":180},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# .env (never committed)\nMAPS_GURU_API_KEY=mapx_your_key\n","bash",[182,328,329,334],{"__ignoreMap":180},[185,330,331],{"class":187,"line":188},[185,332,333],{"class":191},"# .env (never committed)\n",[185,335,336,339,341],{"class":187,"line":195},[185,337,338],{"class":202},"MAPS_GURU_API_KEY",[185,340,207],{"class":206},[185,342,343],{"class":242},"mapx_your_key\n",[175,345,347],{"className":177,"code":346,"language":179,"meta":180,"style":180},"\u002F\u002F server.js\nconst apiKey = process.env.MAPS_GURU_API_KEY;\n",[182,348,349,354],{"__ignoreMap":180},[185,350,351],{"class":187,"line":188},[185,352,353],{"class":191},"\u002F\u002F server.js\n",[185,355,356,358,361,363,366,368,371,373,375],{"class":187,"line":195},[185,357,199],{"class":198},[185,359,360],{"class":202}," apiKey ",[185,362,207],{"class":206},[185,364,365],{"class":202}," process",[185,367,216],{"class":206},[185,369,370],{"class":202},"env",[185,372,216],{"class":206},[185,374,338],{"class":202},[185,376,258],{"class":206},[170,378,380],{"id":379},"separate-keys-per-environment","Separate Keys Per Environment",[382,383,384,400],"table",{},[385,386,387],"thead",{},[388,389,390,394,397],"tr",{},[391,392,393],"th",{},"Environment",[391,395,396],{},"Key Name",[391,398,399],{},"Scopes",[401,402,403,415,425,436],"tbody",{},[388,404,405,409,412],{},[406,407,408],"td",{},"Development",[406,410,411],{},"Dev Key",[406,413,414],{},"All",[388,416,417,420,423],{},[406,418,419],{},"Staging",[406,421,422],{},"Staging Key",[406,424,414],{},[388,426,427,430,433],{},[406,428,429],{},"Production",[406,431,432],{},"Prod Backend",[406,434,435],{},"geocoding, routing",[388,437,438,440,443],{},[406,439,429],{},[406,441,442],{},"Prod Maps",[406,444,445],{},"maps",[165,447,449],{"id":448},"https-only","HTTPS Only",[161,451,452],{},"All maps.guru endpoints enforce HTTPS. Never use HTTP — it exposes your API key in transit.",[165,454,456],{"id":455},"restrict-key-scopes","Restrict Key Scopes",[161,458,459],{},"Follow the principle of least privilege:",[461,462,463,471,476],"ul",{},[464,465,466,467,470],"li",{},"If an application only needs geocoding, create a key with only the ",[182,468,469],{},"geocoding"," scope",[464,472,473,474,470],{},"If a frontend only displays maps, use a key with only the ",[182,475,445],{},[464,477,478],{},"Never use the default all-scopes key in production",[165,480,482],{"id":481},"monitor-usage","Monitor Usage",[161,484,485],{},"Set up monitoring to detect anomalies:",[487,488,489,496,502],"ol",{},[464,490,491,495],{},[492,493,494],"strong",{},"Check daily"," — Review the usage dashboard for unexpected spikes",[464,497,498,501],{},[492,499,500],{},"Set alerts"," — Configure budget warnings in the admin dashboard",[464,503,504,507],{},[492,505,506],{},"Audit keys"," — Regularly review which keys exist and revoke unused ones",[165,509,511],{"id":510},"rotate-keys-regularly","Rotate Keys Regularly",[161,513,514],{},"Establish a key rotation schedule:",[487,516,517,520,523,526,529],{},[464,518,519],{},"Create a new key",[464,521,522],{},"Deploy the new key to your application",[464,524,525],{},"Verify everything works",[464,527,528],{},"Revoke the old key",[464,530,531],{},"Repeat quarterly (or after any team member departure)",[165,533,535],{"id":534},"incident-response","Incident Response",[161,537,538],{},"If you suspect a key has been compromised:",[487,540,541,547,552,558,564],{},[464,542,543,546],{},[492,544,545],{},"Revoke immediately"," — Go to Dashboard → API Keys → Revoke",[464,548,549,551],{},[492,550,519],{}," — Generate a replacement",[464,553,554,557],{},[492,555,556],{},"Update applications"," — Deploy the new key",[464,559,560,563],{},[492,561,562],{},"Review usage"," — Check for any unauthorized requests",[464,565,566,569],{},[492,567,568],{},"Audit access"," — Review who had access to the compromised key",[571,572,573],"warning",{},"Key revocation is instant and permanent. All requests using the revoked key will fail immediately.",[165,575,577],{"id":576},"oauth-consent-management","OAuth Consent Management",[161,579,580,581,584],{},"OAuth-authorized clients are managed separately from ",[182,582,583],{},"mapx_"," keys. The platform splits them across two dashboard pages so each type is manageable at the right granularity:",[461,586,587,599],{},[464,588,589,598],{},[492,590,591],{},[592,593,597],"a",{"href":594,"rel":595},"https:\u002F\u002Fmaps.guru\u002Fdashboard\u002Fsettings\u002Fconnected-apps",[596],"nofollow","maps.guru\u002Fdashboard\u002Fsettings\u002Fconnected-apps"," — remote MCP connectors (ChatGPT, Claude) and other third-party OAuth clients. One row per client, regardless of how many machines you've approved it on.",[464,600,601,608,609,612],{},[492,602,603],{},[592,604,607],{"href":605,"rel":606},"https:\u002F\u002Fmaps.guru\u002Fdashboard\u002Fsettings\u002Fdevices",[596],"maps.guru\u002Fdashboard\u002Fsettings\u002Fdevices"," — individual ",[182,610,611],{},"@invarya\u002Fmaps-mcp auth login"," installs (each machine or CLI sandbox is its own row). CLI entries are deliberately filtered out of Connected Apps to avoid clutter — revoke a specific machine here, or revoke all your CLI installs in one pass.",[170,614,616],{"id":615},"revoking-an-oauth-client","Revoking an OAuth Client",[161,618,619],{},"When you revoke an OAuth consent, the platform does three things atomically:",[487,621,622,636,642],{},[464,623,624,627,628,631,632,635],{},[492,625,626],{},"Marks every refresh token revoked"," for that ",[182,629,630],{},"(user, client)"," pair (",[182,633,634],{},"oauth_refresh_token.revoked = NOW()","). The client cannot mint a fresh access token.",[464,637,638,641],{},[492,639,640],{},"Hard-deletes any stored access tokens"," for that pair. (Most access tokens are stateless JWTs — those still expire on their own within 15 minutes — but any opaque tokens are nuked instantly.)",[464,643,644,647],{},[492,645,646],{},"Deletes the consent row."," The next OAuth flow lands on the consent screen instead of being silently approved.",[161,649,650],{},"In practical terms: revoking an OAuth client locks them out at most 15 minutes later (the JWT TTL), with a hard guarantee that they cannot refresh. Often it's effective immediately.",[170,652,654],{"id":653},"platform-wide-audit-superadmin-only","Platform-wide Audit (Superadmin Only)",[161,656,657,658,661,662,667],{},"Superadmins (",[182,659,660],{},"user.role === 'admin'",") get a global view at ",[592,663,666],{"href":664,"rel":665},"https:\u002F\u002Fmaps.guru\u002Fdashboard\u002Fsettings\u002Fadmin\u002Foauth-consents",[596],"maps.guru\u002Fdashboard\u002Fsettings\u002Fadmin\u002Foauth-consents"," — every consent across every user. Useful for:",[461,669,670,673,676],{},[464,671,672],{},"Spotting an OAuth client that suddenly has thousands of grants (potential abuse signal)",[464,674,675],{},"Force-revoking a misbehaving client across all users in one click",[464,677,678],{},"Verifying which orgs have authorized which AI integrations",[161,680,681],{},"Search by user email\u002Fname or client name; filter by clientId.",[170,683,685],{"id":684},"when-to-revoke-vs-rotate","When to Revoke vs Rotate",[382,687,688,698],{},[385,689,690],{},[388,691,692,695],{},[391,693,694],{},"Situation",[391,696,697],{},"Action",[401,699,700,712,728,736,744,755],{},[388,701,702,705],{},[406,703,704],{},"Stop a single remote MCP connector (ChatGPT, Claude)",[406,706,707,708],{},"Revoke its consent in ",[592,709,711],{"href":594,"rel":710},[596],"connected-apps",[388,713,714,721],{},[406,715,716,717,720],{},"Revoke ",[182,718,719],{},"auth login"," for a specific CLI machine",[406,722,723,724],{},"Revoke that device in ",[592,725,727],{"href":605,"rel":726},[596],"devices",[388,729,730,733],{},[406,731,732],{},"Revoke every one of your CLI installs at once",[406,734,735],{},"Select all on the devices page and revoke",[388,737,738,741],{},[406,739,740],{},"Suspect a single user's session was compromised",[406,742,743],{},"Revoke their OAuth consents — refresh tokens die, JWT max 1 hour",[388,745,746,752],{},[406,747,748,749,751],{},"Suspect a ",[182,750,583],{}," key leaked",[406,753,754],{},"Rotate the key (different flow — see \"Key Rotation Strategy\" above)",[388,756,757,760],{},[406,758,759],{},"Lock an entire OAuth client out platform-wide",[406,761,762],{},"Superadmin → OAuth consents page → revoke all",[161,764,765,767],{},[182,766,583],{}," keys (long-lived bearers used for tiles, geocoding, embeds) and OAuth consents (short-lived JWTs used by MCP) live on separate tracks. Revoking one doesn't affect the other.",[769,770,771],"style",{},"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 pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}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 .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}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);}",{"title":180,"searchDepth":229,"depth":229,"links":773},[774,779,780,781,782,783,784],{"id":167,"depth":195,"text":168,"children":775},[776,777,778],{"id":172,"depth":229,"text":173},{"id":320,"depth":229,"text":321},{"id":379,"depth":229,"text":380},{"id":448,"depth":195,"text":449},{"id":455,"depth":195,"text":456},{"id":481,"depth":195,"text":482},{"id":510,"depth":195,"text":511},{"id":534,"depth":195,"text":535},{"id":576,"depth":195,"text":577,"children":785},[786,787,788],{"id":615,"depth":229,"text":616},{"id":653,"depth":229,"text":654},{"id":684,"depth":229,"text":685},"Security best practices for using maps.guru in production.","md",null,{},true,{"title":124,"description":789},"WPJdEiUlRc-jqiZlMZVgn0GERHia0b1v2p7w1NQPwJI",[797,799],{"title":120,"path":121,"stem":122,"description":798,"children":-1},"How rate limiting and quota enforcement work in maps.guru.",{"title":32,"path":133,"stem":134,"description":800,"children":-1},"Learn how the Model Context Protocol (MCP) connects maps.guru to AI assistants and GIS tools.",1777621084553]