Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
title = "Email/Password Login Disabled for Supabase Accounts Created via Vercel Marketplace"
topics = [ "auth" ]
keywords = [ "Vercel"]
---

If your Supabase account was initiated via the Vercel Marketplace, you will not be able to log in directly using email/password or reset your password. This is because such accounts are tightly coupled to Vercel's authentication system, restricting login to Vercel's integrated methods.

To access your Supabase account independently of the Vercel Marketplace, you can use GitHub OAuth as an alternative:

1. Ensure the GitHub account you use has the same email address associated with your Vercel Marketplace Supabase account.
2. Navigate to the [Supabase dashboard sign-in page](/dashboard/sign-in).
3. Select "Continue with GitHub" and complete the authentication process.

This method provides direct access to your Supabase dashboard, organizations, and projects without requiring login through the Vercel Marketplace.
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
title = "'Error: 'Target organization is not managed by Vercel Marketplace' during project transfer'"
topics = [ "platform" ]
keywords = []
---

If you encounter the error "Target organization is not managed by Vercel Marketplace (currently unsupported)" when attempting a project transfer, it indicates an attempt to move a project from a Supabase-managed organization to a Vercel Marketplace-managed organization. This transfer direction is currently not supported due to existing Vercel Marketplace API limitations.

**Supported Transfer Direction:**
Project transfers from a Vercel-managed organization to a Supabase-managed organization are supported. To perform this transfer:

1. Create a new Supabase-managed organization via your [dashboard](/dashboard).
2. From your project settings, initiate a transfer to the newly created Supabase-managed organization.
3. If any errors occur, refresh the page and retry the transfer.
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
title = "'OTP Verification Failures: 'token has expired' or 'otp_expired' errors'"
topics = [ "auth", "cli" ]
keywords = []
[[errors]]
http_status_code = 403
message = "Forbidden"

[[errors]]
code = "otp_expired"
message = "OTP expired"

---

When users attempt to exchange One-Time Passwords (OTPs), they may encounter various errors indicating that the token is no longer valid. These include messages like "token has expired or is invalid," "Email link is invalid or has expired," or they might receive '403 Forbidden' HTTP responses on the verification endpoint. Authentication logs often show specific `otp_expired` error codes.

## What is OTP (one-time password) verification?

An OTP, or One-Time Password, is a security code generated for a single use or a limited period. In authentication flows, especially for password resets, a user requests an OTP, which is then sent to their email or phone. The user must then provide this OTP back to the system within a set timeframe to verify their identity and proceed with actions like resetting a password. The system verifies this token using a function like `supabase.auth.verifyOtp({ email, token, type: 'recovery' })`.

## Understanding the errors

- **403 Forbidden HTTP Status Code:** This is a standard HTTP status code indicating that the web server understood the request but refuses to authorize it. In the context of OTP verification, a 403 Forbidden response on the `/verify` endpoint typically means the server has rejected the submitted OTP token, often because it's invalid, expired, or used.
- **`otp_expired` Error:** This is a specific error message reported by the authentication service, explicitly stating that the provided OTP token has passed its validity period and can no longer be used. Other similar messages like "token has expired or is invalid" or "Email link is invalid or has expired" also fall under this category of token validity issues.

## The root cause: Email prefetching

The most common reason for OTP tokens appearing expired or invalid before a user can even use them is **email prefetching**.

- **What is email prefetching?** Email prefetching is a mechanism used by email clients or security tools to automatically scan and sometimes access URLs embedded in emails. This is often done to check for malicious links, render content faster, or provide advanced security features.
- **How security tools interfere:** Services such as security tools commonly used by organizations (e.g., for safe link analysis), or similar security scanners, automatically 'click' or access links within emails to analyze their content or check for threats. If your password reset email includes a confirmation URL (sometimes referred to as a "magic link" or a link that implicitly validates the token upon access), these automated prefetching services can consume the OTP token by accessing the link _before_ the legitimate user does. This makes the token appear instantly expired or invalid to the user, as it has already been used or invalidated by the prefetcher.
- **System clock issues:** Less frequently, discrepancies between a user's device system clock and the server's time can lead to tokens appearing invalid due to perceived expiration, though this is less common with modern synchronized systems.

