mirror of
https://github.com/supabase/supabase.git
synced 2026-07-03 03:24:24 +08:00
Contributes to DOCS-1052 ## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Resolves MDX linting errors related to "simple" where it applies. There was a couple cases that did not apply. For example, a product with "Simple" in the name. These changes are made in context, either by removing or using a more descriptive synonym like "minimal" or "basic". ## Tophatting 1. Read each of the diffs. 2. See that the text still makes sense in context. For extra due diligence, you can run `pnpm lint:mdx` locally and see the 'simple' errors that remain and whether they are worth addressing. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Summary by CodeRabbit * **Documentation** * Updated many guide, tutorial, and troubleshooting pages with clearer “basic”/“minimal” wording across setup steps, local testing instructions, security cautions, and RLS guidance. * Refined headings, example descriptions, and inline comments for consistency (including deployment, MCP, metrics API, and search/function phrasing). * Improved readability with small snippet formatting tweaks (whitespace plus import/comment ordering) and added a self-hosting debugging note for Envoy admin endpoints via a short-lived `curl` container. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Chris Chinchilla <chris.ward@supabase.io> Co-authored-by: Nik Richers <nrichers@gmail.com>
277 lines
12 KiB
Plaintext
277 lines
12 KiB
Plaintext
---
|
|
id: 'partner-integration-guide'
|
|
title: 'Supabase Partner Integration Guide'
|
|
subtitle: 'Integrate Supabase with your platform or product.'
|
|
description: 'This guide explains how a Supabase partner can integrate with the Supabase platform via OAuth.'
|
|
---
|
|
|
|
This guide assumes you have already followed [the Build a Supabase Integration guide](/docs/guides/integrations/build-a-supabase-oauth-integration) and have a working OAuth client.
|
|
|
|
When a Supabase user clicks the **Install Integration** button in the Dashboard, they are redirected to your system to begin the OAuth flow. You can implement this redirect in one of two ways:
|
|
|
|
- **[Redirect](#method-1-redirect)**: Easier to build, but your system cannot verify that the incoming user was sent by Supabase.
|
|
- **[Signed redirect](#method-2-signed-redirect)**: More work to build, but cryptographically verifies that the redirect originated from Supabase. **Recommended for production integrations.**
|
|
|
|
Pick the method that fits your security requirements, then follow the matching section below.
|
|
|
|
## Method 1: Redirect
|
|
|
|
In this method, you implement a single `GET` endpoint. Supabase redirects the user to this endpoint when they click **Install Integration**, and your endpoint kicks off the OAuth flow.
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
autonumber
|
|
participant User
|
|
participant Browser
|
|
participant Partner as Partner (OAuth Client)
|
|
participant Supabase as Supabase (OAuth Authorization Server/Protected Resource)
|
|
|
|
Note over Browser: Supabase Dashboard Open
|
|
|
|
User->>Browser: Clicks "Install Integration"
|
|
|
|
Browser->>Partner: "Connect to Partner" Click Handler Page
|
|
Partner->>Browser: Redirect to Supabase Authorization Page
|
|
|
|
Browser->>Supabase: Request Authorization
|
|
Supabase->>Browser: Redirect to Consent Screen
|
|
|
|
Browser->>User: Display Consent Screen
|
|
User->>Browser: Gives Consent
|
|
|
|
Browser->>Supabase: Submit User Consent
|
|
Supabase->>Browser: Redirect to Partner With Authorization Code
|
|
|
|
Browser->>Partner: Submit Authorization Code
|
|
|
|
Partner->>Supabase: Exchange Authorization Code for Token
|
|
Supabase->>Partner: Return Token
|
|
|
|
Partner->>Supabase: Request Management API Resources
|
|
Supabase->>Partner: Return Resources
|
|
|
|
Partner->>Browser: Ok 200, OAuth Flow Complete
|
|
|
|
Browser->>User: Display "Integration Installed" Message
|
|
```
|
|
|
|
### Step 1: Implement the redirect endpoint
|
|
|
|
Expose a `GET` endpoint at any URL you control:
|
|
|
|
```
|
|
GET https://<your-host>/<optional-path>?project_id=<supabase-project_ref>&organization_slug=<supabase-org-slug>
|
|
```
|
|
|
|
Supabase will append the following query parameters to the URL when redirecting:
|
|
|
|
| Param | Description |
|
|
| ------------------- | ---------------------------------------------------------------------------------------------- |
|
|
| `project_id` | Supabase project ref of the project where the user clicked the **Install Integration** button. |
|
|
| `organization_slug` | Supabase organization slug where the user clicked the **Install Integration** button. |
|
|
|
|
Save these parameters in your system. You can use them to fetch project or organization details, or to pre-select a project or organization in your UI once the OAuth flow is complete.
|
|
|
|
Your endpoint may ask the user to sign up, sign in, or perform other setup tasks on your website. Once those are complete, immediately [redirect to the Supabase authorization URL](/docs/guides/integrations/build-a-supabase-oauth-integration#redirecting-to-the-authorize-url) without further user interaction. This starts the OAuth flow.
|
|
|
|
### Step 2: Share your endpoint with Supabase
|
|
|
|
Send Supabase the URL of your endpoint so we can configure the **Install Integration** button to redirect there.
|
|
|
|
## Method 2: Signed redirect
|
|
|
|
In this method, Supabase signs a JWT before redirecting the user. You verify the signature, generate a one-time redirect record, and return its URL to Supabase. Supabase then redirects the user to that URL. This guarantees that any redirect your system handles originated from Supabase.
|
|
|
|
You will implement two endpoints:
|
|
|
|
1. A `POST` endpoint that validates the signed JWT and returns a unique redirect URL.
|
|
2. A `GET` endpoint that handles the user once they are redirected to that URL.
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
autonumber
|
|
participant User
|
|
participant Browser
|
|
participant Partner as Partner (OAuth Client)
|
|
participant Supabase as Supabase (OAuth Authorization Server/Protected Resource)
|
|
|
|
Note over Browser: Supabase Dashboard Open
|
|
|
|
User->>Browser: Clicks "Install Integration"
|
|
|
|
Browser->>Supabase: Request Redirect URL Generation
|
|
Supabase->>Partner: Send Signed JWT
|
|
Partner->>Partner: Validate JWT
|
|
Partner->>Partner: Generate Unique Redirect URL
|
|
Partner->>Supabase: Return Redirect URL
|
|
Supabase->>Browser: Redirect to the Redirect URL
|
|
|
|
Browser->>Partner: Visit Redirect URL
|
|
Partner->>Partner: Validate Redirect Record
|
|
Partner->>Browser: Optional User Actions
|
|
Browser->>User: User Performs Optional Actions
|
|
User->>Browser: User Optional Actions Complete
|
|
Browser->>Partner: User Optional Actions Complete
|
|
Partner->>Browser: Redirect to Supabase Authorization Page
|
|
|
|
Browser->>Supabase: Request Authorization
|
|
Supabase->>Browser: Redirect to Consent Screen
|
|
|
|
Browser->>User: Display Consent Screen
|
|
User->>Browser: Gives Consent
|
|
|
|
Browser->>Supabase: Submit User Consent
|
|
Supabase->>Browser: Redirect to Partner With Authorization Code
|
|
|
|
Browser->>Partner: Submit Authorization Code
|
|
|
|
Partner->>Supabase: Exchange Authorization Code for Token
|
|
Supabase->>Partner: Return Token
|
|
|
|
Partner->>Supabase: Request Management API Resources
|
|
Supabase->>Partner: Return Resources
|
|
|
|
Partner->>Browser: Ok 200, OAuth Flow Complete
|
|
|
|
Browser->>User: Display "Integration Installed" Message
|
|
```
|
|
|
|
### Step 1: Exchange public keys with Supabase
|
|
|
|
Supabase generates two key-pairs, one for staging, one for production, and shares the public keys with you. Save both public keys and their key IDs in your system. The keys are PEM-encoded EC P-256.
|
|
|
|
Example:
|
|
|
|
```
|
|
===============Staging==================
|
|
|
|
Key ID: pik_3038669348a3ea75dbaf0655
|
|
Public Key:
|
|
-----BEGIN PUBLIC KEY-----
|
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEnj3NmwrLPPH/3isvpS601ndQP9Mk
|
|
zqppdLDV9YfmoF4wavTyb9UTVE5pJ0fukpo5aOoNb4fBZgESsedIUoEn8Q==
|
|
-----END PUBLIC KEY-----
|
|
|
|
==============Production================
|
|
|
|
Key ID: pik_89e80ddbca9df41b97e28986
|
|
Public Key:
|
|
-----BEGIN PUBLIC KEY-----
|
|
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEWCGhwtFWn4jpWZNeyZpTlaAdq/tD
|
|
/yBaN0gFPpS8LTFiCPFgnWKbVe3RfExXh7bEhcrEUdWycmYvwrNklWWHRA==
|
|
-----END PUBLIC KEY-----
|
|
```
|
|
|
|
Look up the correct public key by the `kid` field in the JWT header.
|
|
|
|
Storing keys by ID enables zero-downtime key rotation. When Supabase rotates keys, we share new key-pairs and start signing JWTs with the new key ID. Your system picks the correct key based on `kid` without any code changes.
|
|
|
|
<Admonition type="note">
|
|
|
|
In future, we plan to publish keys at a `.../.well-known/jwks.json` URL and fully automate key rotation. For now this is done manually.
|
|
|
|
</Admonition>
|
|
|
|
### Step 2: Implement the redirect record endpoint
|
|
|
|
This endpoint receives the signed JWT from Supabase and returns a one-time redirect URL.
|
|
|
|
Host the endpoint at any URL and path you control. Do not require authentication on this endpoint, but apply rate limiting to prevent abuse.
|
|
|
|
```
|
|
POST https://<your-api-host>/<your-api-path>
|
|
Content-Type: application/json
|
|
```
|
|
|
|
#### Request body
|
|
|
|
```json
|
|
{
|
|
"token": "<signed-jwt>"
|
|
}
|
|
```
|
|
|
|
#### JWT fields
|
|
|
|
The token is a JWT signed with the ES256 private key.
|
|
|
|
**Protected header (JOSE header)**
|
|
|
|
| Field | Required | Description |
|
|
| ----- | -------- | ---------------------------------------------------------------------------------------------------------- |
|
|
| `alg` | Yes | Always `ES256` — the only signing algorithm currently supported. |
|
|
| `kid` | Yes | The key ID identifying the key pair. Use this to pick the correct public key when verifying the signature. |
|
|
|
|
**Payload (claims)**
|
|
|
|
| Claim | Required | Description |
|
|
| ------------------- | -------- | ----------------------------------------------------------------------------------------------------------------- |
|
|
| `iss` | Yes | Always `supabase`. |
|
|
| `aud` | Yes | A unique string identifying the audience of this JWT. Usually a URL. |
|
|
| `iat` | Yes | Issued-at timestamp (seconds since epoch). |
|
|
| `exp` | Yes | Expiry timestamp — at most 5 minutes after `iat`. |
|
|
| `organization_slug` | No | The Supabase organization the user is connecting from. Use to pre-select the org during the OAuth consent screen. |
|
|
| `project_id` | No | The Supabase project ref the user wants to connect. Use to pre-select a Supabase project in your UI. |
|
|
|
|
**Signature**
|
|
|
|
The header and claims are signed with the EC P-256 private key.
|
|
|
|
#### Validation
|
|
|
|
When you receive a request:
|
|
|
|
1. Read the `kid` field from the JWT header and look up the matching public key.
|
|
2. Verify the JWT signature with that public key.
|
|
3. Verify that `alg` is `ES256`.
|
|
4. Verify that `iss` is `supabase`.
|
|
5. Verify that `aud` matches the value you agreed with Supabase.
|
|
6. Verify that the current time is between `iat` and `exp`.
|
|
|
|
If any check fails, return `401 Unauthorized`.
|
|
|
|
If validation succeeds, generate a UUID to identify this redirect record (also called an integration record), save it in your system with an expiry (typically 1 hour), and return it in the response. The expiry prevents records from accumulating and limits the window in which a leaked record can be used.
|
|
|
|
#### Response body
|
|
|
|
```json
|
|
{
|
|
"integrationId": "<a unique uuid>",
|
|
"redirectUrl": "https://<your-api-host>/<your-api-path>/<integration-id>",
|
|
"expiresAt": "<timestamp>"
|
|
}
|
|
```
|
|
|
|
| Field | Description |
|
|
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
| `integrationId` | A UUID uniquely identifying the redirect record. |
|
|
| `redirectUrl` | The URL the user will be redirected to. Must contain the `integrationId` somewhere in its path so you can retrieve the record on redirect. |
|
|
| `expiresAt` | The time when the redirect record expires (typically 1 hour from creation). The user must begin the flow before this time. |
|
|
|
|
### Step 3: Implement the redirect handler endpoint
|
|
|
|
This is the `GET` endpoint at the `redirectUrl` you returned in the previous step. The redirect record's UUID must be in its path.
|
|
|
|
When a user arrives at this endpoint:
|
|
|
|
1. Extract the redirect record UUID from the URL path.
|
|
2. Look it up in your system. If it doesn't exist or has expired, return `401 Unauthorized`.
|
|
3. Optionally, walk the user through any setup required on your side — for example, signing up, signing in, or configuring your system so the integration will work.
|
|
4. Redirect the user to the [Supabase authorization URL](/docs/guides/integrations/build-a-supabase-oauth-integration#redirecting-to-the-authorize-url) to start the OAuth flow.
|
|
|
|
<Admonition type="tip">
|
|
|
|
If you need the user to perform setup steps on your site, design the experience as a wizard that ends by redirecting to the Supabase authorization URL. This minimizes the chance of users getting distracted, navigating elsewhere on your site, and abandoning the OAuth flow.
|
|
|
|
</Admonition>
|
|
|
|
### Step 4: Share your details with Supabase
|
|
|
|
Send Supabase the following so we can configure the **Install Integration** button:
|
|
|
|
- The URL of your redirect record endpoint ([Step 2](#step-2-implement-the-redirect-record-endpoint)).
|
|
- The URL pattern of your redirect handler endpoint ([Step 3](#step-3-implement-the-redirect-handler-endpoint)).
|
|
- The `aud` claim value you want Supabase to send in the signed JWT.
|
|
|
|
Ask Supabase for the public keys and key IDs for the staging and production environments.
|