[{"data":1,"prerenderedAt":887},["ShallowReactive",2],{"docs:doc:\u002Fpl\u002Fdocs\u002Fprzewodniki\u002Fframeworki\u002Fnuxt":3,"docs:pages:docs_pl":817},{"id":4,"title":5,"alt":6,"body":7,"description":807,"extension":808,"key":809,"meta":810,"navigation":376,"order":811,"path":812,"placeholder":813,"seo":814,"stem":815,"__hash__":816},"docs_pl\u002Fpl\u002Fdocs\u002Fprzewodniki\u002Fframeworki\u002Fnuxt.md","Nuxt","\u002Fen\u002Fdocs\u002Fguides\u002Fquickstarts\u002Fnuxt",{"type":8,"value":9,"toc":800},"minimark",[10,22,47,52,118,139,142,255,268,272,510,520,524,531,574,577,581,623,643,647,771,796],[11,12,13,17,18,21],"p",{},[14,15,16],"code",{},"@kleora-io\u002Fnuxt"," to SDK przeglądarkowe w formie modułu Nuxt 4: trzyma\nklienta, dodaje stronę powrotu, rejestruje middleware tras i daje uwierzytelniony\n",[14,19,20],{},"$fetch",".",[23,24,29],"pre",{"className":25,"code":26,"language":27,"meta":28,"style":28},"language-bash shiki shiki-themes github-light","npm install @kleora-io\u002Fnuxt\n","bash","",[14,30,31],{"__ignoreMap":28},[32,33,36,40,44],"span",{"class":34,"line":35},"line",1,[32,37,39],{"class":38},"s7eDp","npm",[32,41,43],{"class":42},"sYBdl"," install",[32,45,46],{"class":42}," @kleora-io\u002Fnuxt\n",[48,49,51],"h2",{"id":50},"_1-zarejestruj-moduł","1. Zarejestruj moduł",[23,53,57],{"className":54,"code":55,"language":56,"meta":28,"style":28},"language-ts shiki shiki-themes github-light","\u002F\u002F nuxt.config.ts\nexport default defineNuxtConfig({\n  modules: ['@kleora-io\u002Fnuxt'],\n  kleora: { issuer: '\u003Cissuer>', clientId: '\u003Cclient_id>' },\n})\n","ts",[14,58,59,65,82,94,112],{"__ignoreMap":28},[32,60,61],{"class":34,"line":35},[32,62,64],{"class":63},"sAwPA","\u002F\u002F nuxt.config.ts\n",[32,66,68,72,75,78],{"class":34,"line":67},2,[32,69,71],{"class":70},"sD7c4","export",[32,73,74],{"class":70}," default",[32,76,77],{"class":38}," defineNuxtConfig",[32,79,81],{"class":80},"sgsFI","({\n",[32,83,85,88,91],{"class":34,"line":84},3,[32,86,87],{"class":80},"  modules: [",[32,89,90],{"class":42},"'@kleora-io\u002Fnuxt'",[32,92,93],{"class":80},"],\n",[32,95,97,100,103,106,109],{"class":34,"line":96},4,[32,98,99],{"class":80},"  kleora: { issuer: ",[32,101,102],{"class":42},"'\u003Cissuer>'",[32,104,105],{"class":80},", clientId: ",[32,107,108],{"class":42},"'\u003Cclient_id>'",[32,110,111],{"class":80}," },\n",[32,113,115],{"class":34,"line":114},5,[32,116,117],{"class":80},"})\n",[11,119,120,123,124,127,128,131,132,138],{},[14,121,122],{},"issuer"," i ",[14,125,126],{},"clientId"," to jedyne wymagane opcje — pusta wartość rzuca błędem przy\nstarcie aplikacji, nazywając zarówno opcję, jak i zmienną środowiskową, która by\nją ustawiła. Nie ma tu ",[14,129,130],{},"redirectUri",", bo moduł domyślnie ustawia go na własną stronę\npowrotu w origin, z którego serwowana jest witryna: ",[133,134,135],"strong",{},[14,136,137],{},"\u002Fauth\u002Fcallback",". To\nnadal jest adres, który rejestrujesz na kliencie, dokładnie w tej postaci.",[11,140,141],{},"Osiem opcji można podać ze środowiska zamiast z pliku konfiguracyjnego — tak\njeden build obsługuje sandbox i produkcję:",[143,144,145,158],"table",{},[146,147,148],"thead",{},[149,150,151,155],"tr",{},[152,153,154],"th",{},"Opcja",[152,156,157],{},"Zmienna",[159,160,161,173,184,195,207,219,231,243],"tbody",{},[149,162,163,168],{},[164,165,166],"td",{},[14,167,122],{},[164,169,170],{},[14,171,172],{},"NUXT_PUBLIC_KLEORA_ISSUER",[149,174,175,179],{},[164,176,177],{},[14,178,126],{},[164,180,181],{},[14,182,183],{},"NUXT_PUBLIC_KLEORA_CLIENT_ID",[149,185,186,190],{},[164,187,188],{},[14,189,130],{},[164,191,192],{},[14,193,194],{},"NUXT_PUBLIC_KLEORA_REDIRECT_URI",[149,196,197,202],{},[164,198,199],{},[14,200,201],{},"scope",[164,203,204],{},[14,205,206],{},"NUXT_PUBLIC_KLEORA_SCOPE",[149,208,209,214],{},[164,210,211],{},[14,212,213],{},"audience",[164,215,216],{},[14,217,218],{},"NUXT_PUBLIC_KLEORA_AUDIENCE",[149,220,221,226],{},[164,222,223],{},[14,224,225],{},"tenant",[164,227,228],{},[14,229,230],{},"NUXT_PUBLIC_KLEORA_TENANT",[149,232,233,238],{},[164,234,235],{},[14,236,237],{},"storage",[164,239,240],{},[14,241,242],{},"NUXT_PUBLIC_KLEORA_STORAGE",[149,244,245,250],{},[164,246,247],{},[14,248,249],{},"apiBase",[164,251,252],{},[14,253,254],{},"NUXT_PUBLIC_API_BASE",[11,256,257,258,261,262,265,266,21],{},"Dziewiąta, ",[14,259,260],{},"callbackPath",", działa wyłącznie w czasie budowania: moduł montuje pod\nnią trasę podczas builda, więc zmienna środowiskowa przesunęłaby miejsce, gdzie\nląduje przeglądarka, nie przesuwając strony, która to obsługuje. Ustaw ją w\n",[14,263,264],{},"nuxt.config"," i trzymaj równą ścieżce z ",[14,267,130],{},[48,269,271],{"id":270},"_2-zaloguj-się-ze-strony","2. Zaloguj się ze strony",[23,273,277],{"className":274,"code":275,"language":276,"meta":28,"style":28},"language-vue shiki shiki-themes github-light","\u003C!-- app\u002Fpages\u002Findex.vue -->\n\u003Cscript setup lang=\"ts\">\nconst { isAuthenticated, isLoading, login, logout } = useKleora()\nconst user = useKleoraUser()\n\u003C\u002Fscript>\n\n\u003Ctemplate>\n  \u003Cp v-if=\"isLoading\">Wczytywanie…\u003C\u002Fp>\n  \u003Cbutton v-else-if=\"!isAuthenticated\" @click=\"login()\">Zaloguj się\u003C\u002Fbutton>\n  \u003Cdiv v-else>\n    \u003Cp>{{ user?.sub }} · {{ user?.email }} · {{ user?.tenant }}\u003C\u002Fp>\n    \u003Cbutton @click=\"logout({ returnTo: '\u002F' })\">Wyloguj się\u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n","vue",[14,278,279,284,308,347,362,371,378,388,411,442,455,470,491,501],{"__ignoreMap":28},[32,280,281],{"class":34,"line":35},[32,282,283],{"class":63},"\u003C!-- app\u002Fpages\u002Findex.vue -->\n",[32,285,286,289,293,296,299,302,305],{"class":34,"line":67},[32,287,288],{"class":80},"\u003C",[32,290,292],{"class":291},"shJU0","script",[32,294,295],{"class":38}," setup",[32,297,298],{"class":38}," lang",[32,300,301],{"class":80},"=",[32,303,304],{"class":42},"\"ts\"",[32,306,307],{"class":80},">\n",[32,309,310,313,316,320,323,326,328,331,333,336,339,341,344],{"class":34,"line":84},[32,311,312],{"class":70},"const",[32,314,315],{"class":80}," { ",[32,317,319],{"class":318},"sYu0t","isAuthenticated",[32,321,322],{"class":80},", ",[32,324,325],{"class":318},"isLoading",[32,327,322],{"class":80},[32,329,330],{"class":318},"login",[32,332,322],{"class":80},[32,334,335],{"class":318},"logout",[32,337,338],{"class":80}," } ",[32,340,301],{"class":70},[32,342,343],{"class":38}," useKleora",[32,345,346],{"class":80},"()\n",[32,348,349,351,354,357,360],{"class":34,"line":96},[32,350,312],{"class":70},[32,352,353],{"class":318}," user",[32,355,356],{"class":70}," =",[32,358,359],{"class":38}," useKleoraUser",[32,361,346],{"class":80},[32,363,364,367,369],{"class":34,"line":114},[32,365,366],{"class":80},"\u003C\u002F",[32,368,292],{"class":291},[32,370,307],{"class":80},[32,372,374],{"class":34,"line":373},6,[32,375,377],{"emptyLinePlaceholder":376},true,"\n",[32,379,381,383,386],{"class":34,"line":380},7,[32,382,288],{"class":80},[32,384,385],{"class":291},"template",[32,387,307],{"class":80},[32,389,391,394,396,399,401,404,407,409],{"class":34,"line":390},8,[32,392,393],{"class":80},"  \u003C",[32,395,11],{"class":291},[32,397,398],{"class":38}," v-if",[32,400,301],{"class":80},[32,402,403],{"class":42},"\"isLoading\"",[32,405,406],{"class":80},">Wczytywanie…\u003C\u002F",[32,408,11],{"class":291},[32,410,307],{"class":80},[32,412,414,416,419,422,424,427,430,432,435,438,440],{"class":34,"line":413},9,[32,415,393],{"class":80},[32,417,418],{"class":291},"button",[32,420,421],{"class":38}," v-else-if",[32,423,301],{"class":80},[32,425,426],{"class":42},"\"!isAuthenticated\"",[32,428,429],{"class":38}," @click",[32,431,301],{"class":80},[32,433,434],{"class":42},"\"login()\"",[32,436,437],{"class":80},">Zaloguj się\u003C\u002F",[32,439,418],{"class":291},[32,441,307],{"class":80},[32,443,445,447,450,453],{"class":34,"line":444},10,[32,446,393],{"class":80},[32,448,449],{"class":291},"div",[32,451,452],{"class":38}," v-else",[32,454,307],{"class":80},[32,456,458,461,463,466,468],{"class":34,"line":457},11,[32,459,460],{"class":80},"    \u003C",[32,462,11],{"class":291},[32,464,465],{"class":80},">{{ user?.sub }} · {{ user?.email }} · {{ user?.tenant }}\u003C\u002F",[32,467,11],{"class":291},[32,469,307],{"class":80},[32,471,473,475,477,479,481,484,487,489],{"class":34,"line":472},12,[32,474,460],{"class":80},[32,476,418],{"class":291},[32,478,429],{"class":38},[32,480,301],{"class":80},[32,482,483],{"class":42},"\"logout({ returnTo: '\u002F' })\"",[32,485,486],{"class":80},">Wyloguj się\u003C\u002F",[32,488,418],{"class":291},[32,490,307],{"class":80},[32,492,494,497,499],{"class":34,"line":493},13,[32,495,496],{"class":80},"  \u003C\u002F",[32,498,449],{"class":291},[32,500,307],{"class":80},[32,502,504,506,508],{"class":34,"line":503},14,[32,505,366],{"class":80},[32,507,385],{"class":291},[32,509,307],{"class":80},[11,511,512,515,516,519],{},[14,513,514],{},"logout()"," bez argumentu odsyła przeglądarkę na korzeń witryny, więc ",[14,517,518],{},"\u002F"," w Twoim\norigin musi być jednym z zarejestrowanych adresów po wylogowaniu.",[48,521,523],{"id":522},"_3-chroń-stronę","3. Chroń stronę",[11,525,526,527,530],{},"Moduł rejestruje globalny middleware o nazwie ",[14,528,529],{},"kleora",", a ten działa tylko\nna stronach, które o to proszą:",[23,532,534],{"className":274,"code":533,"language":276,"meta":28,"style":28},"\u003Cscript setup lang=\"ts\">\ndefinePageMeta({ auth: true })\n\u003C\u002Fscript>\n",[14,535,536,552,566],{"__ignoreMap":28},[32,537,538,540,542,544,546,548,550],{"class":34,"line":35},[32,539,288],{"class":80},[32,541,292],{"class":291},[32,543,295],{"class":38},[32,545,298],{"class":38},[32,547,301],{"class":80},[32,549,304],{"class":42},[32,551,307],{"class":80},[32,553,554,557,560,563],{"class":34,"line":67},[32,555,556],{"class":38},"definePageMeta",[32,558,559],{"class":80},"({ auth: ",[32,561,562],{"class":318},"true",[32,564,565],{"class":80}," })\n",[32,567,568,570,572],{"class":34,"line":84},[32,569,366],{"class":80},[32,571,292],{"class":291},[32,573,307],{"class":80},[11,575,576],{},"Ochrona leży w metadanych samej strony, więc strona nie traci jej przez to, że\nktoś zapomniał dopisać ją do listy gdzie indziej. Middleware działa po stronie\nklienta: renderowanie na serwerze oddaje szkielet dla niezalogowanego i nigdy nie\nprzekierowuje.",[48,578,580],{"id":579},"_4-wołaj-api-z-dołączonym-tokenem","4. Wołaj API z dołączonym tokenem",[23,582,584],{"className":54,"code":583,"language":56,"meta":28,"style":28},"const api = useKleoraApi()\nconst invoices = await api('\u002Finvoices')\n",[14,585,586,600],{"__ignoreMap":28},[32,587,588,590,593,595,598],{"class":34,"line":35},[32,589,312],{"class":70},[32,591,592],{"class":318}," api",[32,594,356],{"class":70},[32,596,597],{"class":38}," useKleoraApi",[32,599,346],{"class":80},[32,601,602,604,607,609,612,614,617,620],{"class":34,"line":67},[32,603,312],{"class":70},[32,605,606],{"class":318}," invoices",[32,608,356],{"class":70},[32,610,611],{"class":70}," await",[32,613,592],{"class":38},[32,615,616],{"class":80},"(",[32,618,619],{"class":42},"'\u002Finvoices'",[32,621,622],{"class":80},")\n",[11,624,625,628,629,631,632,634,635,638,639,642],{},[14,626,627],{},"$kleoraApi"," to instancja ",[14,630,20],{}," z ",[14,633,249],{}," jako bazowym adresem i tokenem\nw każdym żądaniu. ",[14,636,637],{},"401"," jest ponawiane dokładnie raz, z wymuszonym odświeżeniem\n— więc odrzucony token nigdy nie leci po prostu drugi raz — a błąd przychodzi\njako ",[14,640,641],{},"ApiError"," z dokumentem problemu RFC 9457, nie jako sam kod statusu.",[48,644,646],{"id":645},"co-daje-moduł","Co daje moduł",[143,648,649,659],{},[146,650,651],{},[149,652,653,656],{},[152,654,655],{},"Eksport",[152,657,658],{},"Czym jest",[159,660,661,697,713,726,748,762],{},[149,662,663,668],{},[164,664,665],{},[14,666,667],{},"useKleora()",[164,669,670,671,322,674,322,677,322,679,322,681,322,684,322,686,322,688,322,691,322,694,21],{},"Kontekst: ",[14,672,673],{},"client",[14,675,676],{},"user",[14,678,319],{},[14,680,325],{},[14,682,683],{},"hasLikelySession",[14,685,330],{},[14,687,335],{},[14,689,690],{},"getAccessToken",[14,692,693],{},"restore",[14,695,696],{},"settle",[149,698,699,704],{},[164,700,701],{},[14,702,703],{},"useKleoraUser()",[164,705,706,709,710,21],{},[14,707,708],{},"Ref"," z zalogowanym użytkownikiem albo ",[14,711,712],{},"null",[149,714,715,720],{},[164,716,717],{},[14,718,719],{},"useKleoraApi()",[164,721,722,723,725],{},"Uwierzytelniona instancja ",[14,724,20],{}," jako composable.",[149,727,728,733],{},[164,729,730],{},[14,731,732],{},"decideSessionRender()",[164,734,735,736,739,740,743,744,747],{},"Odwzorowuje ",[14,737,738],{},"{ hasMarker, isLoading, isAuthenticated }"," na ",[14,741,742],{},"'shell'"," albo ",[14,745,746],{},"'redirect'"," — dla layoutu, który inaczej by mignął.",[149,749,750,756],{},[164,751,752,753],{},"middleware ",[14,754,755],{},"kleora-auth",[164,757,758,759,21],{},"Globalny, wyzwalany przez ",[14,760,761],{},"definePageMeta({ auth: true })",[149,763,764,768],{},[164,765,766],{},[14,767,137],{},[164,769,770],{},"Strona dodawana przez moduł — chyba że Twoja aplikacja ma już własną pod tą ścieżką.",[772,773,776],"callout",{"title":774,"type":775},"Uwierzytelnianie dzieje się tylko po stronie klienta","note",[11,777,778,779,781,782,322,784,786,787,789,790,792,793,795],{},"Renderowanie na serwerze oddaje szkielet dla niezalogowanego: ",[14,780,325],{}," jest\n",[14,783,562],{},[14,785,676],{}," jest ",[14,788,712],{},", a ",[14,791,627],{}," rzuca wyjątkiem, jeśli wywołasz go\nna serwerze. Strony nie mogą zakładać użytkownika w trakcie SSR; fragmenty\nzwiązane z ",[14,794,319],{}," wypełniają się przy hydracji.",[797,798,799],"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 .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}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 .shJU0, html code.shiki .shJU0{--shiki-default:#22863A}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}",{"title":28,"searchDepth":84,"depth":84,"links":801},[802,803,804,805,806],{"id":50,"depth":67,"text":51},{"id":270,"depth":67,"text":271},{"id":522,"depth":67,"text":523},{"id":579,"depth":67,"text":580},{"id":645,"depth":67,"text":646},"Moduł dla Nuxt — dwie linijki konfiguracji, strona powrotu, której nie piszesz, i middleware chroniący stronę z jej własnych metadanych.","md","guides\u002Fquickstarts\u002Fnuxt",{},30,"\u002Fpl\u002Fdocs\u002Fprzewodniki\u002Fframeworki\u002Fnuxt",false,{"title":5,"description":807},"pl\u002Fdocs\u002Fprzewodniki\u002Fframeworki\u002Fnuxt","n87T8Yvla9UI3rFOadsDvO9LBo5weRrMVRJmt9iX-sk",[818,824,829,835,840,845,851,856,861,862,867,872,877,882],{"path":819,"title":820,"description":821,"order":822,"key":823},"\u002Fpl\u002Fdocs","Dokumentacja Kleora","Dodaj hostowane logowanie do swojej aplikacji, sprawdź token w swoim API i zarządzaj użytkownikami, przestrzeniami roboczymi i rolami z jednej konsoli.",0,"index",{"path":825,"title":826,"description":827,"order":444,"key":828},"\u002Fpl\u002Fdocs\u002Fpierwsze-kroki","Pierwsze kroki","Od pustego projektu do działającego logowania — i paczki, które do tego prowadzą.","getting-started\u002Findex",{"path":830,"title":831,"description":832,"order":833,"key":834},"\u002Fpl\u002Fdocs\u002Fpierwsze-kroki\u002Finstalacja","Instalacja SDK","Pięć paczek, które publikujemy, do czego służy każda z nich i jakiej konfiguracji wymaga.",20,"getting-started\u002Finstallation",{"path":836,"title":837,"description":838,"order":444,"key":839},"\u002Fpl\u002Fdocs\u002Fpierwsze-kroki\u002Fszybki-start","Szybki start","Załóż aplikację, podłącz SDK przeglądarkowe i zaloguj się po raz pierwszy — w całości w sandboksie.","getting-started\u002Fquickstart",{"path":841,"title":842,"description":843,"order":811,"key":844},"\u002Fpl\u002Fdocs\u002Fprzewodniki\u002Farchitektura","Jak zbudowana jest Kleora","Kształt usługi hostowanej — jeden adres na środowisko, dwie powierzchnie API i miejsce, w którym leży stan. Oraz dlaczego hostowania u siebie dzisiaj nie wspieramy.","guides\u002Farchitecture",{"path":846,"title":847,"description":848,"order":849,"key":850},"\u002Fpl\u002Fdocs\u002Fprzewodniki\u002Fframeworki\u002Fexpress","Express","Sprawdzanie tokenu dostępu we własnym API — middleware, uprawnienia i trzy odpowiedzi, jakie może mieć odmowa.",40,"guides\u002Fquickstarts\u002Fexpress",{"path":852,"title":853,"description":854,"order":444,"key":855},"\u002Fpl\u002Fdocs\u002Fprzewodniki\u002Fframeworki","Szybki start dla frameworków","Po jednej stronie na stos — Next.js, Nuxt, Express i zwykła przeglądarka — i dwa adresy powrotne, które łączą je wszystkie.","guides\u002Fquickstarts\u002Findex",{"path":857,"title":858,"description":859,"order":833,"key":860},"\u002Fpl\u002Fdocs\u002Fprzewodniki\u002Fframeworki\u002Fnextjs","Next.js","SDK przeglądarkowe w aplikacji na App Router — leniwy klient, trasa powrotna i sprawdzanie tokenu w route handlerze.","guides\u002Fquickstarts\u002Fnextjs",{"path":812,"title":5,"description":807,"order":811,"key":809},{"path":863,"title":864,"description":865,"order":444,"key":866},"\u002Fpl\u002Fdocs\u002Fprzewodniki\u002Fframeworki\u002Fprzegladarka","Zwykła przeglądarka","Jedna instancja klienta, jedna trasa powrotna i token dostępu do każdego żądania, które wysyła Twoja aplikacja.","guides\u002Fquickstarts\u002Fbrowser",{"path":868,"title":869,"description":870,"order":833,"key":871},"\u002Fpl\u002Fdocs\u002Fprzewodniki","Przewodniki","Jak podłączyć usługę Kleora do swojego stosu, jakich słów używa produkt i jak zbudowana jest usługa hostowana.","guides\u002Findex",{"path":873,"title":874,"description":875,"order":833,"key":876},"\u002Fpl\u002Fdocs\u002Fprzewodniki\u002Fpojecia","Przestrzenie robocze, role i środowiska","Pięć słów, z których zbudowany jest produkt, to, które z nich niosą Twoje tokeny, i jak zmiana roli dociera do działającej aplikacji.","guides\u002Fconcepts",{"path":878,"title":879,"description":880,"order":811,"key":881},"\u002Fpl\u002Fdocs\u002Freferencje","Referencje","Materiały referencyjne dla API HTTP i paczek SDK.","reference\u002Findex",{"path":883,"title":884,"description":885,"order":444,"key":886},"\u002Fpl\u002Fdocs\u002Freferencje\u002Fpodswietlanie","Podświetlanie kodu","Po jednym bloku na każdą wstępnie wczytaną gramatykę Shiki — próbka, nie strona referencyjna.","reference\u002Fcode-highlighting",1790698198124]