Cryptography

How to Rotate Your Supabase JWT Secret Without Breaking Auth

11 min read
By
How to Rotate Your Supabase JWT Secret Without Breaking Auth

Photo by Lukas from Pexels

Supabase has made authentication remarkably easy. With a few clicks, you get a full authentication system with JWT tokens, Row Level Security, and a PostgreSQL database that respects user permissions. But that convenience comes with a responsibility: managing the JWT secret that signs every authentication token your application issues.

Rotating that secret is one of the most important security practices you can perform, and one of the most disruptive if done wrong. Get it right, and your users barely notice. Get it wrong, and every active session breaks simultaneously.

Here's how to rotate your Supabase JWT secret safely.

What the Supabase JWT Secret Does

When a user logs in through Supabase Auth, the server issues a JSON Web Token (JWT). This token contains claims about the user: their UUID, their email, their role, and an expiration timestamp. The token is signed with your project's JWT secret.

Every request your frontend makes to Supabase includes this token. Supabase's PostgREST layer verifies the token's signature using the JWT secret before processing the request. If the signature is valid, Supabase extracts the user's claims and applies Row Level Security policies based on them.

The JWT secret is also used by Supabase's GoTrue auth server to sign tokens, by PostgREST to verify them, and by your own backend if you verify tokens server-side. It's the shared secret that makes the entire authentication system work.

If this secret is compromised, an attacker can forge tokens for any user, including administrators. They can bypass Row Level Security entirely by crafting tokens with elevated roles. The JWT secret is, in effect, the master key to your authentication system.

Why You Need to Rotate It

Key rotation is a fundamental security practice. The principle is simple: the longer a secret exists, the more likely it is to be exposed. Rotation limits the window of exposure if a leak occurs.

There are several scenarios that should trigger an immediate rotation:

**Suspected exposure.** If you think the secret might have been leaked, whether through a misconfigured .env file, a developer's laptop, a CI log, or a security incident, rotate immediately.

**Team turnover.** When a developer with access to the secret leaves the team, rotation ensures they can't use old knowledge to forge tokens.

**Scheduled maintenance.** Even without a specific trigger, periodic rotation is good hygiene. Every 3 to 6 months is reasonable for most applications.

**After a security audit.** If you've had a security review, rotating the JWT secret afterward ensures any theoretical exposure discovered during the audit is neutralized.

Before You Rotate: Preparation

Rotating the JWT secret is not a click-and-done operation. It requires coordination across your frontend, backend, and infrastructure. Here's what to prepare before touching the secret.

**Audit where the secret is used.** The JWT secret appears in several places: the Supabase dashboard, your self-hosted configuration if applicable, your backend code if you verify tokens server-side, and any edge functions that validate JWTs. Make a list of every location.

**Check if you verify tokens server-side.** If your backend verifies Supabase JWTs independently, it needs the JWT secret to verify signatures. After rotation, the old secret won't work. Your backend needs to be updated with the new secret at the same time as the rotation.

**Plan for token invalidation.** All existing JWTs become invalid the moment you rotate. Users with active sessions will need to re-authenticate. If your app uses refresh tokens, the refresh flow should handle this gracefully. If it doesn't, users will see errors and need to log in again.

**Choose a low-traffic window.** Rotation causes a brief disruption for anyone with an active session. Schedule it during your lowest-traffic period to minimize impact.

**Communicate with users.** If your application has many active users, consider notifying them about a brief maintenance window. Frame it as a security improvement, because it is.

Step-by-Step Rotation Process

**Step 1: Generate a new secret.** You need a new, strong secret to replace the old one. A 32-byte random string is the minimum. Use a CSPRNG to generate it. You can use our JWT Secret Generator to create one instantly.

bash openssl rand -base64 32

Or with Python:

python import secrets print(secrets.token_urlsafe(32))

**Step 2: Update your backend.** If your backend verifies JWTs server-side, update the secret in your environment configuration. Don't deploy yet, just have the change ready. The deployment needs to happen simultaneously with the Supabase rotation.

**Step 3: Deploy backend changes.** Deploy the updated backend configuration so it's ready to verify tokens with the new secret. If your backend supports hot-reloading of configuration, this might not require a restart. Otherwise, restart your backend services.

**Step 4: Rotate the secret in Supabase.** In the Supabase dashboard, navigate to Project Settings, then API. Find the JWT secret setting and update it with your new value. In self-hosted Supabase, update the JWT_SECRET environment variable and restart the relevant services.

