[{"data":1,"prerenderedAt":976},["ShallowReactive",2],{"docs:doc:\u002Fen\u002Fdocs\u002Fgetting-started\u002Fquickstart":3,"docs:pages:docs_en":907},{"id":4,"title":5,"alt":6,"body":7,"description":898,"extension":899,"key":900,"meta":901,"navigation":286,"order":374,"path":902,"placeholder":903,"seo":904,"stem":905,"__hash__":906},"docs_en\u002Fen\u002Fdocs\u002Fgetting-started\u002Fquickstart.md","Quickstart","\u002Fpl\u002Fdocs\u002Fpierwsze-kroki\u002Fszybki-start",{"type":8,"value":9,"toc":888},"minimark",[10,28,36,41,56,59,99,110,116,120,139,142,176,183,202,206,231,239,243,258,479,490,497,522,526,529,550,712,733,737,823,827,841,850,868,872,884],[11,12,15],"callout",{"title":13,"type":14},"The packages are not on the registries yet","warning",[16,17,18,19,23,24,27],"p",{},"The SDKs are at version ",[20,21,22],"code",{},"0.1.0"," and are published to npm and PyPI with the\n",[20,25,26],{},"1.0.0"," release. The install commands below are the ones that will fetch them.",[16,29,30,31,35],{},"By the end of this page a browser will sign in against your own App and hand\nyour code an access token. Everything happens in ",[32,33,34],"strong",{},"sandbox",", where the users\nare yours to throw away.",[37,38,40],"h2",{"id":39},"_1-create-an-app","1. Create an App",[16,42,43,44,51,52,55],{},"Sign in to the ",[45,46,50],"a",{"href":47,"rel":48},"https:\u002F\u002Fapp.kleora.io",[49],"nofollow","console",". An account with no\nApps is met by a three-step wizard whose second step is the create form; an\naccount that already has one creates the next from ",[32,53,54],{},"Apps → Create App",".",[16,57,58],{},"The name you give it becomes a slug, and the slug becomes two permanent\naddresses:",[60,61,62,75],"table",{},[63,64,65],"thead",{},[66,67,68,72],"tr",{},[69,70,71],"th",{},"Environment",[69,73,74],{},"Address",[76,77,78,89],"tbody",{},[66,79,80,84],{},[81,82,83],"td",{},"Production",[81,85,86],{},[20,87,88],{},"https:\u002F\u002Facme.kleora.eu",[66,90,91,94],{},[81,92,93],{},"Sandbox",[81,95,96],{},[20,97,98],{},"https:\u002F\u002Facme.sandbox.kleora.eu",[16,100,101,102,105,106,109],{},"Those are the App's ",[32,103,104],{},"issuers",". The slug cannot be changed afterwards: it is\nwhat the ",[20,107,108],{},"iss"," claim of every token says, and what every service that has\nverified one of your tokens has cached. Pick it as carefully as a domain name.",[16,111,112,113,115],{},"Finishing takes you to the App's ",[32,114,34],{}," overview, which shows the three\nvalues the rest of this page needs — the issuer, the default client id, and the\ndiscovery URL.",[37,117,119],{"id":118},"_2-register-your-redirect-uris","2. Register your redirect URIs",[16,121,122,123,126,127,130,131,134,135,138],{},"Go to ",[32,124,125],{},"Integration → Clients"," and open the client named ",[32,128,129],{},"Default",". It is a\n",[20,132,133],{},"spa"," client, created with your App, and it has ",[32,136,137],{},"no redirect URIs at all",".\nUntil you add one, the authorization endpoint has nowhere to send a browser\nback to.",[16,140,141],{},"Add the two your development server will use:",[60,143,144,154],{},[63,145,146],{},[66,147,148,151],{},[69,149,150],{},"Field",[69,152,153],{},"Value",[76,155,156,166],{},[66,157,158,161],{},[81,159,160],{},"Redirect URI",[81,162,163],{},[20,164,165],{},"http:\u002F\u002Flocalhost:5173\u002Fcallback",[66,167,168,171],{},[81,169,170],{},"Post-logout redirect URI",[81,172,173],{},[20,174,175],{},"http:\u002F\u002Flocalhost:5173\u002F",[16,177,178,179,182],{},"Both are matched ",[32,180,181],{},"exactly",". A trailing slash, a different port or an extra\nquery string is a different URI as far as the authorization endpoint is\nconcerned.",[11,184,187],{"title":185,"type":186},"Plain http:\u002F\u002F is a sandbox-only convenience","note",[16,188,189,190,193,194,197,198,201],{},"A sandbox environment accepts ",[20,191,192],{},"http:\u002F\u002Flocalhost"," and ",[20,195,196],{},"http:\u002F\u002F127.0.0.1"," on any\nport and path. A production environment accepts ",[20,199,200],{},"https:\u002F\u002F"," only, so the\nlocalhost entry you develop against cannot be carried across — production gets\nits own list.",[37,203,205],{"id":204},"_3-install-the-browser-sdk","3. Install the browser SDK",[207,208,213],"pre",{"className":209,"code":210,"language":211,"meta":212,"style":212},"language-bash shiki shiki-themes github-light","npm install @kleora-io\u002Fbrowser\n","bash","",[20,214,215],{"__ignoreMap":212},[216,217,220,224,228],"span",{"class":218,"line":219},"line",1,[216,221,223],{"class":222},"s7eDp","npm",[216,225,227],{"class":226},"sYBdl"," install",[216,229,230],{"class":226}," @kleora-io\u002Fbrowser\n",[16,232,233,234,238],{},"It has no runtime dependencies and ships as ES modules only.\n",[45,235,237],{"href":236},"\u002Fen\u002Fdocs\u002Fgetting-started\u002Finstallation","Installing an SDK"," covers the other four\npackages.",[37,240,242],{"id":241},"_4-sign-in","4. Sign in",[16,244,245,246,249,250,253,254,257],{},"Three values go into the client: the ",[32,247,248],{},"issuer"," and the ",[32,251,252],{},"client id"," from the\noverview page, and the ",[32,255,256],{},"redirect URI"," you just registered.",[207,259,263],{"className":260,"code":261,"language":262,"meta":212,"style":212},"language-ts shiki shiki-themes github-light","import { createKleora } from '@kleora-io\u002Fbrowser'\n\nconst kleora = createKleora({\n  issuer: 'https:\u002F\u002Facme.sandbox.kleora.eu',\n  clientId: '\u003Cclient_id>',\n  redirectUri: location.origin + '\u002Fcallback',\n})\n\nif (location.pathname === '\u002Fcallback') {\n  await kleora.handleRedirectCallback()\n} else if (!(await kleora.checkSession())) {\n  await kleora.loginWithRedirect()\n}\n\nconst user = kleora.getUser()\nconst token = await kleora.getAccessToken()\n","ts",[20,264,265,281,288,307,319,330,344,350,355,372,387,419,431,437,442,459],{"__ignoreMap":212},[216,266,267,271,275,278],{"class":218,"line":219},[216,268,270],{"class":269},"sD7c4","import",[216,272,274],{"class":273},"sgsFI"," { createKleora } ",[216,276,277],{"class":269},"from",[216,279,280],{"class":226}," '@kleora-io\u002Fbrowser'\n",[216,282,284],{"class":218,"line":283},2,[216,285,287],{"emptyLinePlaceholder":286},true,"\n",[216,289,291,294,298,301,304],{"class":218,"line":290},3,[216,292,293],{"class":269},"const",[216,295,297],{"class":296},"sYu0t"," kleora",[216,299,300],{"class":269}," =",[216,302,303],{"class":222}," createKleora",[216,305,306],{"class":273},"({\n",[216,308,310,313,316],{"class":218,"line":309},4,[216,311,312],{"class":273},"  issuer: ",[216,314,315],{"class":226},"'https:\u002F\u002Facme.sandbox.kleora.eu'",[216,317,318],{"class":273},",\n",[216,320,322,325,328],{"class":218,"line":321},5,[216,323,324],{"class":273},"  clientId: ",[216,326,327],{"class":226},"'\u003Cclient_id>'",[216,329,318],{"class":273},[216,331,333,336,339,342],{"class":218,"line":332},6,[216,334,335],{"class":273},"  redirectUri: location.origin ",[216,337,338],{"class":269},"+",[216,340,341],{"class":226}," '\u002Fcallback'",[216,343,318],{"class":273},[216,345,347],{"class":218,"line":346},7,[216,348,349],{"class":273},"})\n",[216,351,353],{"class":218,"line":352},8,[216,354,287],{"emptyLinePlaceholder":286},[216,356,358,361,364,367,369],{"class":218,"line":357},9,[216,359,360],{"class":269},"if",[216,362,363],{"class":273}," (location.pathname ",[216,365,366],{"class":269},"===",[216,368,341],{"class":226},[216,370,371],{"class":273},") {\n",[216,373,375,378,381,384],{"class":218,"line":374},10,[216,376,377],{"class":269},"  await",[216,379,380],{"class":273}," kleora.",[216,382,383],{"class":222},"handleRedirectCallback",[216,385,386],{"class":273},"()\n",[216,388,390,393,396,399,402,405,408,411,413,416],{"class":218,"line":389},11,[216,391,392],{"class":273},"} ",[216,394,395],{"class":269},"else",[216,397,398],{"class":269}," if",[216,400,401],{"class":273}," (",[216,403,404],{"class":269},"!",[216,406,407],{"class":273},"(",[216,409,410],{"class":269},"await",[216,412,380],{"class":273},[216,414,415],{"class":222},"checkSession",[216,417,418],{"class":273},"())) {\n",[216,420,422,424,426,429],{"class":218,"line":421},12,[216,423,377],{"class":269},[216,425,380],{"class":273},[216,427,428],{"class":222},"loginWithRedirect",[216,430,386],{"class":273},[216,432,434],{"class":218,"line":433},13,[216,435,436],{"class":273},"}\n",[216,438,440],{"class":218,"line":439},14,[216,441,287],{"emptyLinePlaceholder":286},[216,443,445,447,450,452,454,457],{"class":218,"line":444},15,[216,446,293],{"class":269},[216,448,449],{"class":296}," user",[216,451,300],{"class":269},[216,453,380],{"class":273},[216,455,456],{"class":222},"getUser",[216,458,386],{"class":273},[216,460,462,464,467,469,472,474,477],{"class":218,"line":461},16,[216,463,293],{"class":269},[216,465,466],{"class":296}," token",[216,468,300],{"class":269},[216,470,471],{"class":269}," await",[216,473,380],{"class":273},[216,475,476],{"class":222},"getAccessToken",[216,478,386],{"class":273},[16,480,481,482,485,486,489],{},"Run it. The browser leaves for your App's hosted sign-in page, where you can\ncreate the first user — self-registration is on by default in a new\nenvironment — and comes back to ",[20,483,484],{},"\u002Fcallback"," with an authorization code.\n",[20,487,488],{},"handleRedirectCallback()"," redeems it, validates the ID token, stores the\ntokens and strips the code out of the address bar.",[16,491,492,493,496],{},"Signing out is one call, and ",[20,494,495],{},"returnTo"," has to be one of the client's\nregistered post-logout URIs:",[207,498,500],{"className":260,"code":499,"language":262,"meta":212,"style":212},"await kleora.logout({ returnTo: location.origin + '\u002F' })\n",[20,501,502],{"__ignoreMap":212},[216,503,504,506,508,511,514,516,519],{"class":218,"line":219},[216,505,410],{"class":269},[216,507,380],{"class":273},[216,509,510],{"class":222},"logout",[216,512,513],{"class":273},"({ returnTo: location.origin ",[216,515,338],{"class":269},[216,517,518],{"class":226}," '\u002F'",[216,520,521],{"class":273}," })\n",[37,523,525],{"id":524},"_5-verify-the-token-on-your-own-api","5. Verify the token on your own API",[16,527,528],{},"The access token is a signed JWT. Your API verifies it against your issuer's\npublished key set — no call to us, no shared secret.",[11,530,532],{"title":531,"type":186},"What to pass as the audience",[16,533,534,535,538,539,542,543,546,547,549],{},"A token's ",[20,536,537],{},"aud"," claim is ",[20,540,541],{},"[client_id]",", or ",[20,544,545],{},"[client_id, api_audience]"," once you\nset an API audience on the environment. A fresh environment has none, so pass\nthe ",[32,548,252],{}," as the audience until you do.",[551,552,553,630],"code-tabs",{},[554,555,556],"template",{"v-slot:ts":212},[207,557,559],{"className":260,"code":558,"language":262,"meta":212,"style":212},"import { authenticate } from '@kleora-io\u002Fnode'\n\nconst claims = await authenticate(request, {\n  issuer: 'https:\u002F\u002Facme.sandbox.kleora.eu',\n  audience: '\u003Cclient_id>',\n})\n\nconsole.log(claims.sub, claims.tenant, claims.permissions)\n",[20,560,561,573,577,594,602,611,615,619],{"__ignoreMap":212},[216,562,563,565,568,570],{"class":218,"line":219},[216,564,270],{"class":269},[216,566,567],{"class":273}," { authenticate } ",[216,569,277],{"class":269},[216,571,572],{"class":226}," '@kleora-io\u002Fnode'\n",[216,574,575],{"class":218,"line":283},[216,576,287],{"emptyLinePlaceholder":286},[216,578,579,581,584,586,588,591],{"class":218,"line":290},[216,580,293],{"class":269},[216,582,583],{"class":296}," claims",[216,585,300],{"class":269},[216,587,471],{"class":269},[216,589,590],{"class":222}," authenticate",[216,592,593],{"class":273},"(request, {\n",[216,595,596,598,600],{"class":218,"line":309},[216,597,312],{"class":273},[216,599,315],{"class":226},[216,601,318],{"class":273},[216,603,604,607,609],{"class":218,"line":321},[216,605,606],{"class":273},"  audience: ",[216,608,327],{"class":226},[216,610,318],{"class":273},[216,612,613],{"class":218,"line":332},[216,614,349],{"class":273},[216,616,617],{"class":218,"line":346},[216,618,287],{"emptyLinePlaceholder":286},[216,620,621,624,627],{"class":218,"line":352},[216,622,623],{"class":273},"console.",[216,625,626],{"class":222},"log",[216,628,629],{"class":273},"(claims.sub, claims.tenant, claims.permissions)\n",[554,631,632],{"v-slot:python":212},[207,633,637],{"className":634,"code":635,"language":636,"meta":212,"style":212},"language-python shiki shiki-themes github-light","from kleora import verify_access_token\n\nclaims = verify_access_token(\n    token,\n    issuer=\"https:\u002F\u002Facme.sandbox.kleora.eu\",\n    audience=\"\u003Cclient_id>\",\n)\n\nprint(claims.sub, claims.tenant, claims.permissions)\n","python",[20,638,639,651,655,666,671,684,696,701,705],{"__ignoreMap":212},[216,640,641,643,646,648],{"class":218,"line":219},[216,642,277],{"class":269},[216,644,645],{"class":273}," kleora ",[216,647,270],{"class":269},[216,649,650],{"class":273}," verify_access_token\n",[216,652,653],{"class":218,"line":283},[216,654,287],{"emptyLinePlaceholder":286},[216,656,657,660,663],{"class":218,"line":290},[216,658,659],{"class":273},"claims ",[216,661,662],{"class":269},"=",[216,664,665],{"class":273}," verify_access_token(\n",[216,667,668],{"class":218,"line":309},[216,669,670],{"class":273},"    token,\n",[216,672,673,677,679,682],{"class":218,"line":321},[216,674,676],{"class":675},"sqxcx","    issuer",[216,678,662],{"class":269},[216,680,681],{"class":226},"\"https:\u002F\u002Facme.sandbox.kleora.eu\"",[216,683,318],{"class":273},[216,685,686,689,691,694],{"class":218,"line":332},[216,687,688],{"class":675},"    audience",[216,690,662],{"class":269},[216,692,693],{"class":226},"\"\u003Cclient_id>\"",[216,695,318],{"class":273},[216,697,698],{"class":218,"line":346},[216,699,700],{"class":273},")\n",[216,702,703],{"class":218,"line":352},[216,704,287],{"emptyLinePlaceholder":286},[216,706,707,710],{"class":218,"line":357},[216,708,709],{"class":296},"print",[216,711,629],{"class":273},[16,713,714,717,718,721,722,725,726,193,729,732],{},[20,715,716],{},"authenticate"," takes anything with a ",[20,719,720],{},"headers.authorization"," property, so it\nworks with any Node framework; ",[20,723,724],{},"@kleora-io\u002Fnode"," also ships Express and\nFastify middleware. ",[20,727,728],{},"claims.roles",[20,730,731],{},"claims.permissions"," are already in the\ntoken, so authorising a request costs you nothing but a list lookup.",[37,734,736],{"id":735},"what-the-sdk-is-doing-for-you","What the SDK is doing for you",[60,738,739,749],{},[63,740,741],{},[66,742,743,746],{},[69,744,745],{},"Call",[69,747,748],{},"What it handles",[76,750,751,769,783,793,803,813],{},[66,752,753,758],{},[81,754,755],{},[20,756,757],{},"loginWithRedirect()",[81,759,760,761,764,765,768],{},"Mints ",[20,762,763],{},"state",", ",[20,766,767],{},"nonce"," and a PKCE verifier, then navigates to the authorization endpoint.",[66,770,771,775],{},[81,772,773],{},[20,774,488],{},[81,776,777,778,193,780,782],{},"Validates ",[20,779,763],{},[20,781,108],{},", redeems the code, validates the ID token, stores the tokens, cleans the URL.",[66,784,785,790],{},[81,786,787],{},[20,788,789],{},"getAccessToken()",[81,791,792],{},"Returns the cached token until it is within 30 seconds of expiry, then refreshes. Refresh tokens rotate on every use.",[66,794,795,800],{},[81,796,797],{},[20,798,799],{},"checkSession()",[81,801,802],{},"Recovers a session on page load, silently, without showing the sign-in page again.",[66,804,805,810],{},[81,806,807],{},[20,808,809],{},"logout({ returnTo })",[81,811,812],{},"Clears local state and ends the session at the issuer.",[66,814,815,820],{},[81,816,817],{},[20,818,819],{},"onAuthChange(cb)",[81,821,822],{},"Fires on sign-in, sign-out and refresh. Returns an unsubscribe function.",[37,824,826],{"id":825},"where-the-tokens-live","Where the tokens live",[16,828,829,830,832,833,836,837,840],{},"By default both tokens are held in memory, in a closure. Nothing survives a\nreload, which is why a page load calls ",[20,831,799],{},". Passing\n",[20,834,835],{},"storage: 'session'"," additionally mirrors the refresh token into\n",[20,838,839],{},"sessionStorage",", which is scoped to the tab and cleared when the tab closes.",[16,842,843,849],{},[32,844,845,848],{},[20,846,847],{},"localStorage"," is not an option and will not become one."," It persists\nindefinitely, every tab on the origin shares it, and every script that ever runs\nthere can read it — including one that arrives tomorrow inside a dependency you\nshipped today.",[11,851,853],{"title":852,"type":186},"Why localhost always shows the redirect",[16,854,855,857,858,193,861,864,865,867],{},[20,856,799],{}," recovers a session silently by loading the issuer in a hidden\nframe. That only works where your application and its issuer are the same site.\n",[20,859,860],{},"localhost:5173",[20,862,863],{},"acme.sandbox.kleora.eu"," are not, so in development\na reload always goes through a visible round trip to the sign-in page — it does\nnot ask for credentials again. ",[20,866,835],{}," avoids it within a tab.",[37,869,871],{"id":870},"next","Next",[873,874,875,881],"ul",{},[876,877,878,880],"li",{},[45,879,237],{"href":236}," — Nuxt, Node,\nPython and Django.",[876,882,883],{},"Turn on TOTP, invite people into workspaces or brand the sign-in page from the\nconsole; none of it changes the code above.",[885,886,887],"style",{},"html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}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 pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .sqxcx, html code.shiki .sqxcx{--shiki-default:#E36209}",{"title":212,"searchDepth":290,"depth":290,"links":889},[890,891,892,893,894,895,896,897],{"id":39,"depth":283,"text":40},{"id":118,"depth":283,"text":119},{"id":204,"depth":283,"text":205},{"id":241,"depth":283,"text":242},{"id":524,"depth":283,"text":525},{"id":735,"depth":283,"text":736},{"id":825,"depth":283,"text":826},{"id":870,"depth":283,"text":871},"Create an App, wire up the browser SDK, and sign in for the first time — entirely in sandbox.","md","getting-started\u002Fquickstart",{},"\u002Fen\u002Fdocs\u002Fgetting-started\u002Fquickstart",false,{"title":5,"description":898},"en\u002Fdocs\u002Fgetting-started\u002Fquickstart","4IM2oB0FJwLGUICc9E4-Y3QMDt2BD3QRwQIix0uRS-E",[908,913,917,918,924,929,934,939,945,950,955,960,966,971],{"path":909,"title":910,"description":911,"order":374,"key":912},"\u002Fen\u002Fdocs\u002Fgetting-started","Getting started","From an empty project to a working sign-in, and the packages that get you there.","getting-started\u002Findex",{"path":236,"title":237,"description":914,"order":915,"key":916},"The five packages we publish, what each one is for, and the configuration each one takes.",20,"getting-started\u002Finstallation",{"path":902,"title":5,"description":898,"order":374,"key":900},{"path":919,"title":920,"description":921,"order":922,"key":923},"\u002Fen\u002Fdocs\u002Fguides\u002Farchitecture","How Kleora is put together","The shape of the hosted service — one address per environment, two API surfaces, and where state lives. And why self-hosting is not something we support today.",30,"guides\u002Farchitecture",{"path":925,"title":926,"description":927,"order":915,"key":928},"\u002Fen\u002Fdocs\u002Fguides\u002Fconcepts","Workspaces, roles and environments","The five words the product is built from, which of them your tokens carry, and how a change to a role reaches a running application.","guides\u002Fconcepts",{"path":930,"title":931,"description":932,"order":915,"key":933},"\u002Fen\u002Fdocs\u002Fguides","Guides","Wiring Kleora into your stack, the words the product uses, and how the hosted service is put together.","guides\u002Findex",{"path":935,"title":936,"description":937,"order":374,"key":938},"\u002Fen\u002Fdocs\u002Fguides\u002Fquickstarts\u002Fbrowser","Plain browser","One client instance, one callback route, and an access token for every request your application makes.","guides\u002Fquickstarts\u002Fbrowser",{"path":940,"title":941,"description":942,"order":943,"key":944},"\u002Fen\u002Fdocs\u002Fguides\u002Fquickstarts\u002Fexpress","Express","Verifying the access token on your own API — middleware, permissions, and the three answers a refusal can have.",40,"guides\u002Fquickstarts\u002Fexpress",{"path":946,"title":947,"description":948,"order":374,"key":949},"\u002Fen\u002Fdocs\u002Fguides\u002Fquickstarts","Framework quickstarts","One page per stack — Next.js, Nuxt, Express and the plain browser — and the two redirect URIs all of them share.","guides\u002Fquickstarts\u002Findex",{"path":951,"title":952,"description":953,"order":915,"key":954},"\u002Fen\u002Fdocs\u002Fguides\u002Fquickstarts\u002Fnextjs","Next.js","The browser SDK in an App Router application — a lazy client, a callback route, and token verification in a route handler.","guides\u002Fquickstarts\u002Fnextjs",{"path":956,"title":957,"description":958,"order":922,"key":959},"\u002Fen\u002Fdocs\u002Fguides\u002Fquickstarts\u002Fnuxt","Nuxt","The Nuxt module — two lines of config, a callback page you do not write, and a route middleware that protects a page from its own meta.","guides\u002Fquickstarts\u002Fnuxt",{"path":961,"title":962,"description":963,"order":964,"key":965},"\u002Fen\u002Fdocs","Kleora documentation","Add hosted sign-in to your application, verify the token on your API, and manage users, workspaces and roles from one console.",0,"index",{"path":967,"title":968,"description":969,"order":374,"key":970},"\u002Fen\u002Fdocs\u002Freference\u002Fcode-highlighting","Code highlighting","One fence per preloaded Shiki grammar — a fixture, not a reference page.","reference\u002Fcode-highlighting",{"path":972,"title":973,"description":974,"order":922,"key":975},"\u002Fen\u002Fdocs\u002Freference","Reference","Reference material for the HTTP APIs and the SDK packages.","reference\u002Findex",1790698197242]