mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 01:15:03 +03:00
Closes [DOCS-1289](https://linear.app/supabase/issue/DOCS-1289/get-the-linter-to-fix-what-it-flags-or-retirereplace-the-linter) Stacked on #50600, which points contributors at the authoring skills. Merge that one first. ## Problem Contributors experienced friction with the linter. They felt nickle and dimed for tiny nits and felt detracted from the work itself. PRs would become noisy with tiny one-word suggestions. Additionally, our homegrown linter is not very intelligent, causing frequent overrides. ## Solution This removes the linter entirely in favor of directing contributors to use SKILLS instead. The removal entails... - **CI.** Delete the three `docs_lint` workflows: the PR check, the external-PR comment companion, and the nightly `--fix` bot. Drop the stale `zizmor.yml` ignore entry for the deleted workflow. - **Tooling.** Delete `supa-mdx-lint.config.toml` and the 14 rule files. Drop the `lint:mdx` script and the `@supabase/supa-mdx-lint` dependency from docs, learn, and ui-library, and regenerate the lockfile. - **Content.** Remove the 181 directives. A separate commit carries Prettier's reformatting of the tables and blank lines those comments had suppressed, so the deletion commit stays readable. No prose changes. - **Style guide.** The word list states each rule directly instead of describing what the linter flagged. Every term survives, including the phrase groups that mirrored `Rule004ExcludeWords`. - **Skills.** `write-the-docs`, `edit-the-docs`, and `review-the-docs` drop `pnpm lint:mdx` from their self-review commands and check the word list directly. `ask-the-docs`'s CI reference drops both workflows. ## Manual testing 1. Run `git grep -i supa-mdx-lint -- . ':!pnpm-lock.yaml'`. No matches. 2. Run `pnpm install --frozen-lockfile --lockfile-only`. It passes, so the lockfile matches the three trimmed manifests. 3. Run `git diff master...HEAD --name-only --diff-filter=ACMR | grep -E '\.(md|mdx)$' | xargs npx prettier --config prettier.config.mjs --check`. All changed markdown passes. 4. Open the [reformatted filter table](https://docs-git-docs-retire-mdx-linter-supabase.vercel.app/docs/guides/observability/logs#filter-events) on the preview and compare it with [production](https://supabase.com/docs/guides/observability/logs#filter-events). The table renders the same. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Documentation guidance now uses manual prose and terminology review with the shared word list. * Clarified storage configuration and common Realtime channel mistakes. * Improved table formatting, text wrapping, and selected reference links. * Updated documentation authoring and review guidance. * **Chores** * Retired automated MDX linting from workflows and local validation commands. * Removed lint-suppression markers throughout documentation without changing instructions. * Added targeted documentation review guidance for pull requests. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
169 lines
9.5 KiB
Plaintext
169 lines
9.5 KiB
Plaintext
---
|
|
id: 'build-a-supabase-oauth-integration'
|
|
title: 'Build a Supabase Integration'
|
|
subtitle: "This guide steps through building a Supabase Integration using OAuth2 and the management API, allowing you to manage users' organizations and projects on their behalf."
|
|
description: 'Build a Supabase Integration using OAuth2 and the Management API.'
|
|
---
|
|
|
|
Using OAuth2.0 you can retrieve an access and refresh token that grant your application full access to the [Management API](/docs/reference/api/introduction) on behalf of the user.
|
|
|
|
## Create an OAuth app
|
|
|
|
1. In your organization's settings, navigate to the [**OAuth Apps**](/dashboard/org/_/apps) tab.
|
|
2. In the upper-right section of the page, click **Add application**.
|
|
3. Fill in the required details and click **Confirm**.
|
|
|
|
## Show a "Connect Supabase" button
|
|
|
|
In your user interface, add a "Connect Supabase" button to kick off the OAuth flow. Follow the design guidelines outlined in our [brand assets](/brand-assets).
|
|
|
|
## Implementing the OAuth 2.0 flow
|
|
|
|
Once you've published your OAuth App on Supabase, you can use the OAuth 2.0 protocol get authorization from Supabase users to manage their organizations and projects.
|
|
|
|
You can use your preferred OAuth2 client or follow the steps below. You can see an example implementation in TypeScript using Supabase Edge Functions [on our GitHub](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/connect-supabase).
|
|
|
|
### Redirecting to the authorize URL
|
|
|
|
Within your app's UI, redirect the user to [`https://api.supabase.com/v1/oauth/authorize`](https://api.supabase.com/api/v1#tag/oauth/GET/v1/oauth/authorize). Make sure to include all required query parameters such as:
|
|
|
|
- `client_id`: Your client id from the app creation above.
|
|
- `redirect_uri`: The URL where Supabase will redirect the user to after providing consent.
|
|
- `response_type`: Set this to `code`.
|
|
- `state`: Information about the state of your app. Note that `redirect_uri` and `state` together cannot exceed 4kB in size.
|
|
- `organization_slug`: The slug of the organization you want to connect to. This is optional, but if provided, it will pre-select the organization for the user.
|
|
- [Recommended] PKCE: We strongly recommend using the PKCE flow for increased security. Generate a random value before taking the user to the authorize endpoint. This value is called code verifier. Hash it with SHA256 and include it as the `code_challenge` parameter, while setting `code_challenge_method` to `S256`. In the next step, you would need to provide the code verifier to get the first access and refresh token.
|
|
- [Deprecated] `scope`: Scopes are configured when you create your OAuth app. Read the [docs](/docs/guides/integrations/build-a-supabase-oauth-integration/oauth-scopes) for more details.
|
|
|
|
```ts
|
|
router.get('/connect-supabase/login', async (ctx) => {
|
|
// Construct the URL for the authorization redirect and get a PKCE codeVerifier.
|
|
const { uri, codeVerifier } = await oauth2Client.code.getAuthorizationUri()
|
|
console.log(uri.toString())
|
|
// console.log: https://api.supabase.com/v1/oauth/authorize?response_type=code&client_id=7673bde9-be72-4d75-bd5e-b0dba2c49b38&redirect_uri=http%3A%2F%2Flocalhost%3A54321%2Ffunctions%2Fv1%2Fconnect-supabase%2Foauth2%2Fcallback&scope=all&code_challenge=jk06R69S1bH9dD4td8mS5kAEFmEbMP5P0YrmGNAUVE0&code_challenge_method=S256
|
|
|
|
// Store the codeVerifier in the user session (cookie).
|
|
ctx.state.session.flash('codeVerifier', codeVerifier)
|
|
|
|
// Redirect the user to the authorization endpoint.
|
|
ctx.response.redirect(uri)
|
|
})
|
|
```
|
|
|
|
Find the full example on [GitHub](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/connect-supabase).
|
|
|
|
### Handling the callback
|
|
|
|
Once the user consents to providing API access to your OAuth App, Supabase will redirect the user to the `redirect_uri` provided in the previous step. The URL will contain these query parameters:
|
|
|
|
- `code`: An authorization code you should exchange with Supabase to get the access and refresh token.
|
|
- `state`: The value you provided in the previous step, to help you associate the request with the user. The `state` property returned here should be compared to the `state` you sent previously.
|
|
|
|
Exchange the authorization code for an access and refresh token by calling [`POST https://api.supabase.com/v1/oauth/token`](https://api.supabase.com/api/v1#tag/oauth/POST/v1/oauth/token) with the following query parameters as content-type `application/x-www-form-urlencoded`:
|
|
|
|
- `grant_type`: The value `authorization_code`.
|
|
- `code`: The `code` returned in the previous step.
|
|
- `redirect_uri`: This must be exactly the same URL used in the first step.
|
|
- (Recommended) `code_verifier`: If you used the PKCE flow in the first step, include the code verifier as `code_verifier`.
|
|
|
|
<Admonition type="note">
|
|
|
|
If your application need to support dynamically generated Redirect URLs, check out [Handling Dynamic Redirect URLs](#handling-dynamic-redirect-urls) section below.
|
|
|
|
</Admonition>
|
|
|
|
As per OAuth2 spec, provide the client id and client secret as basic auth header:
|
|
|
|
- `client_id`: The unique client ID identifying your OAuth App.
|
|
- `client_secret`: The secret that authenticates your OAuth App to Supabase.
|
|
|
|
```ts
|
|
router.get('/connect-supabase/oauth2/callback', async (ctx) => {
|
|
// Make sure the codeVerifier is present for the user's session.
|
|
const codeVerifier = ctx.state.session.get('codeVerifier') as string
|
|
if (!codeVerifier) throw new Error('No codeVerifier!')
|
|
|
|
// Exchange the authorization code for an access token.
|
|
const tokens = await fetch(config.tokenUri, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/x-www-form-urlencoded',
|
|
Accept: 'application/json',
|
|
Authorization: `Basic ${btoa(`${config.clientId}:${config.clientSecret}`)}`,
|
|
},
|
|
body: new URLSearchParams({
|
|
grant_type: 'authorization_code',
|
|
code: ctx.request.url.searchParams.get('code') || '',
|
|
redirect_uri: config.redirectUri,
|
|
code_verifier: codeVerifier,
|
|
}),
|
|
}).then((res) => res.json())
|
|
console.log('tokens', tokens)
|
|
|
|
// Store the tokens in your DB for future use.
|
|
|
|
ctx.response.body = 'Success'
|
|
})
|
|
```
|
|
|
|
Find the full example on [GitHub](https://github.com/supabase/supabase/tree/master/examples/edge-functions/supabase/functions/connect-supabase).
|
|
|
|
## Refreshing an access token
|
|
|
|
You can use the [`POST /v1/oauth/token`](https://api.supabase.com/api/v1#tag/oauth/POST/v1/oauth/token) endpoint to refresh an access token using the refresh token returned at the end of the previous section.
|
|
|
|
If the user has revoked access to your application, you will not be able to refresh a token. Furthermore, access tokens will stop working. Make sure you handle HTTP Unauthorized errors when calling any Supabase API.
|
|
|
|
## Calling the Management API
|
|
|
|
Refer to [the Management API reference](/docs/reference/api/introduction#authentication) to learn more about authentication with the Management API.
|
|
|
|
### Use the JavaScript (TypeScript) SDK
|
|
|
|
For convenience, when working with JavaScript/TypeScript, you can use the [supabase-management-js](https://github.com/supabase-community/supabase-management-js#supabase-management-js) library.
|
|
|
|
```ts
|
|
import { SupabaseManagementAPI } from 'supabase-management-js'
|
|
|
|
const client = new SupabaseManagementAPI({ accessToken: '<access token>' })
|
|
```
|
|
|
|
## Integration recommendations
|
|
|
|
There are a couple common patterns you can consider adding to your integration that can facilitate a great user experience.
|
|
|
|
### Store API keys in env variables
|
|
|
|
Some integrations, e.g. like [Cloudflare Workers](/partners/integrations/cloudflare-workers) provide convenient access to the API URL and API keys to allow user to speed up development.
|
|
|
|
Using the management API, you can retrieve a project's API credentials using the [`/projects/{ref}/api-keys` endpoint](https://api.supabase.com/api/v1#/projects/getProjectApiKeys).
|
|
|
|
### Pre-fill database connection details
|
|
|
|
If your integration directly connects to the project's database, you can pref-fill the Postgres connection details for the user, it follows this schema:
|
|
|
|
```
|
|
postgresql://postgres:[DB-PASSWORD]@db.[REF].supabase.co:5432/postgres
|
|
```
|
|
|
|
Note that you cannot retrieve the database password via the management API, so for the user's existing projects you will need to collect their database password in your UI.
|
|
|
|
### Create new projects
|
|
|
|
Use the [`/v1/projects` endpoint](https://api.supabase.com/api/v1#/projects/createProject) to create a new project.
|
|
|
|
When creating a new project, you can either ask the user to provide a database password, or you can generate a secure password for them. In any case, make sure to securely store the database password on your end which will allow you to construct the Postgres URI.
|
|
|
|
### Configure custom Auth SMTP
|
|
|
|
You can configure the user's [custom SMTP settings](/docs/guides/auth/auth-smtp) using the [`/config/auth` endpoint](https://api.supabase.com/api/v1#/projects%20config/updateV1AuthConfig).
|
|
|
|
### Handling dynamic redirect URLs
|
|
|
|
To handle multiple, dynamically generated redirect URLs within the same OAuth app, you can leverage the `state` query parameter. When starting the OAuth process, include the desired, encoded redirect URL in the `state` parameter.
|
|
Once authorization is complete, we will sends the `state` value back to your app. You can then verify its integrity and extract the correct redirect URL, decoding it and redirecting the user to the correct URL.
|
|
|
|
## Current limitations
|
|
|
|
Only some features are available until we roll out fine-grained access control. If you need full database access, you will need to prompt the user for their database password.
|