[{"data":1,"prerenderedAt":1338},["ShallowReactive",2],{"docs:doc:\u002Fpl\u002Fdocs\u002Fpierwsze-kroki\u002Finstalacja":3,"docs:pages:docs_pl":1269},{"id":4,"title":5,"alt":6,"body":7,"description":1259,"extension":1260,"key":1261,"meta":1262,"navigation":504,"order":1263,"path":1264,"placeholder":1265,"seo":1266,"stem":1267,"__hash__":1268},"docs_pl\u002Fpl\u002Fdocs\u002Fpierwsze-kroki\u002Finstalacja.md","Instalacja SDK","\u002Fen\u002Fdocs\u002Fgetting-started\u002Finstallation",{"type":8,"value":9,"toc":1250},"minimark",[10,28,31,121,127,130,155,161,292,300,305,312,326,637,647,650,731,765,770,773,787,819,825,828,843,981,984,988,1000,1014,1104,1213,1235,1239,1246],[11,12,15],"callout",{"title":13,"type":14},"Paczek nie ma jeszcze w repozytoriach","warning",[16,17,18,19,23,24,27],"p",{},"Każda z poniższych paczek jest w wersji ",[20,21,22],"code",{},"0.1.0"," i trafi do npm oraz PyPI razem z\nwydaniem ",[20,25,26],{},"1.0.0",". Polecenia to te, którymi będzie się je instalować.",[16,29,30],{},"Pięć paczek, wszystkie na licencji Apache-2.0 i wszystkie opcjonalne: Kleora\njest dostawcą OAuth 2.1 i OpenID Connect, więc dowolna biblioteka kliencka\nzadziała z nią tak samo.",[32,33,34,50],"table",{},[35,36,37],"thead",{},[38,39,40,44,47],"tr",{},[41,42,43],"th",{},"Paczka",[41,45,46],{},"Do czego służy",[41,48,49],{},"Wymaga",[51,52,53,67,80,93,106],"tbody",{},[38,54,55,61,64],{},[56,57,58],"td",{},[20,59,60],{},"@kleora-io\u002Fbrowser",[56,62,63],{},"Logowanie z aplikacji jednostronicowej.",[56,65,66],{},"Node 22+ do zbudowania; aktualne przeglądarki",[38,68,69,74,77],{},[56,70,71],{},[20,72,73],{},"@kleora-io\u002Fnuxt",[56,75,76],{},"To samo, w postaci modułu Nuxta.",[56,78,79],{},"Nuxt 4, Node 22+",[38,81,82,87,90],{},[56,83,84],{},[20,85,86],{},"@kleora-io\u002Fnode",[56,88,89],{},"Sprawdzanie tokenów dostępu w API na Node i wywołania API zarządzania.",[56,91,92],{},"Node 20+",[38,94,95,100,103],{},[56,96,97],{},[20,98,99],{},"kleora",[56,101,102],{},"To samo w Pythonie.",[56,104,105],{},"Python 3.12+",[38,107,108,113,119],{},[56,109,110],{},[20,111,112],{},"django-kleora",[56,114,115,116,118],{},"Integracja z Django, zbudowana na ",[20,117,99],{},".",[56,120,105],{},[122,123,125],"h2",{"id":124},"kleora-iobrowser",[20,126,60],{},[16,128,129],{},"Klient kodu autoryzacyjnego z PKCE. Bez zależności w czasie działania, wyłącznie\nmoduły ES.",[131,132,137],"pre",{"className":133,"code":134,"language":135,"meta":136,"style":136},"language-bash shiki shiki-themes github-light","npm install @kleora-io\u002Fbrowser\n","bash","",[20,138,139],{"__ignoreMap":136},[140,141,144,148,152],"span",{"class":142,"line":143},"line",1,[140,145,147],{"class":146},"s7eDp","npm",[140,149,151],{"class":150},"sYBdl"," install",[140,153,154],{"class":150}," @kleora-io\u002Fbrowser\n",[16,156,157,160],{},[20,158,159],{},"createKleora()"," przyjmuje trzy opcje obowiązkowe i cztery opcjonalne:",[32,162,163,176],{},[35,164,165],{},[38,166,167,170,173],{},[41,168,169],{},"Opcja",[41,171,172],{},"Domyślnie",[41,174,175],{},"Znaczenie",[51,177,178,195,213,225,244,256,268],{},[38,179,180,185,188],{},[56,181,182],{},[20,183,184],{},"issuer",[56,186,187],{},"—",[56,189,190,191,194],{},"Adres środowiska, np. ",[20,192,193],{},"https:\u002F\u002Facme.kleora.eu",". Ukośnik na końcu jest normalizowany.",[38,196,197,202,204],{},[56,198,199],{},[20,200,201],{},"clientId",[56,203,187],{},[56,205,206,209,210,118],{},[20,207,208],{},"client_id"," klienta. Musi to być klient typu ",[20,211,212],{},"spa",[38,214,215,220,222],{},[56,216,217],{},[20,218,219],{},"redirectUri",[56,221,187],{},[56,223,224],{},"Jeden z zarejestrowanych adresów powrotnych tego klienta, porównywany dokładnie.",[38,226,227,232,237],{},[56,228,229],{},[20,230,231],{},"scope",[56,233,234],{},[20,235,236],{},"openid profile email offline_access",[56,238,239,240,243],{},"Bez ",[20,241,242],{},"offline_access"," nie dostaniesz tokenu odświeżania, więc tokenu dostępu nie da się po cichu odnowić.",[38,245,246,251,253],{},[56,247,248],{},[20,249,250],{},"audience",[56,252,187],{},[56,254,255],{},"Audience API środowiska, o ile zostało ustawione.",[38,257,258,263,265],{},[56,259,260],{},[20,261,262],{},"tenant",[56,264,187],{},[56,266,267],{},"Przypina każde logowanie do jednej przestrzeni roboczej (po slugu).",[38,269,270,275,280],{},[56,271,272],{},[20,273,274],{},"storage",[56,276,277],{},[20,278,279],{},"memory",[56,281,282,284,285,288,289,118],{},[20,283,279],{}," albo ",[20,286,287],{},"session",". Nigdy ",[20,290,291],{},"localStorage",[16,293,294,295,118],{},"Działającą stronę od początku do końca pokazuje ",[296,297,299],"a",{"href":298},"\u002Fpl\u002Fdocs\u002Fpierwsze-kroki\u002Fszybki-start","szybki\nstart",[122,301,303],{"id":302},"kleora-ionuxt",[20,304,73],{},[16,306,307,308,311],{},"Moduł do Nuxta 4 opakowujący SDK przeglądarkowe: automatycznie importowane\ncomposable, strażnik trasy, strona callbacku i instancja ",[20,309,310],{},"$fetch"," z tokenem.",[131,313,315],{"className":133,"code":314,"language":135,"meta":136,"style":136},"npm install @kleora-io\u002Fnuxt\n",[20,316,317],{"__ignoreMap":136},[140,318,319,321,323],{"class":142,"line":143},[140,320,147],{"class":146},[140,322,151],{"class":150},[140,324,325],{"class":150}," @kleora-io\u002Fnuxt\n",[327,328,329,398],"code-tabs",{},[330,331,332],"template",{"v-slot:ts":136},[131,333,337],{"className":334,"code":335,"language":336,"meta":136,"style":136},"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",[20,338,339,345,362,374,392],{"__ignoreMap":136},[140,340,341],{"class":142,"line":143},[140,342,344],{"class":343},"sAwPA","\u002F\u002F nuxt.config.ts\n",[140,346,348,352,355,358],{"class":142,"line":347},2,[140,349,351],{"class":350},"sD7c4","export",[140,353,354],{"class":350}," default",[140,356,357],{"class":146}," defineNuxtConfig",[140,359,361],{"class":360},"sgsFI","({\n",[140,363,365,368,371],{"class":142,"line":364},3,[140,366,367],{"class":360},"  modules: [",[140,369,370],{"class":150},"'@kleora-io\u002Fnuxt'",[140,372,373],{"class":360},"],\n",[140,375,377,380,383,386,389],{"class":142,"line":376},4,[140,378,379],{"class":360},"  kleora: { issuer: ",[140,381,382],{"class":150},"'\u003Cissuer>'",[140,384,385],{"class":360},", clientId: ",[140,387,388],{"class":150},"'\u003Cclient_id>'",[140,390,391],{"class":360}," },\n",[140,393,395],{"class":142,"line":394},5,[140,396,397],{"class":360},"})\n",[330,399,400],{"v-slot:vue":136},[131,401,405],{"className":402,"code":403,"language":404,"meta":136,"style":136},"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\">Loading…\u003C\u002Fp>\n  \u003Cbutton v-else-if=\"!isAuthenticated\" @click=\"login()\">Sign in\u003C\u002Fbutton>\n  \u003Cdiv v-else>\n    \u003Cp>{{ user?.sub }} · {{ user?.email }} · {{ user?.tenant }}\u003C\u002Fp>\n    \u003Cbutton @click=\"logout({ returnTo: '\u002F' })\">Sign out\u003C\u002Fbutton>\n  \u003C\u002Fdiv>\n\u003C\u002Ftemplate>\n","vue",[20,406,407,412,436,475,490,499,506,515,538,569,582,597,618,628],{"__ignoreMap":136},[140,408,409],{"class":142,"line":143},[140,410,411],{"class":343},"\u003C!-- app\u002Fpages\u002Findex.vue -->\n",[140,413,414,417,421,424,427,430,433],{"class":142,"line":347},[140,415,416],{"class":360},"\u003C",[140,418,420],{"class":419},"shJU0","script",[140,422,423],{"class":146}," setup",[140,425,426],{"class":146}," lang",[140,428,429],{"class":360},"=",[140,431,432],{"class":150},"\"ts\"",[140,434,435],{"class":360},">\n",[140,437,438,441,444,448,451,454,456,459,461,464,467,469,472],{"class":142,"line":364},[140,439,440],{"class":350},"const",[140,442,443],{"class":360}," { ",[140,445,447],{"class":446},"sYu0t","isAuthenticated",[140,449,450],{"class":360},", ",[140,452,453],{"class":446},"isLoading",[140,455,450],{"class":360},[140,457,458],{"class":446},"login",[140,460,450],{"class":360},[140,462,463],{"class":446},"logout",[140,465,466],{"class":360}," } ",[140,468,429],{"class":350},[140,470,471],{"class":146}," useKleora",[140,473,474],{"class":360},"()\n",[140,476,477,479,482,485,488],{"class":142,"line":376},[140,478,440],{"class":350},[140,480,481],{"class":446}," user",[140,483,484],{"class":350}," =",[140,486,487],{"class":146}," useKleoraUser",[140,489,474],{"class":360},[140,491,492,495,497],{"class":142,"line":394},[140,493,494],{"class":360},"\u003C\u002F",[140,496,420],{"class":419},[140,498,435],{"class":360},[140,500,502],{"class":142,"line":501},6,[140,503,505],{"emptyLinePlaceholder":504},true,"\n",[140,507,509,511,513],{"class":142,"line":508},7,[140,510,416],{"class":360},[140,512,330],{"class":419},[140,514,435],{"class":360},[140,516,518,521,523,526,528,531,534,536],{"class":142,"line":517},8,[140,519,520],{"class":360},"  \u003C",[140,522,16],{"class":419},[140,524,525],{"class":146}," v-if",[140,527,429],{"class":360},[140,529,530],{"class":150},"\"isLoading\"",[140,532,533],{"class":360},">Loading…\u003C\u002F",[140,535,16],{"class":419},[140,537,435],{"class":360},[140,539,541,543,546,549,551,554,557,559,562,565,567],{"class":142,"line":540},9,[140,542,520],{"class":360},[140,544,545],{"class":419},"button",[140,547,548],{"class":146}," v-else-if",[140,550,429],{"class":360},[140,552,553],{"class":150},"\"!isAuthenticated\"",[140,555,556],{"class":146}," @click",[140,558,429],{"class":360},[140,560,561],{"class":150},"\"login()\"",[140,563,564],{"class":360},">Sign in\u003C\u002F",[140,566,545],{"class":419},[140,568,435],{"class":360},[140,570,572,574,577,580],{"class":142,"line":571},10,[140,573,520],{"class":360},[140,575,576],{"class":419},"div",[140,578,579],{"class":146}," v-else",[140,581,435],{"class":360},[140,583,585,588,590,593,595],{"class":142,"line":584},11,[140,586,587],{"class":360},"    \u003C",[140,589,16],{"class":419},[140,591,592],{"class":360},">{{ user?.sub }} · {{ user?.email }} · {{ user?.tenant }}\u003C\u002F",[140,594,16],{"class":419},[140,596,435],{"class":360},[140,598,600,602,604,606,608,611,614,616],{"class":142,"line":599},12,[140,601,587],{"class":360},[140,603,545],{"class":419},[140,605,556],{"class":146},[140,607,429],{"class":360},[140,609,610],{"class":150},"\"logout({ returnTo: '\u002F' })\"",[140,612,613],{"class":360},">Sign out\u003C\u002F",[140,615,545],{"class":419},[140,617,435],{"class":360},[140,619,621,624,626],{"class":142,"line":620},13,[140,622,623],{"class":360},"  \u003C\u002F",[140,625,576],{"class":419},[140,627,435],{"class":360},[140,629,631,633,635],{"class":142,"line":630},14,[140,632,494],{"class":360},[140,634,330],{"class":419},[140,636,435],{"class":360},[16,638,639,640,642,643,646],{},"W tej konfiguracji nie ma ",[20,641,219],{},", bo moduł domyślnie kieruje na własną\nstronę callbacku pod adresem tej samej witryny — ",[20,644,645],{},"\u002Fauth\u002Fcallback",". Ten adres i\ntak trzeba zarejestrować na kliencie.",[16,648,649],{},"Co daje moduł:",[32,651,652,662],{},[35,653,654],{},[38,655,656,659],{},[41,657,658],{},"Eksport",[41,660,661],{},"Czym jest",[51,663,664,676,692,708,722],{},[38,665,666,671],{},[56,667,668],{},[20,669,670],{},"useKleora()",[56,672,673,118],{},[20,674,675],{},"{ client, user, isAuthenticated, isLoading, hasLikelySession, login, logout, getAccessToken, restore, settle }",[38,677,678,683],{},[56,679,680],{},[20,681,682],{},"useKleoraUser()",[56,684,685,688,689,118],{},[20,686,687],{},"Ref"," z zalogowanym użytkownikiem albo ",[20,690,691],{},"null",[38,693,694,702],{},[56,695,696,450,699],{},[20,697,698],{},"useKleoraApi()",[20,700,701],{},"$kleoraApi",[56,703,704,705,707],{},"Instancja ",[20,706,310],{}," z adresem bazowym Twojego API i tokenem w każdym żądaniu.",[38,709,710,716],{},[56,711,712,713],{},"middleware ",[20,714,715],{},"kleora-auth",[56,717,718,719,118],{},"Rejestrowany globalnie, działa tylko na stronach z ",[20,720,721],{},"definePageMeta({ auth: true })",[38,723,724,728],{},[56,725,726],{},[20,727,645],{},[56,729,730],{},"Strona dodawana przez moduł: kończy logowanie i wraca na stronę, z której się zaczęło.",[16,732,733,734,450,737,450,740,450,743,746,747,450,750,450,753,756,757,760,761,764],{},"Każdą opcję można podać ze środowiska zamiast w pliku konfiguracyjnym:\n",[20,735,736],{},"NUXT_PUBLIC_KLEORA_ISSUER",[20,738,739],{},"…_CLIENT_ID",[20,741,742],{},"…_REDIRECT_URI",[20,744,745],{},"…_SCOPE",",\n",[20,748,749],{},"…_AUDIENCE",[20,751,752],{},"…_TENANT",[20,754,755],{},"…_STORAGE"," oraz ",[20,758,759],{},"NUXT_PUBLIC_API_BASE"," dla adresu\nAPI. Jedynym wyjątkiem jest ",[20,762,763],{},"callbackPath"," — decyduje, pod jakim adresem\nmontuje się strona callbacku, więc ustala się go na etapie budowania.",[122,766,768],{"id":767},"kleora-ionode",[20,769,86],{},[16,771,772],{},"Sprawdzanie tokenów dostępu z cache'em JWKS, middleware dla Express i Fastify\noraz typowany klient API zarządzania. Jedyna zależność w czasie działania to\nbiblioteka JOSE; Express i Fastify są opcjonalnymi peer dependencies.",[131,774,776],{"className":133,"code":775,"language":135,"meta":136,"style":136},"npm install @kleora-io\u002Fnode\n",[20,777,778],{"__ignoreMap":136},[140,779,780,782,784],{"class":142,"line":143},[140,781,147],{"class":146},[140,783,151],{"class":150},[140,785,786],{"class":150}," @kleora-io\u002Fnode\n",[16,788,789,790,793,794,797,798,801,802,450,805,450,807,746,810,450,813,450,815,818],{},"Weryfikacja nie zależy od frameworka — ",[20,791,792],{},"authenticate()"," przyjmuje cokolwiek, co\nma własność ",[20,795,796],{},"headers.authorization",", a ",[20,799,800],{},"verifyAccessToken()"," sam token jako\ntekst. Obie funkcje zwracają claimy tokenu: ",[20,803,804],{},"sub",[20,806,262],{},[20,808,809],{},"roles",[20,811,812],{},"permissions",[20,814,231],{},[20,816,817],{},"env"," i resztę.",[122,820,822,824],{"id":821},"kleora-python",[20,823,99],{}," (Python)",[16,826,827],{},"Ta sama weryfikacja w Pythonie, a do tego klient API zarządzania w wersji\nsynchronicznej i asynchronicznej.",[131,829,831],{"className":133,"code":830,"language":135,"meta":136,"style":136},"pip install kleora\n",[20,832,833],{"__ignoreMap":136},[140,834,835,838,840],{"class":142,"line":143},[140,836,837],{"class":146},"pip",[140,839,151],{"class":150},[140,841,842],{"class":150}," kleora\n",[327,844,845,911],{},[330,846,847],{"v-slot:ts":136},[131,848,850],{"className":334,"code":849,"language":336,"meta":136,"style":136},"import { verifyAccessToken } from '@kleora-io\u002Fnode'\n\nconst claims = await verifyAccessToken(token, {\n  issuer: 'https:\u002F\u002Facme.sandbox.kleora.eu',\n  audience: '\u003Cclient_id>',\n})\n",[20,851,852,866,870,888,898,907],{"__ignoreMap":136},[140,853,854,857,860,863],{"class":142,"line":143},[140,855,856],{"class":350},"import",[140,858,859],{"class":360}," { verifyAccessToken } ",[140,861,862],{"class":350},"from",[140,864,865],{"class":150}," '@kleora-io\u002Fnode'\n",[140,867,868],{"class":142,"line":347},[140,869,505],{"emptyLinePlaceholder":504},[140,871,872,874,877,879,882,885],{"class":142,"line":364},[140,873,440],{"class":350},[140,875,876],{"class":446}," claims",[140,878,484],{"class":350},[140,880,881],{"class":350}," await",[140,883,884],{"class":146}," verifyAccessToken",[140,886,887],{"class":360},"(token, {\n",[140,889,890,893,896],{"class":142,"line":376},[140,891,892],{"class":360},"  issuer: ",[140,894,895],{"class":150},"'https:\u002F\u002Facme.sandbox.kleora.eu'",[140,897,746],{"class":360},[140,899,900,903,905],{"class":142,"line":394},[140,901,902],{"class":360},"  audience: ",[140,904,388],{"class":150},[140,906,746],{"class":360},[140,908,909],{"class":142,"line":501},[140,910,397],{"class":360},[330,912,913],{"v-slot:python":136},[131,914,918],{"className":915,"code":916,"language":917,"meta":136,"style":136},"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","python",[20,919,920,932,936,946,951,964,976],{"__ignoreMap":136},[140,921,922,924,927,929],{"class":142,"line":143},[140,923,862],{"class":350},[140,925,926],{"class":360}," kleora ",[140,928,856],{"class":350},[140,930,931],{"class":360}," verify_access_token\n",[140,933,934],{"class":142,"line":347},[140,935,505],{"emptyLinePlaceholder":504},[140,937,938,941,943],{"class":142,"line":364},[140,939,940],{"class":360},"claims ",[140,942,429],{"class":350},[140,944,945],{"class":360}," verify_access_token(\n",[140,947,948],{"class":142,"line":376},[140,949,950],{"class":360},"    token,\n",[140,952,953,957,959,962],{"class":142,"line":394},[140,954,956],{"class":955},"sqxcx","    issuer",[140,958,429],{"class":350},[140,960,961],{"class":150},"\"https:\u002F\u002Facme.sandbox.kleora.eu\"",[140,963,746],{"class":360},[140,965,966,969,971,974],{"class":142,"line":501},[140,967,968],{"class":955},"    audience",[140,970,429],{"class":350},[140,972,973],{"class":150},"\"\u003Cclient_id>\"",[140,975,746],{"class":360},[140,977,978],{"class":142,"line":508},[140,979,980],{"class":360},")\n",[16,982,983],{},"Obie pobierają zestaw kluczy Twojego środowiska raz, trzymają go tak długo, jak\nmówi odpowiedź, i odmawiają weryfikacji, gdy stanie się nieosiągalny. Żadna z\nnich nie czyta zmiennych środowiskowych: issuer, audience i ewentualny klucz API\npodajesz samodzielnie.",[122,985,986],{"id":112},[20,987,112],{},[16,989,990,991,994,995,997,998,118],{},"Klasa uwierzytelniania dla django-ninja, middleware, dekorator uprawnień i\nsłownik ustawień ",[20,992,993],{},"KLEORA",", zbudowane na ",[20,996,99],{},", którą paczka instaluje za\nCiebie. Sama nie weryfikuje żadnego tokenu: pamięć podręczna zestawu kluczy i\nbłędy tokenów pochodzą z ",[20,999,99],{},[131,1001,1003],{"className":133,"code":1002,"language":135,"meta":136,"style":136},"pip install django-kleora\n",[20,1004,1005],{"__ignoreMap":136},[140,1006,1007,1009,1011],{"class":142,"line":143},[140,1008,837],{"class":146},[140,1010,151],{"class":150},[140,1012,1013],{"class":150}," django-kleora\n",[131,1015,1017],{"className":915,"code":1016,"language":917,"meta":136,"style":136},"# settings.py\nINSTALLED_APPS = [..., \"django_kleora\"]\nMIDDLEWARE = [..., \"django_kleora.KleoraAuthMiddleware\"]\n\nKLEORA = {\n    \"ISSUER\": \"https:\u002F\u002Facme.sandbox.kleora.eu\",\n    \"AUDIENCE\": \"\u003Cclient_id>\",\n}\n",[20,1018,1019,1024,1045,1063,1067,1076,1088,1099],{"__ignoreMap":136},[140,1020,1021],{"class":142,"line":143},[140,1022,1023],{"class":343},"# settings.py\n",[140,1025,1026,1029,1031,1034,1037,1039,1042],{"class":142,"line":347},[140,1027,1028],{"class":446},"INSTALLED_APPS",[140,1030,484],{"class":350},[140,1032,1033],{"class":360}," [",[140,1035,1036],{"class":446},"...",[140,1038,450],{"class":360},[140,1040,1041],{"class":150},"\"django_kleora\"",[140,1043,1044],{"class":360},"]\n",[140,1046,1047,1050,1052,1054,1056,1058,1061],{"class":142,"line":364},[140,1048,1049],{"class":446},"MIDDLEWARE",[140,1051,484],{"class":350},[140,1053,1033],{"class":360},[140,1055,1036],{"class":446},[140,1057,450],{"class":360},[140,1059,1060],{"class":150},"\"django_kleora.KleoraAuthMiddleware\"",[140,1062,1044],{"class":360},[140,1064,1065],{"class":142,"line":376},[140,1066,505],{"emptyLinePlaceholder":504},[140,1068,1069,1071,1073],{"class":142,"line":394},[140,1070,993],{"class":446},[140,1072,484],{"class":350},[140,1074,1075],{"class":360}," {\n",[140,1077,1078,1081,1084,1086],{"class":142,"line":501},[140,1079,1080],{"class":150},"    \"ISSUER\"",[140,1082,1083],{"class":360},": ",[140,1085,961],{"class":150},[140,1087,746],{"class":360},[140,1089,1090,1093,1095,1097],{"class":142,"line":508},[140,1091,1092],{"class":150},"    \"AUDIENCE\"",[140,1094,1083],{"class":360},[140,1096,973],{"class":150},[140,1098,746],{"class":360},[140,1100,1101],{"class":142,"line":517},[140,1102,1103],{"class":360},"}\n",[131,1105,1107],{"className":915,"code":1106,"language":917,"meta":136,"style":136},"from django_kleora import KleoraAuthentication, requires_permission\nfrom ninja import NinjaAPI\n\napi = NinjaAPI(auth=KleoraAuthentication())\n\n\n@api.get(\"\u002Finvoices\")\n@requires_permission(\"invoices:read\")\ndef invoices(request):\n    return {\"tenant\": request.kleora.tenant}\n",[20,1108,1109,1121,1133,1137,1155,1159,1163,1176,1188,1199],{"__ignoreMap":136},[140,1110,1111,1113,1116,1118],{"class":142,"line":143},[140,1112,862],{"class":350},[140,1114,1115],{"class":360}," django_kleora ",[140,1117,856],{"class":350},[140,1119,1120],{"class":360}," KleoraAuthentication, requires_permission\n",[140,1122,1123,1125,1128,1130],{"class":142,"line":347},[140,1124,862],{"class":350},[140,1126,1127],{"class":360}," ninja ",[140,1129,856],{"class":350},[140,1131,1132],{"class":360}," NinjaAPI\n",[140,1134,1135],{"class":142,"line":364},[140,1136,505],{"emptyLinePlaceholder":504},[140,1138,1139,1142,1144,1147,1150,1152],{"class":142,"line":376},[140,1140,1141],{"class":360},"api ",[140,1143,429],{"class":350},[140,1145,1146],{"class":360}," NinjaAPI(",[140,1148,1149],{"class":955},"auth",[140,1151,429],{"class":350},[140,1153,1154],{"class":360},"KleoraAuthentication())\n",[140,1156,1157],{"class":142,"line":394},[140,1158,505],{"emptyLinePlaceholder":504},[140,1160,1161],{"class":142,"line":501},[140,1162,505],{"emptyLinePlaceholder":504},[140,1164,1165,1168,1171,1174],{"class":142,"line":508},[140,1166,1167],{"class":146},"@api.get",[140,1169,1170],{"class":360},"(",[140,1172,1173],{"class":150},"\"\u002Finvoices\"",[140,1175,980],{"class":360},[140,1177,1178,1181,1183,1186],{"class":142,"line":517},[140,1179,1180],{"class":146},"@requires_permission",[140,1182,1170],{"class":360},[140,1184,1185],{"class":150},"\"invoices:read\"",[140,1187,980],{"class":360},[140,1189,1190,1193,1196],{"class":142,"line":540},[140,1191,1192],{"class":350},"def",[140,1194,1195],{"class":146}," invoices",[140,1197,1198],{"class":360},"(request):\n",[140,1200,1201,1204,1207,1210],{"class":142,"line":571},[140,1202,1203],{"class":350},"    return",[140,1205,1206],{"class":360}," {",[140,1208,1209],{"class":150},"\"tenant\"",[140,1211,1212],{"class":360},": request.kleora.tenant}\n",[16,1214,1215,1218,1219,1222,1223,1226,1227,1230,1231,1234],{},[20,1216,1217],{},"requires_permission"," odpowiada ",[20,1220,1221],{},"401",", gdy nie ma zweryfikowanego tokenu, ",[20,1224,1225],{},"403",",\ngdy token nie ma uprawnienia, i ",[20,1228,1229],{},"503",", gdy nie udało się odczytać zestawu kluczy\nissuera — to te same trzy odpowiedzi i te same dokumenty problemu, co w\nmiddleware dla Node. Middleware służy widokom, których django-ninja nie widzi:\nustawia ",[20,1232,1233],{},"request.kleora"," i sam nigdy nie odrzuca żądania.",[122,1236,1238],{"id":1237},"zupełnie-bez-sdk","Zupełnie bez SDK",[16,1240,1241,1242,1245],{},"Hostowane strony i endpointy OAuth są standardowe. Wszystko, czego potrzebuje\ndowolny klient OpenID Connect, stoi pod adresem\n",[20,1243,1244],{},"{issuer}\u002F.well-known\u002Fopenid-configuration",", a zestaw kluczy, który tam jest\nwskazany, weryfikuje token. Jedynym obsługiwanym przepływem przeglądarkowym jest\nkod autoryzacyjny z PKCE; przepływu implicit ani hasłowego nie udostępniamy.",[1247,1248,1249],"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}html pre.shiki code .sqxcx, html code.shiki .sqxcx{--shiki-default:#E36209}",{"title":136,"searchDepth":364,"depth":364,"links":1251},[1252,1253,1254,1255,1257,1258],{"id":124,"depth":347,"text":60},{"id":302,"depth":347,"text":73},{"id":767,"depth":347,"text":86},{"id":821,"depth":347,"text":1256},"kleora (Python)",{"id":112,"depth":347,"text":112},{"id":1237,"depth":347,"text":1238},"Pięć paczek, które publikujemy, do czego służy każda z nich i jakiej konfiguracji wymaga.","md","getting-started\u002Finstallation",{},20,"\u002Fpl\u002Fdocs\u002Fpierwsze-kroki\u002Finstalacja",false,{"title":5,"description":1259},"pl\u002Fdocs\u002Fpierwsze-kroki\u002Finstalacja","FUM1xLA0g8eLOQvYL6YUQBlQIhGRycrHeK7q_YEy8ss",[1270,1276,1281,1282,1286,1292,1298,1303,1308,1313,1318,1323,1328,1333],{"path":1271,"title":1272,"description":1273,"order":1274,"key":1275},"\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":1277,"title":1278,"description":1279,"order":571,"key":1280},"\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":1264,"title":5,"description":1259,"order":1263,"key":1261},{"path":298,"title":1283,"description":1284,"order":571,"key":1285},"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":1287,"title":1288,"description":1289,"order":1290,"key":1291},"\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.",30,"guides\u002Farchitecture",{"path":1293,"title":1294,"description":1295,"order":1296,"key":1297},"\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":1299,"title":1300,"description":1301,"order":571,"key":1302},"\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":1304,"title":1305,"description":1306,"order":1263,"key":1307},"\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":1309,"title":1310,"description":1311,"order":1290,"key":1312},"\u002Fpl\u002Fdocs\u002Fprzewodniki\u002Fframeworki\u002Fnuxt","Nuxt","Moduł dla Nuxt — dwie linijki konfiguracji, strona powrotu, której nie piszesz, i middleware chroniący stronę z jej własnych metadanych.","guides\u002Fquickstarts\u002Fnuxt",{"path":1314,"title":1315,"description":1316,"order":571,"key":1317},"\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":1319,"title":1320,"description":1321,"order":1263,"key":1322},"\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":1324,"title":1325,"description":1326,"order":1263,"key":1327},"\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":1329,"title":1330,"description":1331,"order":1290,"key":1332},"\u002Fpl\u002Fdocs\u002Freferencje","Referencje","Materiały referencyjne dla API HTTP i paczek SDK.","reference\u002Findex",{"path":1334,"title":1335,"description":1336,"order":571,"key":1337},"\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",1790698197911]