**Step 5: Verify.** Immediately after rotation, test authentication. Try logging in, accessing a protected resource, and performing an authenticated API call. If everything works, the rotation was successful.

**Step 6: Monitor.** Watch your error logs for the next hour. You might see authentication errors from clients with stale tokens. These should resolve as users re-authenticate. If errors persist, there may be a configuration issue.

Handling the Transition for Users

The moment you rotate the secret, every existing JWT becomes invalid. This means:

- Users with active sessions will get 401 Unauthorized responses - Frontend applications need to handle this by redirecting to the login page - Refresh tokens, if implemented, should trigger a re-authentication flow - Any long-lived tokens (if you've extended JWT expiration) will need to be reissued

The best user experience comes from a well-implemented refresh token flow. When the access token fails, the frontend should automatically attempt to use the refresh token to get a new access token. If the refresh token is also invalid (which it will be if it's a JWT signed with the old secret), the frontend should redirect to login.

If you're not using refresh tokens, users will simply see an error and need to log in again. This is disruptive but not catastrophic for most applications.

For applications where session continuity is critical, consider a brief grace period. You could implement a backend endpoint that accepts old tokens and reissues them with the new secret, but this requires custom infrastructure and adds complexity. For most teams, accepting the brief disruption is the simpler and safer choice.

Common Pitfalls

**Forgetting backend verification.** If your backend verifies JWTs independently and you forget to update the secret there, all authenticated backend requests will fail after rotation. The frontend works fine (it just sends tokens), but the backend rejects them.

**Not updating edge functions.** Supabase Edge Functions that verify JWTs also need the updated secret. If you're using Supabase's built-in JWT verification in edge functions, the secret update should propagate automatically. But if you've hardcoded the secret in a function, you need to update it.

**Rotating during peak traffic.** If you rotate during your busiest period, the disruption affects the maximum number of users. Choose a low-traffic window.

**Not testing after rotation.** Don't assume the rotation worked. Test the full authentication flow immediately after. Login, authenticated request, token refresh, logout. Verify each step.

**Not securing the new secret.** The new secret is just as sensitive as the old one. Store it in environment variables, not in code. Add it to your secrets manager. Don't commit it to Git.

After Rotation: Cleanup

Once the rotation is complete and verified, clean up the old secret. Remove it from any configuration files, environment variables, and secrets managers where it was stored. The old secret is now useless (it can't verify new tokens), but leaving it around creates confusion and potential security issues if someone mistakenly uses it.

Update your documentation to reflect the new secret's location and rotation procedure. If this is your first rotation, document the process so the next one is smoother.

Schedule the next rotation. Set a calendar reminder for 3 to 6 months out, so you're not caught off guard.

The Bottom Line

Rotating your Supabase JWT secret is a critical security practice that doesn't have to be painful. With proper preparation, coordination, and timing, you can rotate with minimal disruption to users.

Generate a strong new secret, update all the places it's used, rotate during a low-traffic window, and test thoroughly afterward. Your users will barely notice, and your authentication system will be that much more secure.

For guidance on the initial setup of your Supabase JWT secret, see our companion guide on Supabase JWT secret setup. And for understanding the broader context of secret key management across frameworks, our post on Django's SECRET_KEY covers the same principles in a different ecosystem.

Frequently Asked Questions

How often should I rotate my Supabase JWT secret?

There is no universal rule, but a common practice is every 3 to 6 months for high-security applications, or at least annually for most projects. You should also rotate immediately if you suspect the secret has been exposed, if a team member with access leaves, or after any security incident.

Will rotating the JWT secret log out all users?

Yes, rotating the JWT secret invalidates all existing tokens. Users will need to re-authenticate to get new tokens. To minimize disruption, plan the rotation during low-traffic periods, notify users in advance, and ensure your refresh token flow handles the transition gracefully.

Can I have overlapping JWT secrets during rotation?

Supabase does not natively support multiple valid JWT secrets simultaneously. The rotation is atomic: the old secret stops working and the new one takes effect immediately. This is why you need to deploy frontend and backend changes that rely on the new secret at the same time.

Where is the Supabase JWT secret stored?

The JWT secret is set in your Supabase project settings under Authentication. In the dashboard, navigate to Project Settings, then API, where you will find the JWT secret. In self-hosted Supabase, it is set via the JWT_SECRET environment variable in your docker-compose configuration.

Try NovelCrypt Tools

Experience military-grade encryption for your sensitive data. Create self-destructing messages, encrypt files, or explore our experimental lab tools.

Explore NovelCrypt