## Troubleshooting and identifying the problem

To determine if email prefetching or another token validity issue is the root cause, you can correlate events across your logs:

1. **Monitor API Logs:** Look for '403 Forbidden' HTTP status codes on the `/verify` endpoint. These responses directly indicate failed verification attempts.
2. **Check Authentication Logs:** Cross-reference the API log entries with your authentication logs for `otp_expired` error codes or similar "token invalid/expired" messages.
3. **Correlate by Time and IP:** Use timestamps and, if available, IP addresses from both API and authentication logs to link specific failed verification attempts to potential prefetching events. If you see rapid 403 errors or `otp_expired` messages shortly after an email is sent, but before a user could reasonably click the link, it strongly suggests prefetching.
4. **Confirm Verification Method:** Ensure your application uses the intended OTP verification method, such as `supabase.auth.verifyOtp` with the correct type (e.g., `recovery` for password resets). While it's understood that the 'recovery' type is correct for password resets, the issue primarily stems from the initial link access rather than the final verification call.

## Resolving the issue

Addressing this problem typically involves adjusting how your application interacts with email and how tokens are handled:

1. **Review Email Templates:** Carefully inspect your password reset email templates. Identify if they contain confirmation URLs (e.g., `{{ .ConfirmationURL }}`) that, when accessed, might implicitly validate or invalidate an OTP token.
2. **Implement Prefetching Bypasses/Mitigation:**
- **Consult Email Service Documentation:** Refer to the documentation for your email service provider or any integrated security tools. Many services offer methods to prevent or mitigate automated prefetching, such as specific HTML attributes (e.g., `rel="noreferrer noopener"`) or email headers that signal security scanners not to follow links.
- **Delay Token Invalidation:** Consider if your system can be configured to invalidate the OTP token only _after_ a user explicitly submits it, rather than upon initial access of a confirmation URL.
- **Re-evaluate Link Structure:** If using confirmation URLs, explore alternative designs where the link only directs the user to a page to _enter_ the OTP, rather than consuming it directly.
3. **Educate Users:** Inform users that they should not forward password reset emails and should click links directly.
4. **Consider OTP Flow without Direct Links:** If prefetching remains a persistent issue, consider an OTP flow that relies solely on users manually copying a code from the email into your application, bypassing any clickable confirmation URLs for the sensitive part of the process.
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
---
title = "Realtime: Handling Silent Disconnections in Background Applications"
topics = [ "cli", "database", "realtime" ]
keywords = []
---

If your Supabase Realtime subscriptions stop receiving events after some time without any explicit error messages, you might be experiencing a silent disconnection. This guide explains why this occurs and provides robust solutions to maintain connection stability.

## Key technical concepts

To understand the problem and its solutions, it's helpful to first define some core technical terms:

- **What is Supabase Realtime?**
Supabase Realtime is a service that allows your application to listen for and receive instant updates (events) from your Postgres database whenever data changes. It uses WebSocket connections to provide this real-time data streaming.

- **What is a WebSocket?**
A WebSocket is a communication protocol that provides a full-duplex, persistent communication channel over a single TCP connection. Unlike traditional HTTP requests, WebSockets allow for continuous, bi-directional communication between a client (like your application) and a server, making them ideal for real-time applications.

- **What is a heartbeat?**
In the context of network connections, a heartbeat is a periodic signal sent between two connected entities (e.g., your client and the Realtime server) to confirm that the connection is still active and both ends are responsive. If a heartbeat is missed for a certain period, it can indicate a connection loss.

- **What is browser throttling?**
Browser throttling is an optimization strategy employed by web browsers to conserve resources (CPU, battery) when a tab or application is running in the background or is inactive. This often involves reducing the frequency of JavaScript timers, potentially slowing down or pausing background operations.

- **What is a Web Worker?**
A Web Worker is a JavaScript script that runs in the background, independently of the main browser thread. This allows complex computations or long-running tasks to be executed without freezing or affecting the responsiveness of the user interface.

## Understanding the problem: Why Realtime stops silently

Supabase Realtime relies on maintaining a persistent WebSocket connection to deliver real-time updates. To ensure this connection is active and healthy, the Realtime client periodically sends "heartbeat" signals to the server.

