Основи безпеки
Нові API-ключі Supabase: який із них безпечний у застосунку?
Supabase замінив anon і service_role публічними та секретними ключами. Який із них має бути у вашому застосунку, а який не має бути ніколи?

Коротко
- Supabase тепер видає ключі sb_publishable_ і sb_secret_. Вони заступають anon і service_role і виконують ті самі дві ролі.
- Публічний ключ має бути у вашому застосунку. Секретний не має бути там ніколи, і тепер ви розрізняєте їх за першими символами.
- Ваші старі ключі сьогодні ще працюють. Supabase оголосив, що наприкінці 2026 року всі проєкти муситимуть від них відмовитися.
Якщо ви нещодавно відкрили панель Supabase і побачили ключі, що починаються з
sb_publishable_ і sb_secret_, там, де раніше були anon і service_role,
то нічого не зламалося. Supabase перейменував свої API-ключі, і знайома вам пара
поступово йде.
Зміна невелика в тому, що вона робить, і велика в тому, що вона запобігає. Обидва ключі й далі виконують рівно ті самі дві ролі. Нове те, що тепер ви бачите, який із них який, нічого не відкриваючи.
Що Supabase змінив насправді
Supabase оголосив нові ключі в липні 2025 року разом зі зміною того, як він підписує токени входу. Дві речі замінили дві речі:
- Публічний ключ,
sb_publishable_…, заступає ключanon. - Секретні ключі,
sb_secret_…, заступають ключservice_role.
Права не змінилися. Публічний ключ і далі лише називає ваш проєкт і не має власних прав; секретний і далі обходить кожне написане вами правило. Якщо ви вже знаєте, які ключі безпечні у фронтенді, жодна частина цього знання не стала хибною.
Дві практичні відмінності варто знати. Ви можете мати кілька секретних ключів одночасно й відкликати їх по одному, тож заміна ключа більше не означає момент, коли ламається все, що ним користувалося. А старі ключі мали властивість, якої майже ніхто не помічав: це були JWT, що спливають за десять років після створення проєкту. Нові не несуть терміну придатності всередині.
Чи ключ anon це те саме, що публічний ключ?
Так у тому, що він робить, і ні в тому, чим він є.
sb_publishable_… виконує роботу ключа anon точнісінько: він називає ваш проєкт,
щоб запит знав, куди йти, не несе власних прав і призначений лежати у застосунку
там, де його прочитає будь-хто. Усе, що ви вже розуміли про ключ anon, лишається
правдою. Якщо ви поміняєте один на інший, жодна таблиця не стане більш чи менш
читаною, бо жоден із двох ніколи не захищав ваші рядки. Це робить Row Level
Security.
Різниця у самому значенні. Це різні рядки в різних форматах, видані окремо, і проєкт може тримати обидві пари водночас, поки триває міграція. Тож «той самий ключ під новим іменем» це хибна картинка. Це новий ключ на старій роботі, і ваш застосунок треба про нього повідомити.
Один наслідок ловить багатьох: увімкнути нові ключі не означає перевести застосунок. Supabase видає їх і лишає застосунок працювати на тому, що ви йому дали. Заміна це однорядкова зміна, яку робите ви самі, там, де застосунок створює свій клієнт Supabase.
Який із двох має бути у вашому застосунку
Публічний, і лише публічний.
Ваш застосунок працює в браузері відвідувача, і запит до бази йде звідти. Він
має сказати, до якого проєкту належить, і цей ідентифікатор доходить до кожного
відвідувача за задумом. sb_publishable_… і є ключем, зробленим саме для цього:
знайти його у застосунку не є знахідкою, і ніколи не було.
sb_secret_… робить протилежне. Він читає і змінює кожен рядок у кожній таблиці
звідки завгодно, повністю ігноруючи ваші політики, і в цьому весь його сенс. Його
місце на сервері, в edge-функції, у воркері: ніде, куди дістає браузер. Якщо такий ключ
колись потрапляв у код фронтенду, замініть його в панелі, перш ніж правити щось
інше, бо видалення рядка двері не зачиняє.
Який вигляд має ключ sb_publishable_?
Один суцільний рядок, що починається буквальним sb_publishable_, а далі йде
випадкова середина. Жодної крапки всередині, і нічого такого, що можна було б
розшифрувати. Його секретний відповідник читається так само, тільки з
sb_secret_ спереду.
Стара пара має зовсім інший вигляд. anon і service_role це JWT: три блоки,
розділені крапками, кілька сотень символів завдовжки, починаються з eyJ.
Середній блок не зашифрований, а лише закодований, тож будь-хто вставить його в
декодер і прочитає всередині поле role. Саме так двійку розрізняли раніше, і
саме тому так багато людей цього не робили.
Прочитати перші п'ятнадцять символів це вся перевірка тепер. Небезпечний ключ оголошує себе в тій частині рядка, куди око падає першим, а не посеред чогось, що треба спершу відкрити.
Як зрозуміти, який ключ у вас
Прочитайте перші символи. Тепер уся перевірка в цьому.
| Що ви бачите | Що це | Безпечний у браузері? |
|---|---|---|
sb_publishable_… | сучасний публічний ключ | Тут доречно |
sb_secret_… | сучасний секретний ключ | Ніколи |
eyJ… з anon | старий публічний ключ | Тут доречно |
eyJ… з service_role | старий секретний ключ | Ніколи |
Сучасний ключ виглядає як один довгий рядок із двох половин: випадкової середини
й короткої контрольної суми в кінці. Старий ключ складається з трьох блоків,
розділених крапками, і середній блок є читабельним текстом, а не шифром. Саме тому
розрізнити стару пару означало розкодувати її та прочитати поле role.
Якщо ви знайшли ключ у застосунку і не розумієте, який це, наше безкоштовне сканування читає ваш живий сайт ззовні й називає те, що бачить. Це триває приблизно 20 секунд і не потребує акаунта: сканувати застосунок.
Чи працюють іще мої старі ключі anon і service_role?
Сьогодні так. Supabase опублікував розклад, а не вимикач:
| Коли | Що відбувається |
|---|---|
| 1 листопада 2025 | Проєкти, відновлені після цієї дати, взагалі не отримують anon і service_role. |
| Кінець 2026, дата не названа | Усі проєкти муситимуть користуватися новими ключами. |
Тож цього тижня надзвичайної ситуації немає, а цього року є термін. Якщо ваш застосунок зробили до перейменування й відтоді не чіпали, він зараз працює на старих ключах і працюватиме ще якийсь час.
Аргумент рухатися раніше полягає не в терміні. Це той день, коли хтось вставить
не той ключ у промпт: sb_secret_ заявляє про себе, а eyJ… мовчить.
Що таке застарілі ключі API Supabase?
Застарілими Supabase тепер називає початкову пару, anon і service_role, разом
із JWT-секретом, який їх підписує. Кожен проєкт, створений до середини 2025 року,
починав саме з них, а це більшість vibe-coded застосунків.
Вони відрізняються від нової пари так, що варто знати. Оскільки це JWT, вони несуть термін дії, який спливає через десять років після створення проєкту, і лежить він усередині ключа, куди ніхто не заглядає. Змінити їх не можна взагалі: Supabase сказав, що ротація застарілих секретів anon, service_role і JWT більше неможлива, тож знецінити той, що витік, означає перейти на нові ключі й вимкнути стару пару. А проєкт, відновлений після 1 листопада 2025 року, не отримує їх зовсім.
Якщо один із ваших уже витік, ця міграція це єдиний спосіб його знецінити, а порядок дій залежить від того, чи ключ уже лежить у бандлі, який завантажують ваші відвідувачі.
Як перейти, не зламавши застосунок
Власний посібник з міграції Supabase лишається орієнтиром. Коротка версія для застосунку, який ви не писали руками, за умови що ви вже знаєте, де лежить сторінка з вашими ключами:
- У панелі відкрийте Settings → API Keys і створіть нові ключі. Це додає їх; старі нікуди не зникають, і обидві пари працюють одночасно.
- Знайдіть місце, де ваш застосунок створює клієнт Supabase, і замініть публічний ключ. У білдері на кшталт Lovable чи Bolt це зазвичай одне значення в налаштуваннях проєкту, а не рядок коду.
- Замініть секретний ключ усюди, де він використовується на сервері: edge-функції, вебхуки, заплановані завдання і все інше, що не є браузером.
- Відкрийте застосунок і пройдіть місцями, які читають і записують дані. Хибний публічний ключ падає одразу й голосно, і це хороший випадок.
- І лише коли все працює, вимикайте старі ключі.
П'ятий крок варто лишити наостанок і зробити його свідомо, а не ніколи:
напівмігровані проєкти, де застосунок досі несе старий ключ anon поруч із живим
sb_publishable_, трапляються часто і плутають, коли щось іде не так.
Що зробити цього тижня
Що робити
- Відкрийте Settings → API Keys і подивіться, які пари є у вашому проєкті. Це хвилина, і ви вже знаєте, де стоїте.
- Якщо знайдете
sb_secret_…абоservice_roleбудь-де в коді фронтенду, замініть ключ сьогодні. Це єдиний терміновий пункт у цьому списку. - Створіть нові ключі й переведіть застосунок, коли матимете півгодини, не через термін, а тому що префікс робить наступну помилку очевидною.
- Заразом перевірте Row Level Security. Новий ключ нічого не змінює в тому, що дозволяють ваші політики, а увімкнути RLS не означає бути захищеним.
Якщо потрібна версія для конкретної платформи, у нас є зрозумілий розбір для застосунків на Supabase, а 10-хвилинний чекліст безпеки охоплює цей пункт поряд з рештою речей, які варто вимкнути у щойно запущеному застосунку.
Поширені запитання
Чи sb_publishable_ – це те саме, що ключ anon?
Він виконує ту саму роботу. Він називає ваш проєкт, щоб запит знав, куди йти, не має власних прав і призначений жити у вашому застосунку, де його може прочитати будь-хто. В обох випадках ваші дані захищає Row Level Security, а не ключ.
Чи працюють ще мої ключі anon і service_role?
Так, сьогодні. Supabase лишив їх робочими на час міграції, і ви можете мати обидві пари водночас. Оголошено, що наприкінці 2026 року всім проєктам доведеться перейти на нові ключі, але точної дати ще немає.
У панелі є обидві пари. Який має використовувати мій застосунок?
Публічний, sb_publishable_. Заміна займає один рядок: підставте інший ключ там, де застосунок створює клієнт Supabase. Ні таблиці, ні політики змінювати не треба, бо новий ключ має рівно ті самі права, що мав anon.
Чи новий формат сам собою робить застосунок безпечнішим?
Ні. Він робить небезпечний ключ помітним, і це реальна вартість у ненароблених помилках, але публічний ключ і далі читає все, що дозволяють ваші політики. Якщо Row Level Security вимкнено, новий ключ відкриває вашу базу рівно так само широко, як відкривав старий.
Що таке публічний ключ Supabase?
Це ключ, який ваш застосунок і має відвантажувати: sb_publishable_ і далі випадковий рядок, виданий Supabase, щоб кожен запит називав ваш проєкт. Власних привілеїв він не несе, тож читає рівно те, що дозволяють ваші політики Row Level Security, і не більше. Він замінив ключ anon, робить ту саму роботу, і його спокійно можна лишати в коді, який бачить будь-хто.
Що таке застарілі ключі API Supabase?
Застарілими Supabase тепер називає початкову пару, anon і service_role, разом із JWT-секретом, який їх підписує. Це JWT, а не непрозорі рядки, вони несуть термін дії через десять років після створення проєкту, а проєкти, відновлені після 1 листопада 2025 року, не отримують їх зовсім. Наявні проєкти працюють на них до переходу наприкінці 2026 року.