# Rotating API keys and the JWT secret

> SupaHost projects use legacy anon and service_role keys, and key or JWT secret rotation isn't available in the dashboard. What that means, and what to do if a service_role key leaks.

Source: https://supahost.app/kb/rotating-jwt-secret · Updated 2026-11-11

Rotation isn't available in the SupaHost dashboard. Each project has one JWT secret and two keys signed with it, `anon` and `service_role`, and there's no button or API to replace them. If your `service_role` key has leaked, email supahost@volods.com straight away with the project name, and follow the containment steps below while you wait.

## How keys work on SupaHost

- Each project gets its own JWT secret when it's created. The `anon` and `service_role` keys are HS256 JWTs signed with it, valid for ten years.
- There are no publishable (`sb_publishable_...`) or secret (`sb_secret_...`) keys, and no signing-key rotation.
- Users' access tokens are signed with the same secret, so changing it would sign every user out and invalidate both keys at once.
- You'll find both keys under Dashboard → your project → **Connect** → **App**. Only the instance owner can reveal `service_role`.

Branches and new projects get their own secret and keys, so a key from one project never works on another.

## If the anon key is exposed

That's expected. The `anon` key is meant to be public: it ships in every web and mobile app. It only gives the access your Row Level Security policies allow for the `anon` and `authenticated` roles. You don't need to rotate it. Check your policies instead:

```sql
-- Tables in public without RLS: anyone with the anon key can read and write them
select tablename from pg_tables
where schemaname = 'public' and not rowsecurity;
```

## If the service_role key leaks

The `service_role` key bypasses RLS and can use the Auth admin API, so treat a leak as urgent.

1. **Contact support.** Email supahost@volods.com with the project name, when and where the key was exposed, and whether you've seen misuse.
2. **Remove it from where it leaked.** Delete it from the client bundle, repository, logs or screenshot, and take down the affected build. If it was pushed to Git, deleting the file isn't enough, because it's still in the history. Treat it as known to others.
3. **Stop shipping it.** Search your codebase and environment settings for the key and make sure it's only in server-side variables.
4. **Look for misuse.** Check for unexpected users and recent changes:

   ```sql
   select id, email, created_at, last_sign_in_at
   from auth.users
   order by created_at desc
   limit 50;
   ```

   Review recent rows in your important tables, and your Storage buckets. If data was changed, the **Backups** tab can restore the project's database from a daily backup, or to a point in time on plans with point-in-time recovery. Storage files aren't part of database backups.
5. **Rotate secrets stored next to it.** If the key leaked with other values (Stripe keys, email provider keys, Edge Function secrets), rotate those with their providers and update them on the **Functions** tab's **Secrets** card.

## Prevent the next leak

- Keep `service_role` in server environment variables only: never `NEXT_PUBLIC_`, `VITE_` or anything bundled for the browser or a mobile app.
- In Edge Functions, use the injected `SUPABASE_SERVICE_ROLE_KEY` instead of pasting the key into code.
- Add a secret scanner to your repository so a pushed key is caught early.

## Related

- [API keys](/docs/api/api-keys)
- [Keeping keys safe](/docs/security/api-key-safety)
- [Admin tasks on the server with the service_role key](/kb/server-side-admin-tasks)
- [Securing your API](/docs/api/securing-your-api)
