Supabase has become one of the most popular backend-as-a-service platforms for modern web applications. Its built-in authentication, PostgreSQL database, and real-time features make it easy to build full-stack applications quickly. But that convenience comes with a security consideration that too many developers overlook: the JWT secret.
Supabase uses JSON Web Tokens for authentication. Every auth token issued by Supabase Auth is signed with your project's JWT secret. If that secret is compromised or left at its default value, an attacker can forge authentication tokens for any user in your system. This guide walks through setting up, configuring, and rotating your Supabase JWT secret properly.
Understanding Supabase's JWT Architecture
Before diving into configuration, it helps to understand how Supabase uses JWTs.
When a user logs in through Supabase Auth, the system issues a JWT containing the user's identity, role, and expiration time. This token is sent with every request to your Supabase backend, where it's verified using your project's JWT secret. The token is also used by Supabase's Row Level Security (RLS) policies to determine what data the user can access.
The JWT secret is used in two places: Supabase Auth signs tokens with it, and the PostgREST API (which serves your database queries) verifies tokens with it. Both services must use the same secret, which Supabase manages for you through its configuration system.
For HS256 (the default algorithm), the same secret is used for both signing and verification. This means the secret must be kept confidential. Anyone with the secret can forge tokens for any user.
The Default Secret Problem
When you create a local Supabase project using the Supabase CLI, it comes with a default JWT secret. This default is a well-known string that anyone can find in the Supabase documentation and source code. It exists to make local development easy, but it's a critical security risk if used in production.
If you deploy your application to production with the default secret, anyone who knows the default can forge JWTs for your system. They can authenticate as any user, bypass all Row Level Security policies, and access all your data. This is not a theoretical risk. There are automated scanners that look for systems using default Supabase secrets.
For hosted Supabase projects (created through the Supabase dashboard), a random JWT secret is generated during project provisioning. This is more secure, but you should still verify that the secret is strong and rotate it periodically.
Setting Up Your JWT Secret for Local Development
For local development with the Supabase CLI, you need to replace the default secret with a strong, randomly generated one. Here's how:
**Step 1: Generate a strong secret.** Use a cryptographically secure random number generator to create a secret of at least 32 bytes (256 bits). You can use our JWT Secret Generator to generate one in hex or base64url format.
**Step 2: Update your configuration.** In your Supabase project, the JWT secret is stored in the configuration. For local development, update the jwt_secret field in your supabase/config.toml file or your .env file, depending on your setup.
**Step 3: Restart your Supabase services.** After updating the secret, restart your local Supabase services so they pick up the new value. If you're using the Supabase CLI, this means running supabase stop and supabase start.
**Step 4: Update your client configuration.** Your frontend application needs the JWT secret to verify tokens if you're doing client-side verification. However, in most Supabase setups, token verification happens server-side, and your client only needs the Supabase URL and anon key. Check your architecture to determine what needs updating.
Setting Up Your JWT Secret for Hosted Supabase
For hosted Supabase projects, the JWT secret is managed through the Supabase dashboard.
When you create a project, Supabase generates a random JWT secret automatically. You can view it in the project settings under the API section. Verify that it's a strong, random value and not a placeholder or default.
If you need to change it, the Supabase dashboard provides a way to rotate the JWT secret. This will invalidate all existing tokens, so plan accordingly. Before rotating, make sure you understand the implications and have a plan for handling the transition.
Rotating Your Supabase JWT Secret
Secret rotation is just as important for Supabase as for any other JWT-based system. Regular rotation limits the impact of a potential secret compromise. Here's how to rotate your Supabase JWT secret:
**Step 1: Generate a new secret.** Use the JWT Secret Generator to create a new cryptographically secure secret. Make it at least 32 bytes (256 bits) long.
**Step 2: Update the secret in Supabase.** For hosted Supabase, use the dashboard to update the JWT secret. For local development, update your configuration file. Make sure the new secret is correctly saved and applied.
**Step 3: Restart services.** Restart your Supabase services or wait for the hosted project to apply the change. All services that use the JWT secret (Auth, PostgREST, Realtime) need to pick up the new value.
**Step 4: Handle user re-authentication.** Rotating the JWT secret invalidates all existing tokens. All users will need to log in again. This is unavoidable with Supabase's current architecture, which doesn't support dual-secret grace periods natively. Plan rotation for a low-traffic period and communicate the change to users if necessary.
**Step 5: Update downstream services.** If any other services verify your Supabase JWTs, update them with the new secret. This includes custom API servers, microservices, or third-party integrations that validate Supabase tokens.
Supabase-Specific Considerations
Supabase's JWT architecture has some specific characteristics that differ from a custom JWT implementation:
**Row Level Security depends on JWTs.** Supabase's RLS policies use claims from the JWT to determine data access. If your JWT secret is compromised, an attacker can craft tokens with custom claims that bypass RLS policies. This makes secret security especially critical in Supabase architectures.
**The anon key and service role key.** Supabase provides two API keys: the anon key (for client-side use) and the service role key (for server-side, bypassing RLS). The service role key is itself a JWT signed with your JWT secret. If your JWT secret is compromised, an attacker can forge a service role key and bypass all RLS policies. Protect your JWT secret as rigorously as you protect your service role key.
**Realtime connections use JWTs.** Supabase's Realtime feature authenticates WebSocket connections using JWTs. Rotating the secret will disconnect all Realtime clients, and they'll need to re-authenticate with new tokens.
**Edge Functions verify JWTs.** If you're using Supabase Edge Functions, they may verify JWTs passed from the client. Make sure your Edge Functions use the current JWT secret for verification. The secret is typically available as an environment variable in the function context.
Best Practices for Supabase JWT Security
Beyond the basic setup and rotation, here are some best practices specific to Supabase:
**Never expose the JWT secret to the client.** The JWT secret is a server-side secret. It should never appear in client-side code, environment variables exposed to the browser, or any publicly accessible location. Only your Supabase backend and trusted server-side services should have access to it.
**Use the anon key for client-side operations.** The anon key is designed to be public and is safe to include in client-side code. It works with RLS policies to enforce data access rules. Don't use the service role key on the client side, as it bypasses RLS.
**Set reasonable token lifetimes.** Supabase's default token lifetime is typically 1 hour for access tokens, with refresh tokens lasting longer. You can configure these in your Supabase Auth settings. Shorter access token lifetimes are more secure but require more frequent refreshes.
**Monitor for suspicious token usage.** If you suspect your JWT secret has been compromised, look for unusual patterns in your Supabase logs: tokens with unexpected claims, access from unusual IP addresses, or queries that bypass expected RLS policies. Rotate the secret immediately if you see suspicious activity.
The Bottom Line
Your Supabase JWT secret is the key to your entire authentication and authorization system. If it's compromised, an attacker can impersonate any user, bypass all Row Level Security, and access all your data. Treat it with the seriousness that implies.
If you're using the default local development secret in production, fix that immediately. Generate a strong, random secret with our JWT Secret Generator and update your Supabase configuration. If you're using hosted Supabase, verify your secret is strong and plan regular rotation.
For the broader principles of JWT secret management that apply to Supabase and any other JWT-based system, review our JWT secret key best practices guide. The same fundamentals apply: strong random secrets, secure storage, regular rotation, and never exposing secrets to the client.
Supabase makes authentication easy, but easy doesn't mean automatic. Take responsibility for your JWT secret, and your users' data stays protected.