The core issue arises when your application, particularly if it's a web application, moves into a background state (e.g., the browser tab is no longer active, or the application is minimized). In such scenarios, web browsers often implement **browser throttling**. This means the browser reduces the execution frequency of JavaScript timers in the background.

When JavaScript timers are throttled, the Realtime client might be prevented from sending its heartbeats at the required intervals. If the server doesn't receive heartbeats for too long, it assumes the client has disconnected, and the WebSocket connection can **silently drop**. Your application then stops receiving events without any explicit error message, as the connection loss was not actively detected by the client's main thread. Network instability can also contribute to silent disconnections.

## Solutions for robust Realtime connection management

To ensure your Realtime subscriptions remain stable and resilient against silent disconnections, especially in background states, Supabase provides two recommended strategies that can be used together.

### Step 1: Implement `heartbeatCallback` for explicit reconnection

The `heartbeatCallback` option allows you to actively monitor the status of your Realtime connection and programmatically trigger a reconnection if a disconnection is detected.

- **Purpose:** To gain visibility into the connection's health and provide a mechanism for your application to explicitly reconnect when the connection is lost.
- **How it works:** When initializing your `RealtimeClient`, you can provide a `heartbeatCallback` function. This function will be invoked whenever the Realtime client's internal heartbeat mechanism detects a change in the connection's status. By checking if the `status` passed to the callback is `'disconnected'`, you can then call `client.connect()` to attempt to re-establish the WebSocket connection.

```javascript
const client = createClient(SUPABASE_URL, SUPABASE_KEY, {
realtime: {
heartbeatCallback: (status) => {
if (status === 'disconnected') {
// Explicitly reconnect when heartbeat fails or connection drops
client.connect()
}
},
},
})
```

### Step 2: Enable Web workers for reliable background heartbeats

Enabling the Web Worker option helps prevent browser throttling from affecting your Realtime connection's heartbeat mechanism.

- **Purpose:** To ensure that heartbeat signals are sent consistently even when your application is running in the background, thereby preventing silent disconnections caused by browser throttling.
- **How it works:** By setting `worker: true` in your Realtime client configuration, the heartbeat logic is offloaded to a **Web Worker**. Since Web Workers run in a separate thread, they are generally less susceptible to browser throttling than JavaScript execution on the main thread of an inactive tab. This allows heartbeats to be sent reliably in the background, keeping the WebSocket connection alive.

```javascript
const client = createClient(SUPABASE_URL, SUPABASE_KEY, {
realtime: {
worker: true,
},
})
```

### Recommendation: Combine both solutions for maximum stability

For the most robust Realtime connection management, it is strongly recommended to combine both the `heartbeatCallback` and the `worker: true` options.

- The `worker: true` option acts as a primary preventative measure, largely mitigating the risk of disconnections due to browser throttling in background tabs. It ensures that the heartbeats are sent reliably.
- The `heartbeatCallback` serves as a crucial fallback and monitoring mechanism. It allows your application to detect and react to any disconnections that might still occur due to other factors, such as network instability, ensuring that the client can always attempt to re-establish the connection.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
title = "'Supabase project provisioned via Bolt not visible in dashboard'"
topics = [ "database" ]
keywords = [
"Bolt"
]
---

If your Supabase project, provisioned through Bolt's Claude Agent, isn't appearing in your Supabase dashboard, it indicates an ownership difference.

## Why does this happen?

By default, Bolt agent uses Bolt Cloud Backend. When a Cloud backend is created, the Supabase project linked to the backend is owned by Bolt's organizational account. This means they won't automatically show in your personal Supabase dashboard.

## How to resolve this issue

To gain access and manage this database within your personal Supabase account, you must perform a database claim action. Refer to Bolt's official documentation for the precise procedure: [Claim Your Bolt Database in Supabase](https://support.bolt.new/integrations/supabase#claim-your-bolt-database-in-supabase).
1 change: 1 addition & 0 deletions supa-mdx-lint/Rule003Spelling.toml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ allow_list = [
"[Pp]laintext",
"[Pp]olyfill(s|ed)?",
"[Pp]oolers?",
"[Pp]refetcher",
"[Pp]resign(ed|ing)?",
"[Pp]roxying",
"[Pp]sycopg",
Expand Down
Loading