[{"data":1,"prerenderedAt":1268},["ShallowReactive",2],{"blog-uk-supabase-users-logged-out":3,"blog-index-uk":739},{"id":4,"title":5,"body":6,"category":698,"cover":699,"coverAlt":700,"description":701,"draft":702,"extension":703,"faq":704,"image":720,"keywords":721,"meta":728,"navigation":729,"ogTitle":5,"path":730,"published":731,"seo":732,"stem":733,"tldr":734,"updated":731,"__hash__":738},"blog_uk\u002Fblog\u002Fsupabase-users-logged-out.md","Supabase \"Invalid Refresh Token: Refresh Token Not Found\": 3 причини",{"type":7,"value":8,"toc":683},"minimark",[9,13,24,27,35,40,43,62,84,110,114,117,126,217,224,228,231,237,259,265,269,290,293,296,302,305,310,314,326,338,356,361,367,371,374,396,411,414,418,424,427,431,450,453,511,518,524,527,531,534,560,569,575,579,582,591,609,618,638,642,677],[10,11,12],"p",{},"Ваші користувачі пишуть, що їх викинуло із системи. Один був посеред заповнення\nформи, а інша певна, що нічого не натискала. Коли ви пробуєте застосунок самі,\nвін працює. Потім ви відкриваєте логи й бачите той самий рядок, знову і знову:",[14,15,20],"pre",{"className":16,"code":18,"language":19},[17],"language-text","AuthApiError: Invalid Refresh Token: Refresh Token Not Found\n","text",[21,22,18],"code",{"__ignoreMap":23},"",[10,25,26],{},"Supabase \"Invalid Refresh Token: Refresh Token Not Found\" означає, що Supabase\nAuth, частина Supabase, яка відповідає за вхід, не має запису про токен, який\nваш застосунок надіслав, щоб підтримати сесію. Поновлювати більше нічого, тож\nзастосунок виводить користувача із системи.",[10,28,29,30,34],{},"Ось що легко зрозуміти навпаки: ",[31,32,33],"strong",{},"ця помилка є останнім кроком, а причина була\nраніше."," Коли Supabase уже не знаходить токен, сесія, якій він належав, уже\nзавершилася. Її завершив вихід із системи, токен, надісланий двічі, або ліміт,\nякий хтось встановив. Довший термін дії access token чи вимкнена перевірка, яка\nзавершує сесію, роблять цей рядок у логах рідшим і залишають причину там, де\nвона була.",[36,37,39],"h2",{"id":38},"що-означає-invalid-refresh-token-refresh-token-not-found","Що означає \"Invalid Refresh Token: Refresh Token Not Found\"?",[10,41,42],{},"Це означає, що Supabase Auth отримав refresh token, про який не має запису, і\nтому відмовився поновлювати сесію.",[10,44,45,46,49,50,53,54,61],{},"Кожен користувач у системі має два токени. ",[31,47,48],{},"Access token"," працює як браслет:\nвін якийсь час підтверджує, хто це, годину, якщо ви не змінювали налаштування, і\nзастосунок показує його з кожним запитом. ",[31,51,52],{},"Refresh token"," це квиток. Перш ніж\nбраслет сплине, застосунок несе квиток до стійки, якою є Supabase Auth, і\nобмінює його на новий браслет і новий квиток.\n",[55,56,60],"a",{"href":57,"rel":58},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth\u002Fsessions",[59],"nofollow","Посібник Supabase про сесії","\nкаже, що refresh tokens \"never expire but can only be used once\".",[10,63,64,67,68,71,72,77,78,83],{},[21,65,66],{},"Refresh Token Not Found"," означає, що стійка шукає квиток і нічого не знаходить.\nСервер відповідає HTTP 400 і кодом ",[21,69,70],{},"refresh_token_not_found",", який\n",[55,73,76],{"href":74,"rel":75},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth\u002Fdebugging\u002Ferror-codes",[59],"список кодів помилок Auth","\nу Supabase описує як \"Session containing the refresh token not found.\" Якщо\nбраслет теж сплив,\n",[55,79,82],{"href":80,"rel":81},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fsupabase-js\u002Fblob\u002Fmaster\u002Fpackages\u002Fcore\u002Fauth-js\u002Fsrc\u002FGoTrueClient.ts",[59],"JavaScript-клієнт Supabase","\nприбирає сесію з браузера й повідомляє застосунку, що користувач вийшов. Саме\nтоді ваш користувач бачить сторінку входу.",[10,85,86,87,91,92,95,96,100,101,104,105,109],{},"Жоден із двох токенів не є API-ключем вашого проєкту, ключі це окреме питання:\n",[55,88,90],{"href":89},"\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend","які з них мають бути у вашому застосунку",".\nЯкщо ваше повідомлення натомість каже ",[21,93,94],{},"Invalid JWT",", відхилили браслет, а не\nквиток, і\n",[55,97,99],{"href":98},"\u002Fblog\u002Fsupabase-invalid-jwt","для цієї помилки є окрема сторінка",".\nЯкщо після цього людина не може знову увійти, а форма входу каже\n",[21,102,103],{},"Invalid login credentials",",\n",[55,106,108],{"href":107},"\u002Fblog\u002Fsupabase-invalid-login","за цим повідомленням стоять три різні людини",".",[36,111,113],{"id":112},"чому-моїх-користувачів-supabase-викидає-із-системи","Чому моїх користувачів Supabase викидає із системи?",[10,115,116],{},"Бо сесія, що стоїть за їхнім квитком, завершилася, а браслет, який вони ще\nносять, тримав їх у системі, доки не сплив. Ця затримка, до години за\nстандартного налаштування, і робить виходи схожими на випадкові: користувача\nвикидає через якийсь час після того, як сесія завершилася.",[10,118,119,120,125],{},"Supabase Auth має чотири способи сказати, що квиток недійсний, і кожен вказує на\nіншу причину. Ось точні повідомлення з\n",[55,121,124],{"href":122,"rel":123},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fauth\u002Fblob\u002Fmaster\u002Finternal\u002Ftokens\u002Fservice.go",[59],"коду самого сервера Supabase Auth",":",[127,128,129,145],"table",{},[130,131,132],"thead",{},[133,134,135,139,142],"tr",{},[136,137,138],"th",{},"Повідомлення у вашому лозі",[136,140,141],{},"Код",[136,143,144],{},"Що сталося",[146,147,148,163,178,202],"tbody",{},[133,149,150,156,160],{},[151,152,153],"td",{},[21,154,155],{},"Invalid Refresh Token: Refresh Token Not Found",[151,157,158],{},[21,159,70],{},[151,161,162],{},"Стійка не має запису про цей квиток. Його сесію завершив вихід, або його обміняли так давно, що запис уже зник.",[133,164,165,170,175],{},[151,166,167],{},[21,168,169],{},"Invalid Refresh Token: Already Used",[151,171,172],{},[21,173,174],{},"refresh_token_already_used",[151,176,177],{},"Квиток обміняли понад десять секунд тому, і він повернувся. Тоді Supabase завершує всю сесію.",[133,179,180,194,199],{},[151,181,182,185,186,189,190,193],{},[21,183,184],{},"Invalid Refresh Token: Session Expired",", іноді з ",[21,187,188],{},"(Inactivity)"," або ",[21,191,192],{},"(Revoked by Newer Login)"," у кінці",[151,195,196],{},[21,197,198],{},"session_expired",[151,200,201],{},"Її завершив ліміт сесій у налаштуваннях Auth.",[133,203,204,209,214],{},[151,205,206],{},[21,207,208],{},"Invalid Refresh Token: No Valid Session Found",[151,210,211],{},[21,212,213],{},"session_not_found",[151,215,216],{},"Сесії, якій належав квиток, більше немає.",[10,218,219,220,109],{},"За цими повідомленнями стоять три причини, згідно з документацією самого\nSupabase і звітами в його issue trackers, і кожна має своє виправлення. Якщо\nніхто взагалі не може увійти або весь застосунок порожній, це інша проблема, і\nпочинати варто з\n",[55,221,223],{"href":222},"\u002Fblog\u002Fis-supabase-down-or-your-app","чи впав Supabase, чи це ваш застосунок",[36,225,227],{"id":226},"refresh-token-працює-один-раз","Refresh token працює один раз",[10,229,230],{},"Щоразу, коли застосунок поновлює сесію, він віддає квиток, і стійка рве старий.\nSupabase називає це ротацією refresh tokens. Старий квиток працює ще десять\nсекунд, що посібник про сесії називає reuse interval, щоб сервер і браузер, які\nпоновлюють сесію майже одночасно, не вибили одне одного. Клієнт, який обміняв\nквиток і втратив відповідь через погане з'єднання, теж захищений: він отримує\nпоточний квиток назад.",[10,232,233,234,109],{},"Поза цими двома випадками старий квиток, що повертається, вважається тривожним\nсигналом, бо токен, який з'являється двічі, виглядає як украдений. Посібник\nкаже, що тоді вся сесія \"is regarded as terminated and all refresh tokens\nbelonging to it are marked as revoked\". Цього разу відповідь буде ",[21,235,236],{},"Already Used",[10,238,239,240,242,243,246,247,252,253,255,256,258],{},"Ще один крок перетворює ",[21,241,236],{}," на ",[21,244,245],{},"Not Found",". Сервер Supabase Auth\n",[55,248,251],{"href":249,"rel":250},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fauth\u002Fblob\u002Fmaster\u002Finternal\u002Fmodels\u002Fcleanup.go",[59],"стирає записи розірваних квитків","\nчерез 24 години після їх відкликання. Тож застарілий квиток, який сьогодні\nотримує ",[21,254,236],{},", завтра отримує ",[21,257,66],{},", бо в стійки\nвже немає запису, з яким його порівняти.",[260,261],"diagram",{"alt":262,"caption":263,"src":264},"Часова шкала одного квитка. Спочатку його обмінюють на стійці на новий браслет і новий квиток, а старий розривають. Показаний знову протягом 10 секунд, він ще проходить. Пізніше того ж дня його відхиляють як уже використаний. Через 24 години в книзі стійки на місці його запису порожній рядок.","Один квиток у чотири моменти. Протягом десяти секунд він ще працює. Потім його відхиляють як уже використаний, а коли його запис стирають через добу, стійка вже зовсім його не знаходить.","\u002Fblog\u002Fsupabase-users-logged-out\u002Fone-ticket-four-moments-1600x700.png",[36,266,268],{"id":267},"причина-1-хтось-вийшов-на-цьому-пристрої-чи-на-іншому","Причина 1: хтось вийшов, на цьому пристрої чи на іншому",[10,270,271,272,275,276,279,280,285,286,289],{},"Вихід видаляє сесію на боці стійки, і кожен квиток із неї стає таким, якого\nстійка не знаходить. У JavaScript-клієнті Supabase ",[21,273,274],{},"signOut()"," без нічого в\nдужках завершує ",[31,277,278],{},"всі"," сесії цього користувача на всіх пристроях.\n",[55,281,284],{"href":282,"rel":283},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth\u002Fsignout",[59],"Посібник Supabase про вихід","\nкаже це прямо: за цього налаштування інші сесії падають з\n",[21,287,288],{},"AuthApiError: Invalid Refresh Token: Refresh Token Not Found"," наступного разу,\nколи пробують поновитися, \"even though no one signed out on that device.\"",[10,291,292],{},"Тож користувач, який вийшов на телефоні, вилітає й на ноутбуці, до години\nпізніше, коли браслет ноутбука спливає, а його квиток повертається як невідомий.\nЗ його боку здається, що ваш застосунок викинув його без причини.",[10,294,295],{},"Якщо кожен пристрій має лишатися в системі сам по собі, виклик виходу повинен\nзавершувати тільки ту сесію, з якої його зроблено:",[14,297,300],{"className":298,"code":299,"language":19},[17],"await supabase.auth.signOut({ scope: 'local' })\n",[21,301,299],{"__ignoreMap":23},[10,303,304],{},"Попросіть свій білдер використовувати цю форму всюди, де застосунок виводить\nлюдей. Інший звичайний спосіб завершити сесію це зміна пароля, яку посібник\nSupabase про сесії називає серед того, що сесію завершує.",[260,306],{"alt":307,"caption":308,"src":309},"Дві панелі. На лівій телефон виходить через signOut(), і квитки телефона, ноутбука й планшета розірвані всі. На правій телефон виходить зі scope local, і розірваний лише квиток телефона, а ноутбук і планшет свої зберігають.","Без scope один вихід завершує сесію на всіх пристроях. Зі scope local він завершує лише ту, що на пристрої у вас у руці.","\u002Fblog\u002Fsupabase-users-logged-out\u002Fone-sign-out-every-device-1600x720.png",[36,311,313],{"id":312},"причина-2-новий-квиток-так-і-не-дійшов-до-браузера","Причина 2: новий квиток так і не дійшов до браузера",[10,315,316,317,320,321,323,324,109],{},"Якщо ваш застосунок рендерить сторінки на сервері, як це робить застосунок на\nNext.js, цей сервер теж поновлює сесії. Він читає квиток із cookie, обмінює його\nна стійці й мусить повернути новий квиток браузеру в заголовку ",[21,318,319],{},"Set-Cookie"," своєї\nвідповіді. Коли цей cookie не доходить, браузер лишається зі старим квитком, і\nнаступний запит показує квиток, який сервер уже обміняв. Протягом десяти секунд\nце проходить. Після цього буде ",[21,322,236],{}," і сесія завершиться, а через добу\nтой самий квиток уже ",[21,325,245],{},[10,327,328,333,334,337],{},[55,329,332],{"href":330,"rel":331},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fauth\u002Fserver-side\u002Fcreating-a-client",[59],"Посібник Supabase про створення серверного клієнта","\nназиває помилку, яка до цього призводить у застосунку на Next.js. Код, що\nпоновлює сесію, який у Next.js 16 називається Proxy, а в старіших версіях\nmiddleware, мусить повертати ту відповідь, у яку записано нові cookies: \"An\nearlier response doesn't carry the refreshed cookies, so the user is signed out\non the next request.\" Той самий посібник попереджає, що в Next.js 15 і старіших\nфайл із назвою ",[21,335,336],{},"proxy.ts"," взагалі не запускається, \"so sessions never refresh\nand users get signed out\". Асистент, який працює з найновішою документацією,\nможе записати саме такий файл у старіший застосунок.",[10,339,340,341,349,350,355],{},"Посібник Supabase також пояснює, чому цей випадок важко знайти: \"it looks like\nusers being signed out at random rather than an error in your code.\" Звіти\nзвучать так само. Розробник написав в\n",[55,342,345,346],{"href":343,"rel":344},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fssr\u002Fissues\u002F68",[59],"issue tracker ",[21,347,348],{},"@supabase\u002Fssr","\n\"I'm inadvertently logged out of my web application every day\", а інженер\nSupabase, який відповів, указав на те, як middleware передавав свою відповідь.\n",[55,351,354],{"href":352,"rel":353},"https:\u002F\u002Fgithub.com\u002Fsupabase\u002Fsupabase-swift\u002Fissues\u002F486",[59],"Звіт про iOS-застосунок","\nописує вихід \"2-3 days after logging in\", і його закрили після того, як\nоновлення Swift-бібліотеки Supabase зменшили кількість звітів.",[260,357],{"alt":358,"caption":359,"src":360},"Браузер надсилає свій квиток серверу. Сервер обмінює його на стійці й отримує новий. Відповідь, яка мала б донести новий квиток до браузера, обривається дорогою, тож браузер знову надсилає старий квиток, і стійка відхиляє його як уже використаний.","Сервер поновив сесію, а новий квиток так і не повернувся. Браузер досі тримає той, який уже обміняли.","\u002Fblog\u002Fsupabase-users-logged-out\u002Fnew-ticket-lost-1600x640.png",[10,362,363,364,366],{},"Щоб перевірити, відкрийте інструменти розробника в браузері на сторінці, яка\nпоновила сесію, і подивіться на відповідь у вкладці Network. Вона має містити\n",[21,365,319],{}," з новим токеном, а наступний запит має надіслати цей токен назад.",[36,368,370],{"id":369},"причина-3-ліміт-сесій-у-налаштуваннях-auth","Причина 3: ліміт сесій у налаштуваннях Auth",[10,372,373],{},"Починаючи з плану Pro, Supabase може завершувати сесії навмисно, зі сторінки\nSessions у налаштуваннях Auth вашого проєкту. Є три ліміти, і посібник про сесії\nописує кожен:",[375,376,377,384,390],"ul",{},[378,379,380,383],"li",{},[31,381,382],{},"Сесії з обмеженим часом"," завершуються через фіксований час, хоч би який\nактивний був користувач.",[378,385,386,389],{},[31,387,388],{},"Тайм-аут неактивності"," завершує сесію, яку якийсь час не поновлювали.",[378,391,392,395],{},[31,393,394],{},"Одна сесія на користувача"," залишає лише найновіший вхід, тож вхід із\nтелефона завершує сесію на ноутбуці.",[10,397,398,399,402,403,405,406,408,409,109],{},"Вони кажуть про це у власному повідомленні, ",[21,400,401],{},"Session Expired",", з ",[21,404,188],{},"\nабо ",[21,407,192],{}," у кінці для другого й третього. Посібник додає,\nщо завершені сесії видаляються через 24 години, тож квиток з такої сесії, який\nповертається після цього, отримує натомість ",[21,410,245],{},[10,412,413],{},"Якщо ви ввімкнули один із них, виходи означають, що налаштування робить свою\nсправу. Якщо ви цього не хотіли, або це ввімкнув за вас шаблон чи асистент,\nсторінка покаже, який ліміт увімкнено.",[36,415,417],{"id":416},"нешкідливий-випадок","Нешкідливий випадок",[10,419,420,421,423],{},"Квиток із сесії, яка вже завершилася, що повертається зі старої вкладки або з\nбраузера, якого тижнями ніхто не відкривав, теж отримує\n",[21,422,66],{},". Людину за ним уже вивели із системи. Її браузер\nзапитав один раз, Supabase сказав ні, і вона бачить вашу сторінку входу, тобто\nте, що побачила б і так.",[10,425,426],{},"У лозі це виглядає так: один рядок для одного користувача, часто невдовзі після\nтого, як цей користувач десь вийшов, і потім від нього більше нічого. Такі рядки\nозначають, що помилка робить свою справу. Розбиратися варто з тими самими\nлюдьми знову і знову або з купою різних людей того самого дня.",[36,428,430],{"id":429},"як-читати-логи-auth-для-цього","Як читати логи Auth для цього",[10,432,433,434,437,438,441,442,445,446,449],{},"Відкрийте ",[31,435,436],{},"Logs"," у дашборді Supabase, виберіть тип логу ",[31,439,440],{},"Auth"," і пошукайте\n",[21,443,444],{},"refresh token"," у повідомленнях подій. Виберіть рядок, щоб побачити подробиці,\nсеред них ID користувача, а фільтр ",[31,447,448],{},"User"," потім звузить список до цієї однієї\nлюдини. Наскільки далеко сягають логи, залежить від вашого плану, тож читайте їх,\nпоки скарги свіжі.",[10,451,452],{},"Потім читайте, що повторюється:",[127,454,455,465],{},[130,456,457],{},[133,458,459,462],{},[136,460,461],{},"Що ви бачите в лозі Auth",[136,463,464],{},"На що це вказує",[146,466,467,478,488,501],{},[133,468,469,475],{},[151,470,471,472,474],{},"Один ",[21,473,66],{}," для користувача, і нічого після",[151,476,477],{},"Стара вкладка або браузер, що повернувся. Нешкідливо.",[133,479,480,485],{},[151,481,482,484],{},[21,483,66],{}," для користувача невдовзі після його виходу деінде",[151,486,487],{},"Причина 1, вихід, що завершив усі пристрої",[133,489,490,498],{},[151,491,492,494,495,497],{},[21,493,236],{},", а через добу ",[21,496,66],{},", для тих самих користувачів, знову і знову",[151,499,500],{},"Причина 2, нові квитки не доходять до браузера",[133,502,503,508],{},[151,504,505,507],{},[21,506,401],{}," із причиною в дужках",[151,509,510],{},"Причина 3, ліміт сесій",[10,512,513,514,517],{},"Можна також запитати базу даних, як часто люди входять. Кожен вхід додає рядок\nдо ",[21,515,516],{},"auth.sessions",", а вихід його видаляє. Вставте це в SQL Editor:",[14,519,522],{"className":520,"code":521,"language":19},[17],"select user_id, count(*) as sessions, max(created_at) as latest\nfrom auth.sessions\nwhere created_at > now() - interval '14 days'\ngroup by user_id\norder by sessions desc\nlimit 20;\n",[21,523,521],{"__ignoreMap":23},[10,525,526],{},"Користувач, у якого сесій набагато більше, ніж пристроїв, входив знову і знову,\nніколи не виходячи, а саме так поводиться той, кого ваш застосунок постійно\nвикидає.",[36,528,530],{"id":529},"чого-не-змінювати-поки-виправляєте","Чого не змінювати, поки виправляєте",[10,532,533],{},"Ваші правила Row Level Security, виявлення повторного використання і термін дії\naccess token. Усі три схожі на виправлення й залишають причину на місці, а\nпослаблення першого може відкрити ваші дані стороннім.",[10,535,536,539,540,543,544,549,551,552,555,556,109],{},[31,537,538],{},"Не чіпайте свої правила Row Level Security."," Row Level Security це набір\nправил, який вирішує, які рядки отримує кожен відвідувач. Поки користувачів\nвикидає, кожен екран, чиє правило читає ",[21,541,542],{},"auth.uid()",", для них порожній, бо\nзгідно з\n",[55,545,548],{"href":546,"rel":547},"https:\u002F\u002Fsupabase.com\u002Fdocs\u002Fguides\u002Fdatabase\u002Fpostgres\u002Frow-level-security",[59],"документацією Supabase",[21,550,542],{}," повертає ",[21,553,554],{},"null",", коли сесія сплила. Спокуслива ідея послабити це\nправило, доки екран знову не заповниться, але тоді він заповнюється й для\nсторонніх. Якщо хтось уже це зробив, наше безкоштовне сканування питає кожну\nтаблицю, яку називає ваш застосунок, скільки рядків отримав би відвідувач без\nвходу, читає число, не завантажуючи жодного рядка, і займає приблизно 20 секунд\nбез акаунта: ",[55,557,559],{"href":558},"\u002Fsecurity-scanner","перевірте свій застосунок",[10,561,562,565,566,568],{},[31,563,564],{},"Залиште виявлення повторного використання ввімкненим."," Supabase дозволяє його\nвимкнути, у розширених налаштуваннях на сторінці Sessions, і називає це\n\"generally not recommended\". Коли воно вимкнене, причина 2 більше не дає\n",[21,567,236],{},", а новий квиток усе одно не доходить до браузера.",[10,570,571,574],{},[31,572,573],{},"Тримайте access token на одній годині."," Довший браслет відкладає вихід і\nзалишає його причину на місці. Посібник Supabase каже, що значення понад годину\n\"generally discouraged for security reasons\".",[36,576,578],{"id":577},"щоб-входи-працювали-й-після-виправлення","Щоб входи працювали й після виправлення",[10,580,581],{},"Дві речі ще можуть піти не так, коли виходи припиняться: пізніша зміна поверне\nїх, а правило, послаблене дорогою, лишить таблицю відкритою для сторонніх.",[10,583,584],{},[31,585,586,590],{},[55,587,589],{"href":588},"\u002Fwebsite-monitoring","Reeve Monitor"," і далі перевіряє ззовні:",[375,592,593,596,599,606],{},[378,594,595],{},"чи працює ваш застосунок, щохвилини, щоб хвилю повідомлень \"мене викинуло\" не сплутали зі збоєм",[378,597,598],{},"повна перевірка безпеки щогодини, до трьох застосунків",[378,600,601,602,605],{},"повідомлення, коли результат ",[31,603,604],{},"змінюється",", щоб правило, послаблене під час виправлення, не чекало, поки ви глянете",[378,607,608],{},"щомісячний звіт простою мовою про те, що він бачив",[10,610,611],{},[31,612,613,617],{},[55,614,616],{"href":615},"\u002Fsupabase-backups","Reeve Care"," тримає копію вашої бази даних Supabase:",[375,619,620,623,626,629,632,635],{},[378,621,622],{},"зашифрована копія за розкладом, у власному сховищі Reeve в ЄС, поза вашим обліковим записом Supabase",[378,624,625],{},"схема auth, де живуть облікові записи ваших користувачів, щоб вони повернулися разом з усім іншим",[378,627,628],{},"кожна копія перевірена, перш ніж зарахуватися, підрахунком рядків у кожній таблиці",[378,630,631],{},"ваші вивантажені файли теж, щойно ви підключите доступ до Storage",[378,633,634],{},"відновлення в один клік, із безпечною копією поточного стану, зробленою заздалегідь",[378,636,637],{},"усе, що робить Monitor",[36,639,641],{"id":640},"що-зробити-зараз","Що зробити зараз",[643,644,645],"key-takeaways",{},[375,646,647,653,659,665,668,671],{},[378,648,649,650,652],{},"Пошукайте ",[21,651,444],{}," у логах Auth і подивіться, яке повідомлення повторюється і в кого.",[378,654,655,656,109],{},"Якщо вихід на одному пристрої завершує інші, змініть його на ",[21,657,658],{},"signOut({ scope: 'local' })",[378,660,661,662,664],{},"Якщо застосунок рендерить сторінки на сервері, переконайтеся, що відповідь, яка поновила сесію, і є тією, що доходить до браузера, і знайдіть її ",[21,663,319],{}," у вкладці Network.",[378,666,667],{},"Перегляньте сторінку Sessions у налаштуваннях Auth: чи немає там обмеження часу, тайм-ауту неактивності або однієї сесії на користувача, які ніхто не збирався вмикати.",[378,669,670],{},"Залиште Row Level Security, виявлення повторного використання і термін дії access token як є, поки виправляєте.",[378,672,673,674,676],{},"Вважайте один ",[21,675,245],{}," на користувача шумом, а тих самих користувачів щодня багом.",[10,678,679,680,682],{},"Почніть із логу Auth, бо повідомлення, яке повторюється, скаже, яка з трьох\nпричин у вас. Потім, коли люди перестануть вилітати,\n",[55,681,559],{"href":558},", щоб переконатися, що дорогою\nнічого не послабили.",{"title":23,"searchDepth":684,"depth":684,"links":685},3,[686,688,689,690,691,692,693,694,695,696,697],{"id":38,"depth":687,"text":39},2,{"id":112,"depth":687,"text":113},{"id":226,"depth":687,"text":227},{"id":267,"depth":687,"text":268},{"id":312,"depth":687,"text":313},{"id":369,"depth":687,"text":370},{"id":416,"depth":687,"text":417},{"id":429,"depth":687,"text":430},{"id":529,"depth":687,"text":530},{"id":577,"depth":687,"text":578},{"id":640,"depth":687,"text":641},"Основи безпеки","\u002Fblog\u002Fsupabase-users-logged-out\u002Fcover-1200x630.png","Квиток, розірваний навпіл: ліва половина світиться, права згасла й падає, а позаду ряд цілих квитків.","Supabase \"Invalid Refresh Token: Refresh Token Not Found\" виводить ваших користувачів із системи. Три причини і як лог Auth їх розрізняє.",false,"md",[705,708,711,714,717],{"q":706,"a":707},"Чому моїх користувачів Supabase викидає із системи без видимої причини?","Бо сесія, що стоїть за їхнім refresh token, завершилася, а access token, який у них ще є, тримає їх у системі до години. Тож вихід настає пізніше, ніж його причина. Звичні причини такі: вихід на іншому пристрої, поновлений токен, що так і не дійшов до браузера, і ліміт сесій у налаштуваннях Auth. Лог Auth показує, яка з них.",{"q":709,"a":710},"Що таке refresh token?","Це довготривала половина сесії Supabase. Access token за замовчуванням годину підтверджує, хто такий користувач, і до того, як він сплине, ваш застосунок обмінює refresh token на нову пару. Кожен refresh token працює один раз, і старий перестає працювати через десять секунд після обміну.",{"q":712,"a":713},"Чи \"Refresh Token Not Found\" ознака атаки?","Сам по собі ні. Він означає, що Supabase Auth відмовив токену, про який не має запису, і це правильна відповідь. Від украденого токена захищає виявлення повторного використання, яке завершує сесію, коли повертається старий токен, і Supabase радить лишати його ввімкненим.",{"q":715,"a":716},"Чому це трапляється лише в продакшені?","Бо більшості причин потрібен час або другий пристрій. Застарілий токен першого дня відхиляють як уже використаний, а як не знайдений, щойно його запис зітруть через добу, і сесія, у якій ви сидите під час розробки, рідко живе так довго. До того ж справжні користувачі входять із кількох пристроїв, і саме там видно вихід, що завершує всі сесії.",{"q":718,"a":719},"Скільки триває сесія Supabase?","За замовчуванням доти, доки користувач не вийде. Access token діє годину, якщо ви цього не змінили, а refresh token ніколи не спливає, проте працює лише один раз. Починаючи з плану Pro, сесії можна обмежити за загальним часом, за неактивністю або однією на користувача, на сторінці Sessions у налаштуваннях Auth.","\u002Fblog\u002Fsupabase-users-logged-out\u002Fcard-800x500.png",[722,723,70,724,725,726,727],"invalid refresh token refresh token not found","supabase invalid refresh token","supabase користувачів викидає з акаунта","supabase refresh token already used","supabase session expired","supabase ssr помилка refresh token",{},true,"\u002Fblog\u002Fsupabase-users-logged-out","2026-10-19",{"title":5,"description":701},"blog\u002Fsupabase-users-logged-out",[735,736,737],"Supabase \"Invalid Refresh Token: Refresh Token Not Found\" означає, що Supabase Auth не має запису про refresh token, який надіслав ваш застосунок. Сесію не можна поновити, і користувача виводить із системи.","Цей запис зникає з трьох причин: вихід із системи (у JavaScript він за замовчуванням завершує всі пристрої), уже використаний токен, що приходить удруге, і ліміт сесій у налаштуваннях Auth.","Частина цього лише нешкідливий рядок зі старої вкладки. Інша частина щодня виводить усіх ваших користувачів. Лог Auth скаже, що саме у вас, і кожна причина має своє виправлення.","gdu4hHumxl8J0_e5zsPJQwGenzXhgSzmHBo0tDHF2Gg",[740,746,752,758,764,770,776,782,788,794,800,807,813,818,824,830,836,842,848,854,860,866,867,873,879,884,890,896,902,908,914,920,926,932,938,944,950,956,962,968,973,979,985,991,997,1003,1008,1014,1020,1026,1032,1038,1044,1050,1056,1062,1068,1074,1080,1086,1092,1098,1104,1110,1116,1122,1128,1134,1140,1146,1152,1158,1164,1170,1176,1182,1188,1194,1200,1206,1212,1218,1224,1230,1235,1241,1247,1253,1258,1264],{"path":741,"title":742,"description":743,"published":744,"category":698,"image":745,"draft":702},"\u002Fblog\u002Fmax-client-connections-reached","Supabase \"max client connections reached\": пояснення","Supabase \"max client connections reached\": у пулера немає місця ще для одного клієнта. Ліміт визначає порт у вашому рядку підключення.","2026-11-09","\u002Fblog\u002Fmax-client-connections-reached\u002Fcard-800x500.png",{"path":747,"title":748,"description":749,"published":750,"category":698,"image":751,"draft":702},"\u002Fblog\u002Funsupported-provider-provider-is-not-enabled","Помилка Supabase: \"Unsupported provider: provider is not enabled\"","\"Unsupported provider: provider is not enabled\": вхід через Google вимкнено у вашому проєкті Supabase. Як увімкнути та виправити redirect_uri_mismatch.","2026-11-08","\u002Fblog\u002Funsupported-provider-provider-is-not-enabled\u002Fcard-800x500.png",{"path":753,"title":754,"description":755,"published":756,"category":698,"image":757,"draft":702},"\u002Fblog\u002Fviolates-foreign-key-constraint","Помилка Supabase \"violates foreign key constraint\" під час вставки","Supabase \"insert or update on table violates foreign key constraint\": ваш рядок посилається на рядок, якого немає. Який, чому і як це виправити.","2026-11-07","\u002Fblog\u002Fviolates-foreign-key-constraint\u002Fcard-800x500.png",{"path":759,"title":760,"description":761,"published":762,"category":698,"image":763,"draft":702},"\u002Fblog\u002Fnull-value-violates-not-null-constraint","Помилка Supabase \"null value in column violates not-null constraint\"","Supabase \"null value in column violates not-null constraint\": обовʼязковий стовпець прийшов порожнім. Звідки взявся null і як це виправити.","2026-11-06","\u002Fblog\u002Fnull-value-violates-not-null-constraint\u002Fcard-800x500.png",{"path":765,"title":766,"description":767,"published":768,"category":698,"image":769,"draft":702},"\u002Fblog\u002Fauth-session-missing","Supabase \"Auth session missing!\": куди поділася сесія","\"Auth session missing!\" означає, що supabase-js не знайшла жодної сесії й навіть не спитала Supabase. Куди поділася сесія і як це виправити.","2026-11-05","\u002Fblog\u002Fauth-session-missing\u002Fcard-800x500.png",{"path":771,"title":772,"description":773,"published":774,"category":698,"image":775,"draft":702},"\u002Fblog\u002Finvalid-claim-missing-sub-claim","Supabase \"invalid claim: missing sub claim\": ніхто не ввійшов","\"invalid claim: missing sub claim\": Supabase Auth отримав справжній токен без жодного користувача, ключ проєкту замість сесії.","2026-11-04","\u002Fblog\u002Finvalid-claim-missing-sub-claim\u002Fcard-800x500.png",{"path":777,"title":778,"description":779,"published":780,"category":698,"image":781,"draft":702},"\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function","\"Failed to send a request to the Edge Function\": справжня причина","\"Failed to send a request to the Edge Function\": браузер не отримав відповіді, яку можна прочитати. Його консоль каже, чому, і чи ваша функція запускалася.","2026-11-03","\u002Fblog\u002Ffailed-to-send-a-request-to-the-edge-function\u002Fcard-800x500.png",{"path":783,"title":784,"description":785,"published":786,"category":698,"image":787,"draft":702},"\u002Fblog\u002Fsupabase-auth-redirects-to-localhost","Чому Supabase перенаправляє посилання з листів на localhost:3000","Якщо Supabase перенаправляє на localhost:3000, Site URL так і не змінили або вашої адреси немає в Redirect URLs. Як виправити і якої маски уникати.","2026-11-02","\u002Fblog\u002Fsupabase-auth-redirects-to-localhost\u002Fcard-800x500.png",{"path":789,"title":790,"description":791,"published":792,"category":698,"image":793,"draft":702},"\u002Fblog\u002Femail-link-is-invalid-or-has-expired","Supabase \"Email link is invalid or has expired\" на новому посиланні","На посиланні, надісланому хвилину тому, \"Email link is invalid or has expired\" у Supabase зазвичай означає, що поштовий фільтр використав його першим.","2026-11-01","\u002Fblog\u002Femail-link-is-invalid-or-has-expired\u002Fcard-800x500.png",{"path":795,"title":796,"description":797,"published":798,"category":698,"image":799,"draft":702},"\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout","Supabase \"canceling statement due to statement timeout\": пояснення","Supabase \"canceling statement due to statement timeout\": запит перевищив ліміт своєї ролі, 3 секунди для відвідувача. Спершу перевірте політику RLS.","2026-10-31","\u002Fblog\u002Fcanceling-statement-due-to-statement-timeout\u002Fcard-800x500.png",{"path":801,"title":802,"description":803,"published":804,"category":805,"image":806,"draft":702},"\u002Fblog\u002Fdatabase-error-deleting-user","\"Database error deleting user\" у Supabase і що зникає разом","\"Database error deleting user\" у Supabase: ваша база відмовилася видаляти. Причина в логах, а виправлення вирішує, що ще буде видалено.","2026-10-30","Backups","\u002Fblog\u002Fdatabase-error-deleting-user\u002Fcard-800x500.png",{"path":808,"title":809,"description":810,"published":811,"category":698,"image":812,"draft":702},"\u002Fblog\u002Fstripe-webhook-no-signatures-found","\"No signatures found matching the expected signature\" у Supabase","Вебхук Stripe в Edge Function Supabase пише \"No signatures found matching the expected signature\"? Причин дві. Не вимикайте перевірку.","2026-10-29","\u002Fblog\u002Fstripe-webhook-no-signatures-found\u002Fcard-800x500.png",{"path":107,"title":814,"description":815,"published":816,"category":698,"image":817,"draft":702},"\"Invalid login credentials\" у Supabase: три причини","Supabase відповідає \"Invalid login credentials\" на неправильний пароль, невідому пошту й акаунт Google. Як зрозуміти, що саме.","2026-10-28","\u002Fblog\u002Fsupabase-invalid-login\u002Fcard-800x500.png",{"path":819,"title":820,"description":821,"published":822,"category":698,"image":823,"draft":702},"\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code","\"Edge Function returned a non-2xx status code\": справжня помилка","\"Edge Function returned a non-2xx status code\" означає, що ваша функція Supabase відповіла помилкою. Ось де прочитати справжню.","2026-10-27","\u002Fblog\u002Fedge-function-returned-a-non-2xx-status-code\u002Fcard-800x500.png",{"path":825,"title":826,"description":827,"published":828,"category":698,"image":829,"draft":702},"\u002Fblog\u002Fcertificate-not-trusted","Сертифікат не довірений: три причини, крім закінчення строку","Сертифікат не довірений, хоча дата в порядку? Він називає іншу адресу, підписав сам себе або в його ланцюжку бракує ланки. Як зрозуміти, що саме.","2026-10-26","\u002Fblog\u002Fcertificate-not-trusted\u002Fcard-800x500.png",{"path":831,"title":832,"description":833,"published":834,"category":698,"image":835,"draft":702},"\u002Fblog\u002Finvalid-input-syntax-for-type-uuid","Supabase \"invalid input syntax for type uuid\": що в лапках","Supabase \"invalid input syntax for type uuid\" означає, що застосунок надіслав щось, що не є id. Прочитайте лапки, притримайте запит, залиште колонку.","2026-10-25","\u002Fblog\u002Finvalid-input-syntax-for-type-uuid\u002Fcard-800x500.png",{"path":837,"title":838,"description":839,"published":840,"category":698,"image":841,"draft":702},"\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint","Supabase \"duplicate key value violates unique constraint\": пояснення","Supabase \"duplicate key value violates unique constraint\": значення вже зайняте. Знайдіть стовпець, оберіть виправлення й сховайте значення від очей.","2026-10-24","\u002Fblog\u002Fduplicate-key-value-violates-unique-constraint\u002Fcard-800x500.png",{"path":843,"title":844,"description":845,"published":846,"category":698,"image":847,"draft":702},"\u002Fblog\u002Fsupabase-relation-does-not-exist","Supabase \"relation does not exist\", хоча таблиця на місці","Supabase \"relation does not exist\" або PGRST205: жодна таблиця не має такої назви в цій схемі. Чотири перевірки, і на що зважити, відкриваючи схему.","2026-10-23","\u002Fblog\u002Fsupabase-relation-does-not-exist\u002Fcard-800x500.png",{"path":849,"title":850,"description":851,"published":852,"category":698,"image":853,"draft":702},"\u002Fblog\u002Fsupabase-function-not-found","Supabase PGRST202: \"Could not find the function in the schema cache\"","Supabase \"Could not find the function in the schema cache\" показує назви аргументів, які надіслав ваш застосунок. Порівняйте їх із функцією.","2026-10-22","\u002Fblog\u002Fsupabase-function-not-found\u002Fcard-800x500.png",{"path":855,"title":856,"description":857,"published":858,"category":698,"image":859,"draft":702},"\u002Fblog\u002Fsupabase-schema-cache-column-error","Supabase PGRST204: \"Could not find the column in the schema cache\"","Supabase \"Could not find the column in the schema cache\" зазвичай означає, що назва не збігається. Чотири перевірки і рядок для перезавантаження.","2026-10-21","\u002Fblog\u002Fsupabase-schema-cache-column-error\u002Fcard-800x500.png",{"path":861,"title":862,"description":863,"published":864,"category":698,"image":865,"draft":702},"\u002Fblog\u002Fsupabase-email-rate-limit-exceeded","Supabase \"Email Rate Limit Exceeded\": два ліміти, один код помилки","Supabase \"Email Rate Limit Exceeded\" обмежує кожен лист вашого проєкту: 2 на годину з вбудованим відправником. Що враховується і як підняти ліміт.","2026-10-20","\u002Fblog\u002Fsupabase-email-rate-limit-exceeded\u002Fcard-800x500.png",{"path":730,"title":5,"description":701,"published":731,"category":698,"image":720,"draft":702},{"path":868,"title":869,"description":870,"published":871,"category":698,"image":872,"draft":702},"\u002Fblog\u002Fpermission-denied-for-schema-public","Supabase \"permission denied for schema public\": три причини","Supabase \"permission denied for schema public\" означає, що бракує GRANT на схему. Що його прибрало і який рядок його повертає.","2026-10-18","\u002Fblog\u002Fpermission-denied-for-schema-public\u002Fcard-800x500.png",{"path":874,"title":875,"description":876,"published":877,"category":698,"image":878,"draft":702},"\u002Fblog\u002Fsupabase-bucket-not-found","Supabase \"Bucket not found\": три речі, які це може означати","Supabase \"Bucket not found\" означає одне з трьох: публічне посилання на приватний бакет, неточну назву або не той проєкт.","2026-10-17","\u002Fblog\u002Fsupabase-bucket-not-found\u002Fcard-800x500.png",{"path":98,"title":880,"description":881,"published":882,"category":698,"image":883,"draft":702},"Supabase invalid JWT: який ключ перестав працювати?","Помилка Supabase invalid JWT — це PGRST301: підписаний токен не пройшов перевірку. У новому проєкті йдеться про сесію, а не про ключ API.","2026-10-16","\u002Fblog\u002Fsupabase-invalid-jwt\u002Fcard-800x500.png",{"path":885,"title":886,"description":887,"published":888,"category":698,"image":889,"draft":702},"\u002Fblog\u002Fsupabase-single-row-error","Supabase \"multiple (or no) rows returned\" майже завжди означає нуль","Supabase повертає PGRST116, \"JSON object requested, multiple (or no) rows returned\", коли запит нічого не знайшов. Прихований рядок має вигляд відсутнього.","2026-10-15","\u002Fblog\u002Fsupabase-single-row-error\u002Fcard-800x500.png",{"path":891,"title":892,"description":893,"published":894,"category":698,"image":895,"draft":702},"\u002Fblog\u002Fdatabase-error-saving-new-user","\"Database error saving new user\" у Supabase: де шукати","\"Database error saving new user\" означає, що щось причеплене до вашої реєстрації в Supabase впало. Справжня помилка лежить у ваших логах.","2026-10-14","\u002Fblog\u002Fdatabase-error-saving-new-user\u002Fcard-800x500.png",{"path":897,"title":898,"description":899,"published":900,"category":698,"image":901,"draft":702},"\u002Fblog\u002Fwhat-is-supabase","Що таке Supabase? База даних, яку обрав ваш білдер","Що таке Supabase: база даних, вхід і сховище файлів за вашим застосунком. Supabase тримає сервери, а правила про те, хто читає ваші рядки, ваші.","2026-10-13","\u002Fblog\u002Fwhat-is-supabase\u002Fcard-800x500.png",{"path":903,"title":904,"description":905,"published":906,"category":698,"image":907,"draft":702},"\u002Fblog\u002Faws-access-key-exposed-in-frontend","Відкритий у фронтенді ключ AWS це не те саме, що ключ OpenAI","Ключ доступу AWS, відкритий у вашому фронтенді, читає і пише ваше сховище. Рішення зазвичай presigned URL, а не новий ключ.","2026-10-12","\u002Fblog\u002Faws-access-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":909,"title":910,"description":911,"published":912,"category":698,"image":913,"draft":702},"\u002Fblog\u002Fstorage-upload-violates-row-level-security","\"Row-level security policy for table objects\" при вивантаженні","\"New row violates row-level security policy for table objects\" означає, що вашому вивантаженню бракує правила insert. Публічний бакет його не додає.","2026-10-11","\u002Fblog\u002Fstorage-upload-violates-row-level-security\u002Fcard-800x500.png",{"path":915,"title":916,"description":917,"published":918,"category":698,"image":919,"draft":702},"\u002Fblog\u002Fbase44-security-scan","Сканування безпеки Base44: те, що бачить лише воно","Сканування безпеки Base44 перевіряє сім видів проблем зсередини. Ось половина, яку читає тільки воно, і половина, на яку воно ніколи не дивиться.","2026-10-10","\u002Fblog\u002Fbase44-security-scan\u002Fcard-800x500.png",{"path":921,"title":922,"description":923,"published":924,"category":698,"image":925,"draft":702},"\u002Fblog\u002Fapi-key-leaked-what-to-do","Ваш API-ключ витік. Порядок дій","API-ключ витік, і ви не знаєте, що робити першим. Не кожен ключ у вашому фронтенді є витоком, а порядок важить більше за швидкість.","2026-10-09","\u002Fblog\u002Fapi-key-leaked-what-to-do\u002Fcard-800x500.png",{"path":927,"title":928,"description":929,"published":930,"category":698,"image":931,"draft":702},"\u002Fblog\u002Finfinite-recursion-in-policy-for-relation","\"Infinite recursion detected in policy\" без вимкнення RLS","\"Infinite recursion detected in policy for relation\" означає, що ваша policy запитала таблицю, яку вона захищає. Ось як розірвати коло.","2026-10-08","\u002Fblog\u002Finfinite-recursion-in-policy-for-relation\u002Fcard-800x500.png",{"path":933,"title":934,"description":935,"published":936,"category":698,"image":937,"draft":702},"\u002Fblog\u002Fno-api-key-found-in-request","\"No API key found in request\" у Supabase, і хибне виправлення","\"No API key found in request\" означає, що запит дійшов до Supabase без ключа. Більшість відповідей натомість вказують на правила вашої бази.","2026-10-07","\u002Fblog\u002Fno-api-key-found-in-request\u002Fcard-800x500.png",{"path":939,"title":940,"description":941,"published":942,"category":698,"image":943,"draft":702},"\u002Fblog\u002Fis-base44-safe","Чи безпечний Base44? Дані 5 442 застосунків","Чи безпечний Base44? Ми прогнали дев’ять перевірок на 5 442 робочих застосунках Base44. Майже всі отримали B з причин, яких власник ніколи не обирав.","2026-10-06","\u002Fblog\u002Fis-base44-safe\u002Fcard-800x500.png",{"path":945,"title":946,"description":947,"published":948,"category":698,"image":949,"draft":702},"\u002Fblog\u002Fmove-a-secret-to-an-edge-function","Сховати ключ API: перенесіть його в Supabase Edge Function","Сховати ключ API означає прибрати його з браузера, а Supabase Edge Function це найменше місце, куди його покласти. Два кроки поруч важать більше.","2026-10-05","\u002Fblog\u002Fmove-a-secret-to-an-edge-function\u002Fcard-800x500.png",{"path":951,"title":952,"description":953,"published":954,"category":698,"image":955,"draft":702},"\u002Fblog\u002Fenv-file-exposed-on-your-server","Чи відкритий ваш файл .env? Дванадцять шляхів для перевірки","Чи відкритий ваш файл .env на вашому власному вебсервері? Дванадцять адрес скажуть це за хвилину, а влучання означає, що все в ньому вже публічне.","2026-10-04","\u002Fblog\u002Fenv-file-exposed-on-your-server\u002Fcard-800x500.png",{"path":957,"title":958,"description":959,"published":960,"category":698,"image":961,"draft":702},"\u002Fblog\u002Fis-v0-safe","Безпека v0: усі 1 790 просканованих застосунків v0 отримали A","Безпека v0 на 1 790 живих застосунках v0: усі отримали A. Лише 17 згадували базу даних, і саме це здебільшого вимірює оцінка A.","2026-10-03","\u002Fblog\u002Fis-v0-safe\u002Fcard-800x500.png",{"path":963,"title":964,"description":965,"published":966,"category":698,"image":967,"draft":702},"\u002Fblog\u002Fis-bolt-safe","Чи безпечний Bolt? Що показали 1 123 застосунки Bolt","Чи безпечний Bolt? Ми прогнали 1 123 живі застосунки Bolt через дев’ять перевірок. Хостинг був чистим. Знахідки: ключі й відкриті таблиці в самих застосунках.","2026-10-02","\u002Fblog\u002Fis-bolt-safe\u002Fcard-800x500.png",{"path":222,"title":969,"description":970,"published":971,"category":698,"image":972,"draft":702},"Supabase не працює чи проблема у вашому застосунку? Як розрізнити","Supabase не працює чи зламався ваш застосунок? Пауза, повна база й ваша власна помилка виглядають однаково. Чотири перевірки їх розрізняють.","2026-10-01","\u002Fblog\u002Fis-supabase-down-or-your-app\u002Fcard-800x500.png",{"path":974,"title":975,"description":976,"published":977,"category":698,"image":978,"draft":702},"\u002Fblog\u002Fdoes-supabase-encrypt-my-data","Чи шифрує Supabase мої дані? Так. Ось від чого це захищає","Чи шифрує Supabase дані? Так: AES-256 у стані спокою, TLS під час передавання, SOC 2 та ISO 27001. Що покриває кожне і який витік не зупиняє жодне.","2026-09-30","\u002Fblog\u002Fdoes-supabase-encrypt-my-data\u002Fcard-800x500.png",{"path":980,"title":981,"description":982,"published":983,"category":698,"image":984,"draft":702},"\u002Fblog\u002Fsupabase-free-plan-limits","Ліміти безкоштовного тарифу Supabase і що стається на кожному","Ліміти безкоштовного тарифу Supabase: 500 МБ бази, 5 ГБ egress і жодних резервних копій. Що стається на кожній межі і що змінює Pro за $25.","2026-09-29","\u002Fblog\u002Fsupabase-free-plan-limits\u002Fcard-800x500.png",{"path":986,"title":987,"description":988,"published":989,"category":805,"image":990,"draft":702},"\u002Fblog\u002Ftest-your-supabase-backup","Перевірте резервну копію Supabase до того, як вона знадобиться","Як перевірити резервну копію Supabase: відновити в тестовий проєкт, порахувати рядки, увійти й знайти рядок, якого бракує обрізаному файлу.","2026-09-28","\u002Fblog\u002Ftest-your-supabase-backup\u002Fcard-800x500.png",{"path":992,"title":993,"description":994,"published":995,"category":805,"image":996,"draft":702},"\u002Fblog\u002Fsupabase-backup-github-action","Безкоштовна резервна копія Supabase через GitHub Action і підступ","Резервна копія Supabase через GitHub Action безкоштовна й годиться багатьом застосункам. Робочий процес, потрібний рядок підключення та egress.","2026-09-27","\u002Fblog\u002Fsupabase-backup-github-action\u002Fcard-800x500.png",{"path":998,"title":999,"description":1000,"published":1001,"category":805,"image":1002,"draft":702},"\u002Fblog\u002Fdownload-your-supabase-backup","Чому ви не можете завантажити резервну копію Supabase","Завантажити резервну копію Supabase на сучасному проєкті не вийде: щоденна копія там фізична. Як це перевірити і як тримати власну копію.","2026-09-26","\u002Fblog\u002Fdownload-your-supabase-backup\u002Fcard-800x500.png",{"path":1004,"title":1005,"description":1006,"published":1001,"category":698,"image":1007,"draft":702},"\u002Fblog\u002Fsupabase-permission-denied-for-table","Supabase \"permission denied for table\": бракує GRANT","З 30 жовтня нова таблиця в Supabase відповідає \"permission denied for table\", доки ви не дасте доступ. Лист показує лише половину виправлення.","\u002Fblog\u002Fsupabase-permission-denied-for-table\u002Fcard-800x500.png",{"path":1009,"title":1010,"description":1011,"published":1012,"category":698,"image":1013,"draft":702},"\u002Fblog\u002Fopen-api-endpoint-exposed","Чи є відкритий API-ендпоінт проблемою безпеки? Читайте JSON","Ваше сканування позначило відкритий API-ендпоінт. Чи це важливо, залежить від того, що повернулося, і більшість знайдених належали платформі.","2026-09-25","\u002Fblog\u002Fopen-api-endpoint-exposed\u002Fcard-800x500.png",{"path":1015,"title":1016,"description":1017,"published":1018,"category":698,"image":1019,"draft":702},"\u002Fblog\u002Flovable-security-scan","Сканування безпеки Lovable: чого воно не доведе","Сканування безпеки Lovable: що перевіряють Quick scan і Deep scan, коли запускається кожне, і єдине, чого не доведе жодне сканування зсередини.","2026-09-24","\u002Fblog\u002Flovable-security-scan\u002Fcard-800x500.png",{"path":1021,"title":1022,"description":1023,"published":1024,"category":805,"image":1025,"draft":702},"\u002Fblog\u002Fsupabase-backup-auth-users","Чому у вашому дампі Supabase немає користувачів","Запустіть supabase db dump окремо і отримаєте форму вашої бази та жодного її рядка, без схеми auth, у якій живуть ваші користувачі.","2026-09-23","\u002Fblog\u002Fsupabase-backup-auth-users\u002Fcard-800x500.png",{"path":1027,"title":1028,"description":1029,"published":1030,"category":698,"image":1031,"draft":702},"\u002Fblog\u002Fdomain-and-certificate-expiry","Домен закінчився, сайт лежить: що буде далі","Ваш домен закінчився і сайт лежить. Ось який годинник уже пішов, чому прострочений сертифікат це менша з двох бід, і як перевірити обидва.","2026-09-22","\u002Fblog\u002Fdomain-and-certificate-expiry\u002Fcard-800x500.png",{"path":1033,"title":1034,"description":1035,"published":1036,"category":698,"image":1037,"draft":702},"\u002Fblog\u002Fis-lovable-safe","Чи безпечний Lovable? Що показали 18 554 застосунки Lovable","Чи безпечний Lovable? Ми прогнали 18 554 живі застосунки Lovable через дев’ять перевірок. Платформа виявилася найчистішою з п’яти. Знахідки були в застосунках.","2026-09-21","\u002Fblog\u002Fis-lovable-safe\u002Fcard-800x500.png",{"path":1039,"title":1040,"description":1041,"published":1042,"category":698,"image":1043,"draft":702},"\u002Fblog\u002Fvibe-coded-app-security-checklist","Чек-лист безпеки для vibe coding, у девʼяти перевірках","Чек-лист безпеки для vibe coding із девʼяти пунктів, кожен з яких будь-хто може перевірити у вашому живому застосунку ззовні, і кожен має тест на один рядок.","2026-09-20","\u002Fblog\u002Fvibe-coded-app-security-checklist\u002Fcard-800x500.png",{"path":1045,"title":1046,"description":1047,"published":1048,"category":698,"image":1049,"draft":702},"\u002Fblog\u002Fstripe-secret-key-in-frontend","Секретний ключ Stripe у фронтенді може рухати гроші","Секретний ключ Stripe, відкритий у вашому фронтенді, може повертати кошти, списувати й читати кожну картку клієнта. А ключ pk_live_ там і має бути.","2026-09-19","\u002Fblog\u002Fstripe-secret-key-in-frontend\u002Fcard-800x500.png",{"path":1051,"title":1052,"description":1053,"published":1054,"category":698,"image":1055,"draft":702},"\u002Fblog\u002Fvite-and-next-public-env-vars","Змінні оточення Vite відкриті: префікс означає опублікувати це","Змінні оточення Vite відкриті у вашому застосунку, бо так просив префікс. VITE_ і NEXT_PUBLIC_ означають опублікувати це, а ШІ, який їх додав, не знав ціни.","2026-09-18","\u002Fblog\u002Fvite-and-next-public-env-vars\u002Fcard-800x500.png",{"path":1057,"title":1058,"description":1059,"published":1060,"category":698,"image":1061,"draft":702},"\u002Fblog\u002Fbase44-source-maps","Безпека Base44: що позначає скан і що з цього виправляти вам","Безпека Base44 на 5 438 просканованих застосунках: три знахідки майже на кожному належать платформі, source map є бейджем Base44, а ваша частина коротка.","2026-09-17","\u002Fblog\u002Fbase44-source-maps\u002Fcard-800x500.png",{"path":1063,"title":1064,"description":1065,"published":1066,"category":698,"image":1067,"draft":702},"\u002Fblog\u002Fis-cursor-ai-safe","Чи безпечний Cursor AI? Редактор, код і опублікований застосунок","Чи безпечний Cursor AI? Три запитання в одному пошуку: що Cursor зберігає, у чому помиляється його код і чи відкритий застосунок, який ви опублікували.","2026-09-16","\u002Fblog\u002Fis-cursor-ai-safe\u002Fcard-800x500.png",{"path":1069,"title":1070,"description":1071,"published":1072,"category":698,"image":1073,"draft":702},"\u002Fblog\u002Fis-replit-safe","Чи безпечний Replit? Що ми знайшли в 3 042 живих застосунках Replit","Чи безпечний Replit? Ми прогнали 3 042 живі застосунки Replit через дев’ять зовнішніх перевірок. Знахідки були в опублікованому застосунку, а не в хостингу.","2026-09-15","\u002Fblog\u002Fis-replit-safe\u002Fcard-800x500.png",{"path":1075,"title":1076,"description":1077,"published":1078,"category":805,"image":1079,"draft":702},"\u002Fblog\u002Fsupabase-storage-backup","Supabase storage backup: у копії бази даних немає жодного файлу","Supabase storage backup це окрема робота. Копії бази даних зберігають список ваших файлів і жодного з них, тож після відновлення кожне завантаження зламане.","2026-09-14","\u002Fblog\u002Fsupabase-storage-backup\u002Fcard-800x500.png",{"path":1081,"title":1082,"description":1083,"published":1084,"category":805,"image":1085,"draft":702},"\u002Fblog\u002Fsupabase-point-in-time-recovery","Point-in-time recovery у Supabase: ціна та межі","Point-in-time recovery у Supabase відмотує базу на будь-яку секунду за останній тиждень. Коштує $100 на місяць понад Pro і покриває лише базу даних.","2026-09-13","\u002Fblog\u002Fsupabase-point-in-time-recovery\u002Fcard-800x500.png",{"path":1087,"title":1088,"description":1089,"published":1090,"category":805,"image":1091,"draft":702},"\u002Fblog\u002Fsupabase-project-paused-recover","Проєкт Supabase на паузі? Ваші дані нікуди не зникли","Supabase поставив ваш проєкт на паузу після тижня без активності. Нічого не видалено, кнопка Restore стоїть поруч із назвою, і у вас є рік, щоб натиснути.","2026-09-12","\u002Fblog\u002Fsupabase-project-paused-recover\u002Fcard-800x500.png",{"path":1093,"title":1094,"description":1095,"published":1096,"category":698,"image":1097,"draft":702},"\u002Fblog\u002Fsafest-ai-app-builder","Який білдер застосунків з ШІ найбезпечніший? 30 998 тестів","Який білдер застосунків з ШІ найбезпечніший? Ми просканували 30 998 живих застосунків з Lovable, Base44, Replit, v0 і Bolt. Оцінку вирішує не білдер.","2026-09-11","\u002Fblog\u002Fsafest-ai-app-builder\u002Fcard-800x500.png",{"path":1099,"title":1100,"description":1101,"published":1102,"category":698,"image":1103,"draft":702},"\u002Fblog\u002Fenable-rls-on-every-supabase-table","Увімкніть Row Level Security на кожній таблиці Supabase і перевірте","Row Level Security у Supabase без політики закриває таблицю повністю. Політика без увімкненого перемикача не робить нічого. Ось SQL, і ось перевірка.","2026-09-10","\u002Fblog\u002Fenable-rls-on-every-supabase-table\u002Fcard-800x500.png",{"path":1105,"title":1106,"description":1107,"published":1108,"category":698,"image":1109,"draft":702},"\u002Fblog\u002Fsupabase-rls-disabled-in-public","Supabase \"RLS disabled in public\": чого не бачить попередження","Supabase позначає \"RLS disabled in public\" як помилку. Про політику читання, яка лишає вашу таблицю так само відкритою, він не каже нічого.","2026-09-09","\u002Fblog\u002Fsupabase-rls-disabled-in-public\u002Fcard-800x500.png",{"path":1111,"title":1112,"description":1113,"published":1114,"category":698,"image":1115,"draft":702},"\u002Fblog\u002Frotate-supabase-service-role-key","Як замінити злитий ключ service_role у Supabase","Supabase каже спершу закрити витік. Інші посібники кажуть міняти негайно. Що правильно, залежить від того, куди саме потрапив ваш ключ service_role.","2026-09-08","\u002Fblog\u002Frotate-supabase-service-role-key\u002Fcard-800x500.png",{"path":1117,"title":1118,"description":1119,"published":1120,"category":698,"image":1121,"draft":702},"\u002Fblog\u002Fvibe-coding-security-scanners-compared","Сканери безпеки для vibe coding у порівнянні, наш теж","Найкращий сканер безпеки для vibe coding залежить від трьох питань, на які не відповідає жоден перелік функцій. Вісім інструментів і ціни.","2026-09-07","\u002Fblog\u002Fvibe-coding-security-scanners-compared\u002Fcard-800x500.png",{"path":1123,"title":1124,"description":1125,"published":1126,"category":698,"image":1127,"draft":702},"\u002Fblog\u002Fsupabase-security-checker","Supabase security checker: п’ять перевірок, які зробите самі","Supabase security checker читає ваш опублікований застосунок, а не налаштування проєкту. Ось п’ять перевірок і як виконати кожну самостійно.","2026-09-06","\u002Fblog\u002Fsupabase-security-checker\u002Fcard-800x500.png",{"path":1129,"title":1130,"description":1131,"published":1132,"category":698,"image":1133,"draft":702},"\u002Fblog\u002Fvibe-coding-security-scanner","Сканер безпеки для vibe coding: чого не бачить скан URL","Сканер безпеки для vibe coding читає ваш робочий застосунок ззовні. Що це охоплює, чотири речі, яких він не бачить, і як читати результат.","2026-09-05","\u002Fblog\u002Fvibe-coding-security-scanner\u002Fcard-800x500.png",{"path":1135,"title":1136,"description":1137,"published":1138,"category":698,"image":1139,"draft":702},"\u002Fblog\u002Fmissing-security-headers","Відсутні заголовки безпеки: коли це справді важливо","Відсутні заголовки безпеки трапляються в наших звітах найчастіше. Від чого вони захищають і коли це найменш терміновий рядок вашого звіту.","2026-09-04","\u002Fblog\u002Fmissing-security-headers\u002Fcard-800x500.png",{"path":1141,"title":1142,"description":1143,"published":1144,"category":698,"image":1145,"draft":702},"\u002Fblog\u002Fopenai-api-key-exposed-in-frontend","Ваш ключ API OpenAI відкритий у фронтенді. Замініть його.","Ключ API OpenAI, відкритий у фронтенді, не можна прив'язати до домену. Замініть його сьогодні, перенесіть виклик на свій сервер і обмежте витрати.","2026-09-03","\u002Fblog\u002Fopenai-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1147,"title":1148,"description":1149,"published":1150,"category":698,"image":1151,"draft":702},"\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps","Ключ API у фронтенді: що насправді віддають 30 998 застосунків","Ключ API, відкритий у вашому фронтенді, зазвичай є ключем Google Maps. Ми просканували 30 998 vibe-coded застосунків і порахували, що витікає насправді.","2026-09-02","\u002Fblog\u002Fwhat-secrets-leak-from-vibe-coded-apps\u002Fcard-800x500.png",{"path":1153,"title":1154,"description":1155,"published":1156,"category":805,"image":1157,"draft":702},"\u002Fblog\u002Fsupabase-backup-tools-compared","Інструменти резервного копіювання Supabase, і наш серед них","Чотири види інструментів резервного копіювання Supabase, що копіює кожен і коли безкоштовна GitHub Action виграє в будь-якої оплати, нашої теж.","2026-09-01","\u002Fblog\u002Fsupabase-backup-tools-compared\u002Fcard-800x500.png",{"path":1159,"title":1160,"description":1161,"published":1162,"category":698,"image":1163,"draft":702},"\u002Fblog\u002Freplit-secrets-explained","Як користуватися секретами в Replit і що все одно публікується","Як користуватися секретами в Replit: додати, прочитати і усунути дві причини undefined. А ще ключі, які цей інструмент не здатен зберегти в таємниці.","2026-08-31","\u002Fblog\u002Freplit-secrets-explained\u002Fcard-800x500.png",{"path":1165,"title":1166,"description":1167,"published":1168,"category":805,"image":1169,"draft":702},"\u002Fblog\u002Fback-up-supabase-free-tier","Резервні копії на безкоштовному тарифі Supabase без терміналу","На безкоштовному тарифі Supabase резервних копій немає: копію робите ви. Як зробити її з панелі та що втрачає шлях через CSV.","2026-08-30","\u002Fblog\u002Fback-up-supabase-free-tier\u002Fcard-800x500.png",{"path":1171,"title":1172,"description":1173,"published":1174,"category":698,"image":1175,"draft":702},"\u002Fblog\u002Fis-supabase-secure","Чи безпечний Supabase? Так. Ваш проєкт це інше питання","Чи безпечний Supabase? Платформа проходить аудити, шифрує дані й тримає пентести. Їхня документація каже, де це закінчується і починаються ваші налаштування.","2026-08-29","\u002Fblog\u002Fis-supabase-secure\u002Fcard-800x500.png",{"path":1177,"title":1178,"description":1179,"published":1180,"category":698,"image":1181,"draft":702},"\u002Fblog\u002Fwhere-to-find-supabase-api-keys","Де знайти API-ключі Supabase: anon, service_role і URL","URL проєкту, ключ anon і ключ service_role лежать на одній сторінці панелі. Ось де вона, і яке з чотирьох значень має бути у вашому застосунку.","2026-08-28","\u002Fblog\u002Fwhere-to-find-supabase-api-keys\u002Fcard-800x500.png",{"path":1183,"title":1184,"description":1185,"published":1186,"category":698,"image":1187,"draft":702},"\u002Fblog\u002Fnew-row-violates-row-level-security-policy","New row violates row-level security policy в Supabase. Що далі?","\"New row violates row-level security policy\" означає, що Supabase відмовив у записі. Швидке виправлення знову відкриває таблицю для всіх.","2026-08-27","\u002Fblog\u002Fnew-row-violates-row-level-security-policy\u002Fcard-800x500.png",{"path":1189,"title":1190,"description":1191,"published":1192,"category":698,"image":1193,"draft":702},"\u002Fblog\u002Fcors-wildcard-security-risk","Чи є вайлдкард CORS ризиком для безпеки? Майже ніколи.","Чи є вайлдкард CORS ризиком для безпеки? Зазвичай це типове налаштування вашого білдера, і воно не видає нічого, що ваш сервер і так віддавав кожному.","2026-08-26","\u002Fblog\u002Fcors-wildcard-security-risk\u002Fcard-800x500.png",{"path":1195,"title":1196,"description":1197,"published":1198,"category":805,"image":1199,"draft":702},"\u002Fblog\u002Fsupabase-branching-is-not-a-backup","Branching у Supabase це не бекап. Він іде тільки вперед.","Чому branching у Supabase це не бекап: гілка стартує без ваших даних, а мердж переносить саму лише схему. Для чого він потрібен і що брати замість нього.","2026-08-25","\u002Fblog\u002Fsupabase-branching-is-not-a-backup\u002Fcard-800x500.png",{"path":1201,"title":1202,"description":1203,"published":1204,"category":805,"image":1205,"draft":702},"\u002Fblog\u002Fhow-to-restore-a-supabase-backup","Як відновити резервну копію Supabase, і що ламається потім","Як відновити резервну копію Supabase з панелі або з файлу дампа, що саме замінює відновлення і чому ваш застосунок може лишитися зламаним після нього.","2026-08-24","\u002Fblog\u002Fhow-to-restore-a-supabase-backup\u002Fcard-800x500.png",{"path":1207,"title":1208,"description":1209,"published":1210,"category":698,"image":1211,"draft":702},"\u002Fblog\u002Fsupabase-storage-bucket-public","Ваш бакет Supabase Storage публічний. Чи це проблема?","Публічний бакет Supabase Storage означає, що той, хто має URL файлу, може його відкрити. Він не означає, що хтось може переглянути список вмісту.","2026-08-23","\u002Fblog\u002Fsupabase-storage-bucket-public\u002Fcard-800x500.png",{"path":1213,"title":1214,"description":1215,"published":1216,"category":698,"image":1217,"draft":702},"\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend","Чи є проблемою ключ API Google у вашому браузері?","Ключ API Google у відкритому коді сторінки наш сканер знаходить найчастіше, і зазвичай усе гаразд. Вирішує це одне безкоштовне налаштування.","2026-08-22","\u002Fblog\u002Fgoogle-api-key-exposed-in-frontend\u002Fcard-800x500.png",{"path":1219,"title":1220,"description":1221,"published":1222,"category":805,"image":1223,"draft":702},"\u002Fblog\u002Fai-agent-deleted-my-database","ШІ-агент видалив мої дані в Supabase. Що можна відновити?","ШІ-агент видалив дані з вашої бази. Те, що ви зможете відновити, вирішилося раніше, а наступні хвилини вирішують, скільки з цього вціліє.","2026-08-21","\u002Fblog\u002Fai-agent-deleted-my-database\u002Fcard-800x500.png",{"path":1225,"title":1226,"description":1227,"published":1228,"category":698,"image":1229,"draft":702},"\u002Fblog\u002Fcan-anyone-read-your-supabase-database","Чи може будь-хто прочитати вашу базу Supabase? 3 680 застосунків","Чи може будь-хто прочитати вашу базу даних Supabase без входу? Ми просканували 30 998 живих застосунків, зроблених ШІ-білдерами, і виміряли, як часто так.","2026-08-18","\u002Fblog\u002Fcan-anyone-read-your-supabase-database\u002Fcard-800x500.png",{"path":1231,"title":1232,"description":1233,"published":1228,"category":698,"image":1234,"draft":702},"\u002Fblog\u002Fsource-maps-exposed-in-production","Відкриті source maps: ваш застосунок публікує свій вихідний код","Відкрита source map дає будь-кому прочитати оригінальний код вашого застосунку, разом із коментарями. Перевірка за 30 секунд, і що важить насправді.","\u002Fblog\u002Fsource-maps-exposed-in-production\u002Fcard-800x500.png",{"path":1236,"title":1237,"description":1238,"published":1239,"category":698,"image":1240,"draft":702},"\u002Fblog\u002Fsupabase-new-api-keys","Supabase publishable key: це той самий anon key?","Supabase замінив anon і service_role публічними та секретними ключами. Який із них має бути у вашому застосунку, а який не має бути ніколи?","2026-08-12","\u002Fblog\u002Fsupabase-new-api-keys\u002Fcard-800x500.png",{"path":1242,"title":1243,"description":1244,"published":1245,"category":805,"image":1246,"draft":702},"\u002Fblog\u002Fdoes-supabase-back-up-my-database","Чи робить Supabase резервні копії моєї бази? Залежить від тарифу.","Чи робить Supabase резервні копії вашої бази даних? На платних тарифах щодня, на безкоштовному жодної. Як дізнатися, що у вас насправді є.","2026-08-11","\u002Fblog\u002Fdoes-supabase-back-up-my-database\u002Fcard-800x500.png",{"path":1248,"title":1249,"description":1250,"published":1251,"category":698,"image":1252,"draft":702},"\u002Fblog\u002Fsupabase-rls-on-but-table-still-public","Supabase Row Level Security увімкнено. Таблиця досі публічна.","Увімкнути Supabase Row Level Security не означає захистити таблицю. Захищають політики, а та, що полагодила застосунок, часто впускає всіх.","2026-08-10","\u002Fblog\u002Fsupabase-rls-on-but-table-still-public\u002Fcard-800x500.png",{"path":1254,"title":1255,"description":1256,"published":1251,"category":805,"image":1257,"draft":702},"\u002Fblog\u002Fversion-history-is-not-a-backup","Історія версій не є резервною копією. Вона не поверне таблицю.","Lovable і Bolt ведуть історію версій вашого коду. Ваша база даних працює як окремий сервіс, тож відкат назад не поверне ваші дані.","\u002Fblog\u002Fversion-history-is-not-a-backup\u002Fcard-800x500.png",{"path":1259,"title":1260,"description":1261,"published":1262,"category":805,"image":1263,"draft":702},"\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database","Три способи зробити резервну копію бази Supabase, і чого бракує","Панель, pg_dump і керований сервіс. Що насправді зберігає кожен спосіб, що тихо лишає осторонь і який із них переживе втрату акаунта.","2026-08-09","\u002Fblog\u002Fthree-ways-to-back-up-a-supabase-database\u002Fcard-800x500.png",{"path":89,"title":1265,"description":1266,"published":1262,"category":698,"image":1267,"draft":702},"Які API-ключі безпечні у браузері, а які ні","Ваш ключ anon у Supabase створений, щоб бути публічним. Ключ service_role для цього не створений, і він ігнорує всі правила, які ви задали. Як їх розрізнити.","\u002Fblog\u002Fwhich-api-keys-are-safe-in-your-frontend\u002Fcard-800x500.png",1794213654377]